From d98a1adfd9c2cdff4a19acdebb0a5d245059a60a Mon Sep 17 00:00:00 2001 From: Franziska Kunsmann Date: Sun, 25 Apr 2021 09:09:23 +0200 Subject: [PATCH] bundles/ssl: support using a preexisting ssl certificate --- bundles/nginx/files/port80.conf | 3 +- bundles/nginx/files/site_template | 6 ++- bundles/nginx/files/ssl_template | 6 +++ bundles/nginx/items.py | 84 +++++++++++++++++++++++-------- 4 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 bundles/nginx/files/ssl_template diff --git a/bundles/nginx/files/port80.conf b/bundles/nginx/files/port80.conf index 4aacfa7..9d2444e 100644 --- a/bundles/nginx/files/port80.conf +++ b/bundles/nginx/files/port80.conf @@ -6,8 +6,9 @@ server { location / { return 308 https://$host$request_uri; } - +% if needs_le: location /.well-known/acme-challenge/ { alias /var/lib/dehydrated/acme-challenges/; } +% endif } diff --git a/bundles/nginx/files/site_template b/bundles/nginx/files/site_template index d4e4c83..83f3ec7 100644 --- a/bundles/nginx/files/site_template +++ b/bundles/nginx/files/site_template @@ -11,9 +11,13 @@ server { listen 443 ssl http2; listen [::]:443 ssl http2; - ssl_trusted_certificate /var/lib/dehydrated/certs/${domain}/chain.pem; +% if ssl == 'letsencrypt': ssl_certificate /var/lib/dehydrated/certs/${domain}/fullchain.pem; ssl_certificate_key /var/lib/dehydrated/certs/${domain}/privkey.pem; +% else: + ssl_certificate /etc/nginx/ssl/${vhost}.crt; + ssl_certificate_key /etc/nginx/ssl/${vhost}.key; +% endif ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; diff --git a/bundles/nginx/files/ssl_template b/bundles/nginx/files/ssl_template new file mode 100644 index 0000000..d886bed --- /dev/null +++ b/bundles/nginx/files/ssl_template @@ -0,0 +1,6 @@ +<% + from os.path import isfile, join +%><%include file="ssl/${domain}.crt.pem"/> +% if isfile(join(repo.path, 'data', 'ssl', f'{domain}.crt_intermediate.pem')): +<%include file="ssl/${domain}.crt_intermediate.pem"/> +% endif diff --git a/bundles/nginx/items.py b/bundles/nginx/items.py index 64ec620..cf857ba 100644 --- a/bundles/nginx/items.py +++ b/bundles/nginx/items.py @@ -5,6 +5,12 @@ directories = { 'svc_systemd:nginx:restart', }, }, + '/etc/nginx/ssl': { + 'purge': True, + 'triggers': { + 'svc_systemd:nginx:restart', + }, + }, '/var/www': {}, } @@ -47,27 +53,13 @@ svc_systemd = { }, } -# Always redirect all traffic to HTTPS, except if there is only one -# vhost and this vhost has ssl disabled. -install_port80_redirect = True -if len(node.metadata.get('nginx/vhosts', {})) == 1: - vhost_name = list(node.metadata['nginx']['vhosts'].keys())[0] - if node.metadata.get('nginx/vhosts/{}/ssl'.format(vhost_name), 'letsencrypt') == False: - install_port80_redirect = False - -if install_port80_redirect: - files['/etc/nginx/sites/000-port80.conf'] = { - 'source': 'port80.conf', - 'triggers': { - 'svc_systemd:nginx:restart', - }, - } - +install_port80_redirect = False +port80_has_letsencrypt = False for vhost, config in node.metadata.get('nginx/vhosts', {}).items(): if not 'domain' in config: config['domain'] = vhost - files['/etc/nginx/sites/{}'.format(vhost)] = { + files[f'/etc/nginx/sites/{vhost}'] = { 'source': 'site_template', 'content_type': 'mako', 'context': { @@ -76,20 +68,70 @@ for vhost, config in node.metadata.get('nginx/vhosts', {}).items(): **config, }, 'needs': set(), + 'needed_by': { + 'svc_systemd:nginx', + 'svc_systemd:nginx:restart', + }, 'triggers': { 'svc_systemd:nginx:restart', }, } if not 'webroot' in config: - directories['/var/www/{}'.format(vhost)] = {} + directories[f'/var/www/{vhost}'] = {} if node.has_bundle('zfs'): - directories['/var/www/{}'.format(vhost)]['needs'] = { + directories[f'/var/www/{vhost}']['needs'] = { 'bundle:zfs', } - directories['/var/www/{}'.format(vhost)].update(config.get('webroot_config', {})) + directories[f'/var/www/{vhost}'].update(config.get('webroot_config', {})) if config.get('ssl', 'letsencrypt') == 'letsencrypt': - files['/etc/nginx/sites/{}'.format(vhost)]['needs'].add('action:letsencrypt_ensure-some-certificate_{}'.format(config['domain'])) + files[f'/etc/nginx/sites/{vhost}']['needs'].add('action:letsencrypt_ensure-some-certificate_{}'.format(config['domain'])) + files[f'/etc/nginx/sites/{vhost}']['needed_by'].add('action:letsencrypt_update_certificates') + port80_has_letsencrypt = True + install_port80_redirect = True + + elif config.get('ssl', 'letsencrypt'): + files[f'/etc/nginx/ssl/{vhost}.crt'] = { + 'content_type': 'mako', + 'source': 'ssl_template', + 'context': { + 'domain': config['ssl'], + }, + 'needed_by': { + 'svc_systemd:nginx', + 'svc_systemd:nginx:restart', + }, + 'triggers': { + 'svc_systemd:nginx:reload', + }, + } + files[f'/etc/nginx/ssl/{vhost}.key'] = { + 'content': repo.vault.decrypt_file('ssl/{}.key.pem.vault'.format(config['ssl'])), + 'mode': '0600', + 'needed_by': { + 'svc_systemd:nginx', + 'svc_systemd:nginx:restart', + }, + 'triggers': { + 'svc_systemd:nginx:reload', + }, + } + + files[f'/etc/nginx/sites/{vhost}']['needs'].add(f'file:/etc/nginx/ssl/{vhost}.crt') + files[f'/etc/nginx/sites/{vhost}']['needs'].add(f'file:/etc/nginx/ssl/{vhost}.key') + install_port80_redirect = True + +if install_port80_redirect: + files['/etc/nginx/sites/000-port80.conf'] = { + 'source': 'port80.conf', + 'content_type': 'mako', + 'context': { + 'needs_le': port80_has_letsencrypt, + }, + 'triggers': { + 'svc_systemd:nginx:restart', + }, + }