Commit 102cfd02 authored by Łukasz Nowak's avatar Łukasz Nowak

rapid-cdn: c->h: Implement ciphers

Cipher translation is implented on the node, so that old style and new style
nodes can co-exists in the same cluster, thus making partial upgrade possible.
parent 8a403fed
......@@ -14,7 +14,7 @@
# not need these here).
[template]
filename = instance.cfg.in
md5sum = 5bb84bad160a23a675d778d398a20930
md5sum = a7cd4f5e23208bd9bf37cec03ad92fcd
[profile-common]
filename = instance-common.cfg.in
......@@ -26,11 +26,11 @@ md5sum = 3eb6adca77906f7b2c40b6f7f28c4bec
[profile-master]
filename = instance-master.cfg.in
md5sum = 4dd96ed68befe0b1e3ad5d76cb7c1114
md5sum = b235bcf15d12b477736258b790054c59
[profile-slave-list]
filename = instance-slave-list.cfg.in
md5sum = 47af66841c1197630819202502e4c02f
md5sum = ca2e775e7bd2a96e46113a628461a46f
[profile-master-publish-slave-information]
filename = instance-master-publish-slave-information.cfg.in
......@@ -42,7 +42,7 @@ md5sum = 7c96b713bd25fdad23ff20660e625a58
[template-frontend-haproxy-crt-list]
_update_hash_filename_ = templates/frontend-haproxy-crt-list.in
md5sum = 6bd05ec62e11fd479fadbea292865556
md5sum = f444c9735e5247faba26831fda6f27f9
[template-not-found-html]
_update_hash_filename_ = templates/notfound.html
......
......@@ -72,9 +72,9 @@
"type": "string"
},
"ciphers": {
"description": "List of ciphers. Empty defaults to Caddy list of ciphers. See https://caddyserver.com/docs/tls for more information.",
"title": "Ordered space separated list of ciphers",
"type": "string"
"type": "string",
"default": "ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA AES256-SHA AES128-SHA ECDHE-RSA-DES-CBC3-SHA DES-CBC3-SHA"
},
"request-timeout": {
"default": 600,
......
......@@ -5,7 +5,27 @@
{%- set NAME_BASE = 'caddy-frontend' %}
{#- DANGER! DANGER! #}
{%- set TRUE_VALUES = ['y', 'yes', '1', 'true'] -%}
{%- set GOOD_CIPHER_LIST = ['ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-WITH-CHACHA20-POLY1305', 'ECDHE-RSA-WITH-CHACHA20-POLY1305', 'ECDHE-RSA-AES256-CBC-SHA', 'ECDHE-RSA-AES128-CBC-SHA', 'ECDHE-ECDSA-AES256-CBC-SHA', 'ECDHE-ECDSA-AES128-CBC-SHA', 'RSA-AES256-CBC-SHA', 'RSA-AES128-CBC-SHA', 'ECDHE-RSA-3DES-EDE-CBC-SHA', 'RSA-3DES-EDE-CBC-SHA'] %}
{%- set GOOD_CIPHER_LIST = [
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-GCM-SHA256',
] %}
{%- set CIPHER_TRANSLATION_DICT = {
'ECDHE-ECDSA-WITH-CHACHA20-POLY1305': 'ECDHE-ECDSA-CHACHA20-POLY1305',
'ECDHE-RSA-WITH-CHACHA20-POLY1305': 'ECDHE-RSA-CHACHA20-POLY1305',
'ECDHE-RSA-AES256-CBC-SHA': 'ECDHE-RSA-AES256-SHA',
'ECDHE-RSA-AES128-CBC-SHA': 'ECDHE-RSA-AES128-SHA',
'ECDHE-ECDSA-AES256-CBC-SHA': 'ECDHE-ECDSA-AES256-SHA',
'ECDHE-ECDSA-AES128-CBC-SHA': 'ECDHE-ECDSA-AES128-SHA',
'RSA-AES256-CBC-SHA': 'AES256-SHA',
'RSA-AES128-CBC-SHA': 'AES128-SHA',
'ECDHE-RSA-3DES-EDE-CBC-SHA': 'ECDHE-RSA-DES-CBC3-SHA',
'RSA-3DES-EDE-CBC-SHA': 'DES-CBC3-SHA'
} %}
{%- for key, value in CIPHER_TRANSLATION_DICT.items() %}
{%- do GOOD_CIPHER_LIST.append(value) %}
{%- endfor %}
{#- Allow to pass only some parameters to frontend nodes #}
{%- set FRONTEND_NODE_PASSED_KEY_LIST = [
'plain_http_port',
......@@ -214,8 +234,13 @@ context =
{% set slave_cipher_list = slave.get('ciphers', '').strip().split() %}
{% if slave_cipher_list %}
{% for cipher in slave_cipher_list %}
{% if cipher not in GOOD_CIPHER_LIST %}
{% do slave_error_list.append('Cipher %r is not supported.' % (cipher,)) %}
{% if cipher not in GOOD_CIPHER_LIST %}
{% if cipher in CIPHER_TRANSLATION_DICT %}
{# Real translation happens in instance-slave-list.cfg.in #}
{% do slave_warning_list.append('Cipher %r translated to %r' % (cipher, CIPHER_TRANSLATION_DICT[cipher])) %}
{% else %}
{% do slave_error_list.append('Cipher %r is not supported.' % (cipher,)) %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
......
......@@ -210,9 +210,9 @@
"type": "integer"
},
"ciphers": {
"description": "List of ciphers. Empty defaults to cluster list of ciphers, which by default are Caddy list of ciphers. See https://caddyserver.com/docs/tls for more information.",
"title": "Ordered space separated list of ciphers",
"type": "string"
"type": "string",
"default": "ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA AES256-SHA AES128-SHA ECDHE-RSA-DES-CBC3-SHA DES-CBC3-SHA"
},
"authenticate-to-backend": {
"description": "If set to true the frontend certificate will be used as authentication certificate to the backend. Note: backend might have to know the frontend CA, available with 'backend-client-caucase-url'.",
......
......@@ -40,6 +40,18 @@ context =
[slave-htpasswd]
{#- Prepare configuration parameters #}
{%- set CIPHER_TRANSLATION_DICT = {
'ECDHE-ECDSA-WITH-CHACHA20-POLY1305': 'ECDHE-ECDSA-CHACHA20-POLY1305',
'ECDHE-RSA-WITH-CHACHA20-POLY1305': 'ECDHE-RSA-CHACHA20-POLY1305',
'ECDHE-RSA-AES256-CBC-SHA': 'ECDHE-RSA-AES256-SHA',
'ECDHE-RSA-AES128-CBC-SHA': 'ECDHE-RSA-AES128-SHA',
'ECDHE-ECDSA-AES256-CBC-SHA': 'ECDHE-ECDSA-AES256-SHA',
'ECDHE-ECDSA-AES128-CBC-SHA': 'ECDHE-ECDSA-AES128-SHA',
'RSA-AES256-CBC-SHA': 'AES256-SHA',
'RSA-AES128-CBC-SHA': 'AES128-SHA',
'ECDHE-RSA-3DES-EDE-CBC-SHA': 'ECDHE-RSA-DES-CBC3-SHA',
'RSA-3DES-EDE-CBC-SHA': 'DES-CBC3-SHA'
} %}
{%- set DEFAULT_PORT = {'http': 80, 'https': 443, '': None} %}
{%- for key in ['enable-http2-by-default'] %}
{%- do configuration.__setitem__(key, ('' ~ configuration[key]).lower() in TRUE_VALUES) %}
......@@ -86,11 +98,14 @@ context =
{%- do slave_instance.__setitem__('default-path', slave_instance.get('default-path', '').strip('/') | urlencode) %}
{%- do slave_instance.__setitem__('path', slave_instance.get('path', '').strip('/')) %}
{#- Manage ciphers #}
{%- set slave_ciphers = slave_instance.get('ciphers', '').strip().split() %}
{%- set slave_ciphers = [] %}
{%- for cipher in slave_instance.get('ciphers', '').strip().split() %}
{%- do slave_ciphers.append(CIPHER_TRANSLATION_DICT.get(cipher, cipher)) %}
{%- endfor %}
{%- if slave_ciphers %}
{%- set slave_cipher_list = ' '.join(slave_ciphers) %}
{%- set slave_cipher_list = ':'.join(slave_ciphers) %}
{%- else %}
{%- set slave_cipher_list = configuration['ciphers'].strip() %}
{%- set slave_cipher_list = ':'.join(configuration['ciphers'].strip().split()) %}
{%- endif %}
{%- do slave_instance.__setitem__('ciphers', slave_cipher_list) %}
{#- Manage common instance parameters #}
......
......@@ -96,7 +96,7 @@ configuration.disk-cache-size = 8G
configuration.ram-cache-size = 1G
configuration.re6st-verification-url = http://[2001:67c:1254:4::1]/index.html
configuration.enable-http2-by-default = true
configuration.ciphers =
configuration.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA AES256-SHA AES128-SHA ECDHE-RSA-DES-CBC3-SHA DES-CBC3-SHA
configuration.request-timeout = 600
configuration.frontend-name =
configuration.backend-connect-timeout = 5
......
......@@ -34,9 +34,6 @@
bind {{ slave_parameter['local_ipv4'] }}
{%- if tls %}
tls {{ slave_parameter['certificate'] }} {{ slave_parameter['certificate'] }} {
{%- if slave_parameter['ciphers'] %}
ciphers {{ slave_parameter['ciphers'] }}
{%- endif %}
{%- if slave_parameter['enable_h2'] %}
# Allow http2
alpn h2 http/1.1
......
{%- for slave in frontend_slave_list %}
{%- set entry_list = [] %}
{%- set sslbindconf = [] %}
{#- <crtfile> #}
{%- do entry_list.append(slave['certificate']) %}
{%- if slave['ciphers'] %}
{%- do sslbindconf.append('ciphers %s' % (slave['ciphers']),) %}
{%- endif %}
{%- do entry_list.append('[' + ' '.join(sslbindconf) + ']') %}
{#- <snifilter> #}
{%- do entry_list.extend(slave['host_list']) %}
{{- ' '.join(entry_list) }}
......
......@@ -1922,7 +1922,19 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin, AtsMixin):
},
'ciphers': {
'ciphers': 'RSA-3DES-EDE-CBC-SHA RSA-AES128-CBC-SHA',
}
},
'ciphers-translation-all': {
# all ciphers from instance-master.cfg.in found in GOOD_CIPHER_LIST
# and keys of CIPHER_TRANSLATION_DICT in order to check translations
'ciphers':
'ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 '
'ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 '
'ECDHE-ECDSA-WITH-CHACHA20-POLY1305 ECDHE-RSA-WITH-CHACHA20-POLY1305 '
'ECDHE-RSA-AES256-CBC-SHA ECDHE-RSA-AES128-CBC-SHA '
'ECDHE-ECDSA-AES256-CBC-SHA ECDHE-ECDSA-AES128-CBC-SHA '
'RSA-AES256-CBC-SHA RSA-AES128-CBC-SHA ECDHE-RSA-3DES-EDE-CBC-SHA '
'RSA-3DES-EDE-CBC-SHA',
},
}
monitor_setup_url_key = 'monitor-setup-url'
......@@ -2100,7 +2112,30 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin, AtsMixin):
'warning-slave-dict': {
'_Url': [
"slave url ' %(backend)s/?a=b&c= ' has been converted to "
"'%(backend)s/?a=b&c='" % {'backend': self.backend_url}]}
"'%(backend)s/?a=b&c='" % {'backend': self.backend_url}],
'_ciphers': [
"Cipher 'RSA-3DES-EDE-CBC-SHA' translated to 'DES-CBC3-SHA'",
"Cipher 'RSA-AES128-CBC-SHA' translated to 'AES128-SHA'"],
'_ciphers-translation-all': [
"Cipher 'ECDHE-ECDSA-AES128-CBC-SHA' translated to "
"'ECDHE-ECDSA-AES128-SHA'",
"Cipher 'ECDHE-ECDSA-AES256-CBC-SHA' translated to "
"'ECDHE-ECDSA-AES256-SHA'",
"Cipher 'ECDHE-ECDSA-WITH-CHACHA20-POLY1305' translated to "
"'ECDHE-ECDSA-CHACHA20-POLY1305'",
"Cipher 'ECDHE-RSA-3DES-EDE-CBC-SHA' translated to "
"'ECDHE-RSA-DES-CBC3-SHA'",
"Cipher 'ECDHE-RSA-AES128-CBC-SHA' translated to "
"'ECDHE-RSA-AES128-SHA'",
"Cipher 'ECDHE-RSA-AES256-CBC-SHA' translated to "
"'ECDHE-RSA-AES256-SHA'",
"Cipher 'ECDHE-RSA-WITH-CHACHA20-POLY1305' translated to "
"'ECDHE-RSA-CHACHA20-POLY1305'",
"Cipher 'RSA-3DES-EDE-CBC-SHA' translated to 'DES-CBC3-SHA'",
"Cipher 'RSA-AES128-CBC-SHA' translated to 'AES128-SHA'",
"Cipher 'RSA-AES256-CBC-SHA' translated to 'AES256-SHA'"]
}
}
self.assertEqual(
......@@ -3691,7 +3726,11 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin, AtsMixin):
)
def test_ciphers(self):
parameter_dict = self.assertSlaveBase('ciphers')
parameter_dict = self.assertSlaveBase(
'ciphers', expected_parameter_dict={
'warning-list': [
"Cipher 'RSA-3DES-EDE-CBC-SHA' translated to 'DES-CBC3-SHA'",
"Cipher 'RSA-AES128-CBC-SHA' translated to 'AES128-SHA'"]})
result = fakeHTTPSResult(
parameter_dict['domain'], 'test-path')
......@@ -3717,12 +3756,73 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin, AtsMixin):
configuration_file = glob.glob(
os.path.join(
self.instance_path, '*', 'etc', 'caddy-slave-conf.d', '_ciphers.conf'
self.instance_path, '*', 'etc', 'frontend-haproxy-crt-list.txt'
))[0]
with open(configuration_file) as fh:
self.assertIn(
'ciphers RSA-3DES-EDE-CBC-SHA RSA-AES128-CBC-SHA',
fh.read())
self.assertTrue(
'/_ciphers.pem [ciphers DES-CBC3-SHA:AES128-SHA '
in fh.read()
)
def test_ciphers_translation_all(self):
parameter_dict = self.assertSlaveBase(
'ciphers-translation-all', expected_parameter_dict={
'warning-list': [
"Cipher 'ECDHE-ECDSA-AES128-CBC-SHA' translated to "
"'ECDHE-ECDSA-AES128-SHA'",
"Cipher 'ECDHE-ECDSA-AES256-CBC-SHA' translated to "
"'ECDHE-ECDSA-AES256-SHA'",
"Cipher 'ECDHE-ECDSA-WITH-CHACHA20-POLY1305' translated to "
"'ECDHE-ECDSA-CHACHA20-POLY1305'",
"Cipher 'ECDHE-RSA-3DES-EDE-CBC-SHA' translated to "
"'ECDHE-RSA-DES-CBC3-SHA'",
"Cipher 'ECDHE-RSA-AES128-CBC-SHA' translated to "
"'ECDHE-RSA-AES128-SHA'",
"Cipher 'ECDHE-RSA-AES256-CBC-SHA' translated to "
"'ECDHE-RSA-AES256-SHA'",
"Cipher 'ECDHE-RSA-WITH-CHACHA20-POLY1305' translated to "
"'ECDHE-RSA-CHACHA20-POLY1305'",
"Cipher 'RSA-3DES-EDE-CBC-SHA' translated to 'DES-CBC3-SHA'",
"Cipher 'RSA-AES128-CBC-SHA' translated to 'AES128-SHA'",
"Cipher 'RSA-AES256-CBC-SHA' translated to 'AES256-SHA'"]})
result = fakeHTTPSResult(
parameter_dict['domain'], 'test-path')
self.assertEqual(
self.certificate_pem,
der2pem(result.peercert))
self.assertEqual(http.client.SERVICE_UNAVAILABLE, result.status_code)
result_http = fakeHTTPResult(
parameter_dict['domain'], 'test-path')
self.assertEqual(
http.client.FOUND,
result_http.status_code
)
self.assertEqual(
'https://cipherstranslationall.example.com:%s/test-path' % (HTTP_PORT,),
result_http.headers['Location']
)
configuration_file = glob.glob(
os.path.join(
self.instance_path, '*', 'etc', 'frontend-haproxy-crt-list.txt'
))[0]
with open(configuration_file) as fh:
self.assertTrue(
'/_ciphers.translation.all.pem [ciphers '
'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:'
'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:'
'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:'
'ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:'
'ECDHE-ECDSA-AES128-SHA:AES256-SHA:AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:'
'DES-CBC3-SHA'
in fh.read()
)
def test_enable_cache_custom_domain(self):
parameter_dict = self.assertSlaveBase(
......@@ -5810,12 +5910,12 @@ class TestSlaveCiphers(SlaveHttpFrontendTestCase, TestDataMixin):
configuration_file = glob.glob(
os.path.join(
self.instance_path, '*', 'etc', 'caddy-slave-conf.d',
'_default_ciphers.conf'
self.instance_path, '*', 'etc', 'frontend-haproxy-crt-list.txt'
))[0]
with open(configuration_file) as fh:
self.assertIn(
'ciphers ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384',
'_default_ciphers.pem [ciphers '
'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384 ',
fh.read())
def test_own_ciphers(self):
......@@ -5836,12 +5936,12 @@ class TestSlaveCiphers(SlaveHttpFrontendTestCase, TestDataMixin):
configuration_file = glob.glob(
os.path.join(
self.instance_path, '*', 'etc', 'caddy-slave-conf.d',
'_own_ciphers.conf'
self.instance_path, '*', 'etc', 'frontend-haproxy-crt-list.txt'
))[0]
with open(configuration_file) as fh:
self.assertIn(
'ciphers ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256',
'_own_ciphers.pem [ciphers '
'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 ',
fh.read())
......
......@@ -18,6 +18,7 @@ T-2/var/log/httpd/_auth-to-backend_access_log
T-2/var/log/httpd/_auth-to-backend_backend_log
T-2/var/log/httpd/_bad-backend_access_log
T-2/var/log/httpd/_bad-backend_backend_log
T-2/var/log/httpd/_ciphers-translation-all_access_log
T-2/var/log/httpd/_ciphers_access_log
T-2/var/log/httpd/_custom_domain_access_log
T-2/var/log/httpd/_custom_domain_backend_log
......
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