Commit 8927f427 authored by Łukasz Nowak's avatar Łukasz Nowak

caddy-frontend: Protect against malformed backend from the request

The backend url can come from request in `url` and `https-url` strings.
It is validated using real caddy template configuration and by using
caddy's `-stdin`. It results with calling it on each slave having any of
those parameters.
parent 424926f0
......@@ -2,6 +2,7 @@ Generally things to be done with ``caddy-frontend``:
* tests: add assertion with results of promises in etc/promise for each partition
* generated files: ``| trim`` values (like ``slave_password[slave]`` in ``templates/template-log-access.conf.in``) in generated configuration files to have them renfered correctly
* check the whole frontend slave snippet with ``caddy -validate`` during buildout run, and reject if does not pass validation
* ``apache-ca-certificate`` shall be merged with ``apache-certificate``
* ``apache-ca-certificate`` shall be appended to ``apache-certificate`` if not already there
......
......@@ -14,7 +14,7 @@
# not need these here).
[template]
filename = instance.cfg
md5sum = 906e5bd66b1265b8109a86b6ab46e91f
md5sum = b73505ae80d6325a244f5094f8edc0ae
[template-apache-frontend]
filename = instance-apache-frontend.cfg
......@@ -22,7 +22,7 @@ md5sum = b170d0987563b481eb71cf705c3658ab
[template-apache-replicate]
filename = instance-apache-replicate.cfg.in
md5sum = 7f15b5745eda8e1f02d4bf7d886dcdad
md5sum = 27e98547061bd81e5f84cb7dd21b683b
[template-slave-list]
filename = templates/apache-custom-slave-list.cfg.in
......@@ -44,6 +44,10 @@ md5sum = 6689d96fc18d9aad78d77fe87770d4da
filename = templates/apache-custom-slave-list.cfg.in
md5sum = fb6c93f42f232e381174a5951c3fc222
[caddy-backend-url-validator]
filename = templates/caddy-backend-url-validator.in
md5sum = 0979a03476e86bf038516c9565dadc17
[template-not-found-html]
filename = templates/notfound.html
md5sum = f20d6c3d2d94fb685f8d26dfca1e822b
......
......@@ -46,6 +46,13 @@ url = ${:_profile_base_location_}/instance-apache-frontend.cfg
output = ${buildout:directory}/template-caddy-frontend.cfg
mode = 0644
[caddy-backend-url-validator]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/${:filename}
filename = caddy-backend-url-validator.in
output = ${buildout:directory}/caddy-backend-url-validator
mode = 0750
[template-caddy-replicate]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/instance-apache-replicate.cfg.in
......
......@@ -72,7 +72,22 @@ context =
{% for slave in slave_instance_list %}
{# BBB: apache_custom_https AND apache_custom_http #}
{% if not ((slave.has_key('caddy_custom_http') or slave.has_key('apache_custom_http') or slave.has_key('caddy_custom_https') or slave.has_key('apache_custom_https')) and not slave.get('slave_reference') in authorized_slave_string) %}
{% do authorized_slave_list.append(slave) %}
{% set slave_ok = True %}
{% if slave.get('url') %}
{% if subprocess_module.call([caddy_backend_url_validator, slave['url']]) == 1 %}
{% set slave_ok = False %}
{% endif %}
{% endif %}
{% if slave.get('https-url') %}
{% if subprocess_module.call([caddy_backend_url_validator, slave['https-url']]) == 1 %}
{% set slave_ok = False %}
{% endif %}
{% endif %}
{% if slave_ok %}
{% do authorized_slave_list.append(slave) %}
{% else %}
{% do rejected_slave_list.append(slave.get('slave_reference')) %}
{% endif %}
{% else %}
{% do rejected_slave_list.append(slave.get('slave_reference')) %}
{% endif %}
......
......@@ -43,6 +43,8 @@ template = ${template-caddy-replicate:target}
filename = instance-caddy-replicate.cfg
extensions = jinja2.ext.do
extra-context =
import subprocess_module subprocess
raw caddy_backend_url_validator ${caddy-backend-url-validator:output}
raw template_publish_slave_information ${template-replicate-publish-slave-information:target}
# Must match the key id in [switch-softwaretype] which uses this section.
raw software_type RootSoftwareInstance-default-custom-personal-replicate
......
#!${dash:location}/bin/dash
config="https://example.com {\n proxy / $1 {\n }\n}"
echo -e $config | ${caddy:output} -conf stdin -validate > /dev/null 2>&1
......@@ -2692,3 +2692,91 @@ class TestRe6stVerificationUrlSlave(SlaveHttpFrontendTestCase,
'URL="some-re6st-verification-url"' in
open(re6st_connectivity_promise_list[0]).read()
)
class TestMalformedBackenUrlSlave(SlaveHttpFrontendTestCase,
TestDataMixin):
@classmethod
def getInstanceParameterDict(cls):
return {
'domain': 'example.com',
'nginx-domain': 'nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4,
'apache-certificate': open('wildcard.example.com.crt').read(),
'apache-key': open('wildcard.example.com.key').read(),
'port': HTTPS_PORT,
'plain_http_port': HTTP_PORT,
'nginx_port': NGINX_HTTPS_PORT,
'plain_nginx_port': NGINX_HTTP_PORT,
'monitor-httpd-port': MONITOR_HTTPD_PORT,
'-frontend-config-1-monitor-httpd-port': MONITOR_F1_HTTPD_PORT,
}
@classmethod
def getSlaveParameterDictDict(cls):
return {
'empty': {
},
'url': {
'url': "https://[fd46::c2ae]:!py!u'123123'",
},
'https-url': {
'https-url': "https://[fd46::c2ae]:!py!u'123123'",
}
}
def test_master_partition_state(self):
parameter_dict = self.computer_partition.getConnectionParameterDict()
self.assertKeyWithPop('monitor-setup-url', parameter_dict)
expected_parameter_dict = {
'monitor-base-url': None,
'domain': 'example.com',
'accepted-slave-amount': '1',
'rejected-slave-amount': '2',
'slave-amount': '3',
'rejected-slave-list': '["_url", "_https-url"]'}
self.assertEqual(
expected_parameter_dict,
parameter_dict
)
def test_empty(self):
parameter_dict = self.slave_connection_parameter_dict_dict[
'empty']
self.assertLogAccessUrlWithPop(parameter_dict, 'empty')
self.assertEqual(
parameter_dict,
{
'domain': 'empty.example.com',
'replication_number': '1',
'url': 'http://empty.example.com',
'site_url': 'http://empty.example.com',
'secure_access': 'https://empty.example.com',
'public-ipv4': utils.LOCAL_IPV4,
}
)
result = self.fakeHTTPSResult(
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual(
utils.der2pem(result.peercert),
open('wildcard.example.com.crt').read())
self.assertEqual(result.status_code, no_backend_response_code)
def test_url(self):
parameter_dict = self.slave_connection_parameter_dict_dict[
'url'].copy()
self.assertEqual(
parameter_dict, {}
)
def test_https_url(self):
parameter_dict = self.slave_connection_parameter_dict_dict[
'https-url'].copy()
self.assertEqual(
parameter_dict, {}
)
TestMalformedBackenUrlSlave-0/var/log/monitor-httpd-error.log
TestMalformedBackenUrlSlave-1/var/log/frontend-access.log
TestMalformedBackenUrlSlave-1/var/log/frontend-error.log
TestMalformedBackenUrlSlave-1/var/log/httpd/_empty_access_log
TestMalformedBackenUrlSlave-1/var/log/httpd/_empty_error_log
TestMalformedBackenUrlSlave-1/var/log/monitor-httpd-error.log
TestMalformedBackenUrlSlave-1/var/log/nginx-access.log
TestMalformedBackenUrlSlave-1/var/log/nginx-error.log
TestMalformedBackenUrlSlave-1/var/log/trafficserver/manager.log
TestMalformedBackenUrlSlave-1/var/log/trafficserver/traffic.out
\ No newline at end of file
TestMalformedBackenUrlSlave-0/var/run/monitor-httpd.pid
TestMalformedBackenUrlSlave-0/var/run/monitor/monitor-bootstrap.pid
TestMalformedBackenUrlSlave-1/var/run/caddy_configuration.signature
TestMalformedBackenUrlSlave-1/var/run/httpd.pid
TestMalformedBackenUrlSlave-1/var/run/monitor-httpd.pid
TestMalformedBackenUrlSlave-1/var/run/monitor/monitor-bootstrap.pid
TestMalformedBackenUrlSlave-1/var/run/ncaddy_configuration.signature
TestMalformedBackenUrlSlave-1/var/run/nginx.pid
TestMalformedBackenUrlSlave-1/etc/monitor-promise/check-_empty-error-log-last-day
TestMalformedBackenUrlSlave-1/etc/monitor-promise/check-_empty-error-log-last-hour
\ No newline at end of file
TestMalformedBackenUrlSlave-0/etc/promise/check-free-disk-space
TestMalformedBackenUrlSlave-0/etc/promise/monitor-http-frontend
TestMalformedBackenUrlSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestMalformedBackenUrlSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
TestMalformedBackenUrlSlave-1/etc/promise/caddy-frontend-is-running-actual-software-release
TestMalformedBackenUrlSlave-1/etc/promise/caddy_cached
TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv4_http
TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv4_https
TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv6_http
TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv6_https
TestMalformedBackenUrlSlave-1/etc/promise/caddy_ssl_cached
TestMalformedBackenUrlSlave-1/etc/promise/check-free-disk-space
TestMalformedBackenUrlSlave-1/etc/promise/frontend-caddy-configuration-promise
TestMalformedBackenUrlSlave-1/etc/promise/monitor-http-frontend
TestMalformedBackenUrlSlave-1/etc/promise/monitor-httpd-listening-on-tcp
TestMalformedBackenUrlSlave-1/etc/promise/nginx-configuration-promise
TestMalformedBackenUrlSlave-1/etc/promise/nginx_frontend_ipv4_http
TestMalformedBackenUrlSlave-1/etc/promise/nginx_frontend_ipv4_https
TestMalformedBackenUrlSlave-1/etc/promise/nginx_frontend_ipv6_http
TestMalformedBackenUrlSlave-1/etc/promise/nginx_frontend_ipv6_https
TestMalformedBackenUrlSlave-1/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
TestMalformedBackenUrlSlave-1/etc/promise/promise-nginx-is-process-older-than-dependency-set
TestMalformedBackenUrlSlave-1/etc/promise/re6st-connectivity
TestMalformedBackenUrlSlave-1/etc/promise/trafficserver-cache-availability
TestMalformedBackenUrlSlave-1/etc/promise/trafficserver-port-listening
\ No newline at end of file
TestMalformedBackenUrlSlave-0:bootstrap-monitor EXITED
TestMalformedBackenUrlSlave-0:certificate_authority-on-watch RUNNING
TestMalformedBackenUrlSlave-0:crond RUNNING
TestMalformedBackenUrlSlave-0:monitor-httpd-graceful EXITED
TestMalformedBackenUrlSlave-0:monitor-httpd-on-watch RUNNING
TestMalformedBackenUrlSlave-1:6tunnel-11080-on-watch RUNNING
TestMalformedBackenUrlSlave-1:6tunnel-11443-on-watch RUNNING
TestMalformedBackenUrlSlave-1:6tunnel-12080-on-watch RUNNING
TestMalformedBackenUrlSlave-1:6tunnel-12443-on-watch RUNNING
TestMalformedBackenUrlSlave-1:6tunnel-26011-on-watch RUNNING
TestMalformedBackenUrlSlave-1:6tunnel-26012-on-watch RUNNING
TestMalformedBackenUrlSlave-1:bootstrap-monitor EXITED
TestMalformedBackenUrlSlave-1:certificate_authority-on-watch RUNNING
TestMalformedBackenUrlSlave-1:crond-on-watch RUNNING
TestMalformedBackenUrlSlave-1:frontend-caddy-safe-graceful EXITED
TestMalformedBackenUrlSlave-1:frontend-nginx-safe-graceful EXITED
TestMalformedBackenUrlSlave-1:frontend_caddy-on-watch RUNNING
TestMalformedBackenUrlSlave-1:frontend_nginx-on-watch RUNNING
TestMalformedBackenUrlSlave-1:monitor-httpd-graceful EXITED
TestMalformedBackenUrlSlave-1:monitor-httpd-on-watch RUNNING
TestMalformedBackenUrlSlave-1:trafficserver-on-watch RUNNING
TestMalformedBackenUrlSlave-1:trafficserver-reload EXITED
watchdog:watchdog RUNNING
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment