From 14cc54f4ed38d3dca1e9bae7f70d15e4e53e927e Mon Sep 17 00:00:00 2001 From: VC Date: Fri, 11 Apr 2025 17:11:15 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB:=20manage=20san=20for=20certificate/d?= =?UTF-8?q?omain/sni=20routing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- inventory/host_vars/web1.yml | 7 ++-- inventory/host_vars/web2.yml | 8 ++-- roles/haproxy/templates/haproxy.cfg.j2 | 39 ++++++++++++++----- roles/nginx/tasks/acme.yml | 2 +- roles/nginx/tasks/main.yml | 2 +- roles/nginx/templates/header.conf.j2 | 2 +- .../templates/vhosts/nintendojo.fr.conf.j2 | 0 .../templates/vhosts/nintendojofr.com.conf.j2 | 0 .../vhosts/perso.libertus.eu.conf.j2 | 0 .../vhosts/perso.nintendojo.fr.conf.j2 | 0 .../nginx/templates/vhosts/r.mateu.be.conf.j2 | 12 +----- .../vhosts/www.nintendojo.fr.conf.j2 | 10 +---- .../vhosts/www.nintendojofr.com.conf.j2 | 10 +---- roles/nsd/tasks/zones.yml | 12 +++++- 14 files changed, 53 insertions(+), 51 deletions(-) delete mode 100644 roles/nginx/templates/vhosts/nintendojo.fr.conf.j2 delete mode 100644 roles/nginx/templates/vhosts/nintendojofr.com.conf.j2 delete mode 100644 roles/nginx/templates/vhosts/perso.libertus.eu.conf.j2 delete mode 100644 roles/nginx/templates/vhosts/perso.nintendojo.fr.conf.j2 diff --git a/inventory/host_vars/web1.yml b/inventory/host_vars/web1.yml index e8f0c91..ddedd1c 100644 --- a/inventory/host_vars/web1.yml +++ b/inventory/host_vars/web1.yml @@ -13,11 +13,10 @@ web_hostname: type: bac - host: mail.libertus.eu type: roundcube - - host: perso.nintendojo.fr - acme_unmanaged: true - - host: perso.libertus.eu - acme_unmanaged: true - host: r.mateu.be + san: + - perso.libertus.eu + - perso.nintendojo.fr - host: ff.libertus.eu type: firefly3 - host: koi.libertus.eu diff --git a/inventory/host_vars/web2.yml b/inventory/host_vars/web2.yml index 7d04007..657ea06 100644 --- a/inventory/host_vars/web2.yml +++ b/inventory/host_vars/web2.yml @@ -2,16 +2,16 @@ php_modules: ['opcache', 'mysql', 'mbstring', 'gd', 'intl', 'xml', 'bcmath', 'curl', 'imagick'] web_hostname: - - host: nintendojo.fr - acme_unmanaged: true - host: www.nintendojo.fr type: wordpress + san: + - nintendojo.fr - host: forum.nintendojo.fr type: phpbb - - host: nintendojofr.com - acme_unmanaged: true - host: www.nintendojofr.com type: retrodojo + san: + - nintendojofr.com - host: forum.nintendojofr.com mariadb_root_pass: !vault | diff --git a/roles/haproxy/templates/haproxy.cfg.j2 b/roles/haproxy/templates/haproxy.cfg.j2 index a8e1e51..114ea8a 100644 --- a/roles/haproxy/templates/haproxy.cfg.j2 +++ b/roles/haproxy/templates/haproxy.cfg.j2 @@ -42,10 +42,19 @@ frontend http acl letsencrypt path_beg /.well-known/acme-challenge redirect scheme https code 301 if !letsencrypt {% for server in haproxy_backend_servers %} -{% for hostname in hostvars[server]['web_hostname'] | sort(attribute='host') %} - ## {{ hostname.host }} configuration - acl host_{{ hostname.host }} hdr(host) -i {{ hostname.host }} - use_backend http_{{ hostvars[server].ansible_host }} if letsencrypt host_{{ hostname.host }} +{% for hostname in ( + (hostvars[server].web_hostname + | map(attribute='host')) + + + (hostvars[server].web_hostname + | selectattr('san', 'defined') + | map(attribute='san') + | flatten) + ) | sort +%} + ## {{ hostname }} configuration + acl host_{{ hostname }} hdr(host) -i {{ hostname }} + use_backend http_{{ hostvars[server].ansible_host }} if letsencrypt host_{{ hostname }} {% endfor %} {% endfor %} @@ -57,14 +66,24 @@ frontend https tcp-request inspect-delay 3s tcp-request content accept if { req.ssl_hello_type 1 } {% for server in haproxy_backend_servers %} -{% for hostname in hostvars[server]['web_hostname'] | sort(attribute='host') %} - ## {{ hostname.host }} configuration - acl host_{{ hostname.host }} req.ssl_sni -i {{ hostname.host }} -{% if hostname.allowlistv4 is defined %} - acl network_allowed_{{ hostname.host }} src {% for addrv4 in hostname.allowlistv4 %}{{ addrv4 }}{% endfor %} +{% for hostname in ( + (hostvars[server].web_hostname + | map(attribute='host')) + + + (hostvars[server].web_hostname + | selectattr('san', 'defined') + | map(attribute='san') + | flatten) + ) | sort +%} + ## {{ hostname }} configuration + acl host_{{ hostname }} req.ssl_sni -i {{ hostname }} +{% set host = (hostvars[server].web_hostname | selectattr('host', '==', hostname))[0] %} +{% if host.allowlistv4 is defined %} + acl network_allowed_{{ hostname }} src {% for addrv4 in host.allowlistv4 %}{{ addrv4 }}{% endfor %} {% endif %} - use_backend https_{{ hostvars[server].ansible_host }} if host_{{ hostname.host }}{% if hostname.allowlistv4 is defined %} network_allowed_{{ hostname.host }}{% endif %} + use_backend https_{{ hostvars[server].ansible_host }} if host_{{ hostname }}{% if host.allowlistv4 is defined %} network_allowed_{{ hostname }}{% endif %} {% endfor %} diff --git a/roles/nginx/tasks/acme.yml b/roles/nginx/tasks/acme.yml index f61449b..c8e1d9f 100644 --- a/roles/nginx/tasks/acme.yml +++ b/roles/nginx/tasks/acme.yml @@ -2,7 +2,7 @@ - name: Issue certificate ansible.builtin.command: - cmd: "/etc/x509/acme.sh --issue --domain {{ host.host }} --webroot {{ nginx_letsencrypt_dir }} --reloadcmd \"{{ acme_reload_cmd | default('systemctl reload nginx.service') }}\"" + cmd: "/etc/x509/acme.sh --issue --domain {{ host.host }} {{ ['--domain'] | product(host.san | default([])) | map('join', ' ') | join(' ') }} --webroot {{ nginx_letsencrypt_dir }} --reloadcmd \"{{ acme_reload_cmd | default('systemctl reload nginx.service') }}\"" creates: "/etc/x509/{{ host.host }}*" environment: LE_WORKING_DIR: "/etc/x509" diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml index c794f1f..2808698 100644 --- a/roles/nginx/tasks/main.yml +++ b/roles/nginx/tasks/main.yml @@ -46,7 +46,7 @@ - name: Include acme auto cert ansible.builtin.include_tasks: acme.yml - loop: "{{ web_hostname | rejectattr('acme_unmanaged', 'defined') }}" + loop: "{{ web_hostname }}" loop_control: loop_var: "host" diff --git a/roles/nginx/templates/header.conf.j2 b/roles/nginx/templates/header.conf.j2 index aa0aa6d..ea8c7d9 100644 --- a/roles/nginx/templates/header.conf.j2 +++ b/roles/nginx/templates/header.conf.j2 @@ -3,7 +3,7 @@ ssl_certificate /etc/x509/{{ item.host }}/fullchain.cer; ssl_certificate_key /etc/x509/{{ item.host }}/{{ item.host }}.key; - server_name {{ item.host }}; + server_name {{ item.host }}{{ ' ' ~ item.san | join(' ') if item.san is defined }}; access_log /var/log/nginx/{{ item.host }}.access.log combined; access_log syslog:server=unix:/dev/log combined; error_log /var/log/nginx/{{ item.host }}.error.log; diff --git a/roles/nginx/templates/vhosts/nintendojo.fr.conf.j2 b/roles/nginx/templates/vhosts/nintendojo.fr.conf.j2 deleted file mode 100644 index e69de29..0000000 diff --git a/roles/nginx/templates/vhosts/nintendojofr.com.conf.j2 b/roles/nginx/templates/vhosts/nintendojofr.com.conf.j2 deleted file mode 100644 index e69de29..0000000 diff --git a/roles/nginx/templates/vhosts/perso.libertus.eu.conf.j2 b/roles/nginx/templates/vhosts/perso.libertus.eu.conf.j2 deleted file mode 100644 index e69de29..0000000 diff --git a/roles/nginx/templates/vhosts/perso.nintendojo.fr.conf.j2 b/roles/nginx/templates/vhosts/perso.nintendojo.fr.conf.j2 deleted file mode 100644 index e69de29..0000000 diff --git a/roles/nginx/templates/vhosts/r.mateu.be.conf.j2 b/roles/nginx/templates/vhosts/r.mateu.be.conf.j2 index fae8bff..46908c0 100644 --- a/roles/nginx/templates/vhosts/r.mateu.be.conf.j2 +++ b/roles/nginx/templates/vhosts/r.mateu.be.conf.j2 @@ -1,15 +1,5 @@ server { - listen *:443 ssl http2; - listen [::]:443 ssl http2; - - server_name r.mateu.be perso.nintendojo.fr perso.libertus.eu; - access_log /var/log/nginx/r.mateu.be.access.log combined; - access_log syslog:server=unix:/dev/log combined; - error_log /var/log/nginx/r.mateu.be.error.log; - error_log syslog:server=unix:/dev/log; - ssl_certificate /etc/x509/r.mateu.be/fullchain.cer; - ssl_certificate_key /etc/x509/r.mateu.be/r.mateu.be.key; - +{% include './templates/header.conf.j2' %} root /srv/www-data/r.mateu.be/; location / { diff --git a/roles/nginx/templates/vhosts/www.nintendojo.fr.conf.j2 b/roles/nginx/templates/vhosts/www.nintendojo.fr.conf.j2 index a3dc10b..9c6a707 100644 --- a/roles/nginx/templates/vhosts/www.nintendojo.fr.conf.j2 +++ b/roles/nginx/templates/vhosts/www.nintendojo.fr.conf.j2 @@ -7,15 +7,7 @@ fastcgi_cache_path max_size=250m; server { - listen *:443 ssl http2; - listen [::]:443 ssl http2; - server_name nintendojo.fr www.nintendojo.fr; - access_log /var/log/nginx/nintendojo.fr.access.log combined; - access_log syslog:server=unix:/dev/log combined; - error_log /var/log/nginx/nintendojo.fr.error.log; - error_log syslog:server=unix:/dev/log; - ssl_certificate /etc/x509/www.nintendojo.fr/fullchain.cer; - ssl_certificate_key /etc/x509/www.nintendojo.fr/www.nintendojo.fr.key; +{% include './templates/header.conf.j2' %} root /var/www/www.nintendojo.fr/; index index.html index.htm index.php; diff --git a/roles/nginx/templates/vhosts/www.nintendojofr.com.conf.j2 b/roles/nginx/templates/vhosts/www.nintendojofr.com.conf.j2 index e74a5be..0b963a2 100644 --- a/roles/nginx/templates/vhosts/www.nintendojofr.com.conf.j2 +++ b/roles/nginx/templates/vhosts/www.nintendojofr.com.conf.j2 @@ -1,13 +1,5 @@ server { - listen *:443 ssl http2; - listen [::]:443 ssl http2; - server_name www.nintendojofr.com nintendojofr.com; - access_log /var/log/nginx/nintendojofr.com.access.log combined; - access_log syslog:server=unix:/dev/log combined; - error_log /var/log/nginx/nintendojofr.com.error.log; - error_log syslog:server=unix:/dev/log; - ssl_certificate /etc/x509/www.nintendojofr.com/fullchain.cer; - ssl_certificate_key /etc/x509/www.nintendojofr.com/www.nintendojofr.com.key; +{% include './templates/header.conf.j2' %} root /var/www/www.nintendojofr.com/; index index.html index.htm index.php; diff --git a/roles/nsd/tasks/zones.yml b/roles/nsd/tasks/zones.yml index 70f6fae..52cb779 100644 --- a/roles/nsd/tasks/zones.yml +++ b/roles/nsd/tasks/zones.yml @@ -11,7 +11,17 @@ dns_serial: "{{ ansible_date_time.epoch }}" web_hostname_block: |- {% for webserver in groups['webservers'] | sort -%} - {% for web_hostname in (hostvars[webserver]['web_hostname'] | selectattr('host', 'match', '.*' ~ item.name) | map(attribute='host') | sort) -%} + {% for web_hostname in ( + (hostvars[webserver]['web_hostname'] + | selectattr('host', 'match', '.*' ~ item.name) + | map(attribute='host') + + + (hostvars[webserver]['web_hostname'] + | selectattr('san', 'defined') + | map(attribute='san') + | flatten + | select('match', '.*' ~ item.name))) + | sort) -%} {% if web_hostname is match("(\S+\.){2}") %} {{ web_hostname | regex_replace('\.' ~ item.name ~ '$', '') }} IN CNAME {{ hostvars[webserver].ansible_host }}. {% else %} -- 2.39.5