diff --git a/group_vars/certbot.yml b/group_vars/certbot.yml new file mode 100644 index 0000000..011aa68 --- /dev/null +++ b/group_vars/certbot.yml @@ -0,0 +1,8 @@ +--- +glob_certbot: + dns_rfc2136_server: '10.128.0.30' + dns_rfc2136_name: certbot_challenge. + dns_rfc2136_secret: "{{ vault_certbot_dns_secret }}" + mail: tech.aurore@lists.crans.org + certname: auro.re + domains: "auro.re" diff --git a/group_vars/nginx.yml b/group_vars/nginx.yml new file mode 100644 index 0000000..eef80da --- /dev/null +++ b/group_vars/nginx.yml @@ -0,0 +1,24 @@ +--- +glob_nginx: + contact: tech.aurore@lists.crans.org + who: "L'équipe technique d'Aurore" + service_name: service + ssl: + cert: /etc/letsencrypt/live/auro.re/fullchain.pem + cert_key: /etc/letsencrypt/live/auro.re/privkey.pem + trusted_cert: /etc/letsencrypt/live/auro.re/chain.pem + servers: + - ssl: false + server_name: + - "default" + - "_" + root: "/var/www/html" + locations: + - filter: "/" + params: [] + upstreams: [] + + auth_passwd: [] + default_server: + default_ssl_server: + deploy_robots_file: false diff --git a/host_vars/portail.adm.auro.re.yml b/host_vars/portail.adm.auro.re.yml new file mode 100644 index 0000000..e13a06d --- /dev/null +++ b/host_vars/portail.adm.auro.re.yml @@ -0,0 +1,116 @@ +--- +loc_certbot: + domains: + - portail-fleming.auro.re + - portail-pacaterie.auro.re + - portail-rives.auro.re + - portail-edc.auro.re + - portail-gs.auro.re + mail: tech.aurore@lists.crans.org + certname: auro.re + +loc_nginx: + service_name: captive_portal + default_server: '$server_addr' + default_ssl_server: '$server_addr' + + servers: + - ssl: false + server_name: + - "10.13.0.247" + locations: + - filter: "/" + params: + - "return 302 https://portail-fleming.auro.re/portail/" + + - ssl: true + server_name: + - portail-fleming.auro.re + locations: + - filter: "~ /(potail|cotisations/comnpay|static|javascript|media|about|contact|logout|.*-autocomplete)" + params: + - "proxy_pass http://10.128.0.20" + - "include /etc/nginx/snippets/options-proxypass.conf" + - filter: "/" + params: + - "return 302 https://portail-fleming.auro.re/portail/" + + - ssl: false + server_name: + - 10.23.0.247 + locations: + - filter: "/" + params: + - "return 302 https://portail-pacaterie.auro.re/portail/" + + - ssl: true + server_name: + - portail-pacaterie.auro.re + locations: + - filter: "~ /(potail|cotisations/comnpay|static|javascript|media|about|contact|logout|.*-autocomplete)" + params: + - "proxy_pass http://10.128.0.20" + - "include /etc/nginx/snippets/options-proxypass.conf" + - filter: "/" + params: + - "return 302 https://portail-pacaterie.auro.re/portail/" + + - ssl: false + server_name: + - "10.33.0.247" + locations: + - filter: "/" + params: + - "return 302 https://portail-rives.auro.re/portail/" + + - ssl: true + server_name: + - portail-rives.auro.re + locations: + - filter: "~ /(potail|cotisations/comnpay|static|javascript|media|about|contact|logout|.*-autocomplete)" + params: + - "proxy_pass http://10.128.0.20" + - "include /etc/nginx/snippets/options-proxypass.conf" + - filter: "/" + params: + - "return 302 https://portail-rives.auro.re/portail/" + + - ssl: false + server_name: + - "10.43.0.247" + locations: + - filter: "/" + params: + - "return 302 https://portail-edc.auro.re/portail/" + + - ssl: true + server_name: + - portail-edc.auro.re + locations: + - filter: "~ /(potail|cotisations/comnpay|static|javascript|media|about|contact|logout|.*-autocomplete)" + params: + - "proxy_pass http://10.128.0.20" + - "include /etc/nginx/snippets/options-proxypass.conf" + - filter: "/" + params: + - "return 302 https://portail-edc.auro.re/portail/" + + - ssl: false + server_name: + - "10.53.0.247" + locations: + - filter: "/" + params: + - "return 302 https://portail-gs.auro.re/portail/" + + - ssl: true + server_name: + - portail-gs.auro.re + locations: + - filter: "~ /(potail|cotisations/comnpay|static|javascript|media|about|contact|logout|.*-autocomplete)" + params: + - "proxy_pass http://10.128.0.20" + - "include /etc/nginx/snippets/options-proxypass.conf" + - filter: "/" + params: + - "return 302 https://portail-gs.auro.re/portail/" diff --git a/host_vars/proxy.adm.auro.re.yml b/host_vars/proxy.adm.auro.re.yml index b8fb2c3..04184fc 100644 --- a/host_vars/proxy.adm.auro.re.yml +++ b/host_vars/proxy.adm.auro.re.yml @@ -33,7 +33,7 @@ nginx: redirect_sites: - from: 45.66.111.61 - to: auro.re + to: intranet.auro.re reverseproxy_sites: - from: re2o.auro.re diff --git a/hosts b/hosts index eec54a0..55cf3fc 100644 --- a/hosts +++ b/hosts @@ -35,6 +35,7 @@ services-web.adm.auro.re mail.adm.auro.re wikijs.adm.auro.re prometheus-aurore.adm.auro.re +portail.adm.auro.re [aurore_testing_vm] pendragon.adm.auro.re @@ -488,3 +489,8 @@ ldap-replica-ovh.adm.auro.re [ldap_replica_rives] ldap-replica-rives.adm.auro.re +[certbot] +portail.adm.auro.re + +[nginx] +portail.adm.auro.re diff --git a/roles/certbot/tasks/main.yml b/roles/certbot/tasks/main.yml index cbce286..549e7a2 100644 --- a/roles/certbot/tasks/main.yml +++ b/roles/certbot/tasks/main.yml @@ -1,10 +1,10 @@ --- -- name: Install certbot and nginx plugin +- name: Install certbot and RFC2136 plugin apt: update_cache: true name: - certbot - - python3-certbot-nginx + - python3-certbot-dns-rfc2136 register: pkg_result retries: 3 until: pkg_result is succeeded @@ -15,6 +15,19 @@ state: directory mode: 0755 +- name: Lookup DNS masters IPv4 + set_fact: + dns_masters_ipv4: + - "10.128.0.30" + cacheable: true + +- name: Add DNS credentials + template: + src: letsencrypt/rfc2136.ini.j2 + dest: /etc/letsencrypt/rfc2136.ini + mode: 0600 + owner: root + - name: Add Certbot configuration template: src: "letsencrypt/conf.d/certname.ini.j2" diff --git a/roles/certbot/templates/letsencrypt/conf.d/certname.ini.j2 b/roles/certbot/templates/letsencrypt/conf.d/certname.ini.j2 index c23d930..88512d2 100644 --- a/roles/certbot/templates/letsencrypt/conf.d/certname.ini.j2 +++ b/roles/certbot/templates/letsencrypt/conf.d/certname.ini.j2 @@ -15,8 +15,13 @@ email = {{ certbot.mail }} # Uncomment to use a text interface instead of ncurses text = True -# Use nginx challenge -authenticator = nginx +# Yes I want to sell my soul and my guinea pig. +agree-tos = True + +# Use DNS-01 challenge +authenticator = dns-rfc2136 +dns-rfc2136-credentials = /etc/letsencrypt/rfc2136.ini +dns-rfc2136-propagation-seconds = 30 # Wildcard the domain cert-name = {{ certbot.certname }} diff --git a/roles/certbot/templates/letsencrypt/rfc2136.ini.j2 b/roles/certbot/templates/letsencrypt/rfc2136.ini.j2 new file mode 100644 index 0000000..948f6a1 --- /dev/null +++ b/roles/certbot/templates/letsencrypt/rfc2136.ini.j2 @@ -0,0 +1,7 @@ +{{ ansible_managed | comment(decoration='# ') }} + +dns_rfc2136_server = {{ certbot.dns_rfc2136_server }} +dns_rfc2136_port = 53 +dns_rfc2136_name = {{ certbot.dns_rfc2136_name }} +dns_rfc2136_secret = {{ certbot.dns_rfc2136_secret }} +dns_rfc2136_algorithm = HMAC-SHA512 diff --git a/roles/logrotate/templates/logrotate.d/rsyslog.j2 b/roles/logrotate/templates/logrotate.d/rsyslog.j2 index beab470..f47e725 100644 --- a/roles/logrotate/templates/logrotate.d/rsyslog.j2 +++ b/roles/logrotate/templates/logrotate.d/rsyslog.j2 @@ -26,7 +26,7 @@ /var/log/debug /var/log/messages { - rotate 1 + rotate 90 daily missingok notifempty diff --git a/roles/nginx/handlers/main.yml b/roles/nginx/handlers/main.yml new file mode 100644 index 0000000..6dfcdd7 --- /dev/null +++ b/roles/nginx/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Reload nginx + systemd: + name: nginx + state: reloaded diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml new file mode 100644 index 0000000..4d4179c --- /dev/null +++ b/roles/nginx/tasks/main.yml @@ -0,0 +1,121 @@ +--- +- name: Install NGINX + apt: + update_cache: true + name: nginx + register: apt_result + retries: 3 + until: apt_result is succeeded + +- name: Copy snippets + template: + src: "nginx/snippets/{{ item }}.j2" + dest: "/etc/nginx/snippets/{{ item }}" + owner: root + group: root + mode: 0644 + loop: + - options-ssl.conf + - options-proxypass.conf + +- name: Copy dhparam + template: + src: letsencrypt/dhparam.j2 + dest: /etc/letsencrypt/dhparam + owner: root + group: root + mode: 0644 + +- name: Disable default site + file: + dest: "/etc/nginx/sites-enabled/default" + state: absent + +- name: Copy reverse proxy sites + when: nginx.reverseproxy_sites is defined or nginx.redirect_sites is defined + template: + src: "nginx/sites-available/{{ item }}.j2" + dest: "/etc/nginx/sites-available/{{ item }}" + owner: root + group: root + mode: 0644 + loop: + - reverseproxy + - reverseproxy_redirect_dname + - redirect + notify: Reload nginx + +- name: Activate reverse proxy sites + when: nginx.reverseproxy_sites is defined or nginx.redirect_sites is defined + file: + src: "/etc/nginx/sites-available/{{ item }}" + dest: "/etc/nginx/sites-enabled/{{ item }}" + owner: root + group: root + state: link + loop: + - reverseproxy + - reverseproxy_redirect_dname + - redirect + notify: Reload nginx + ignore_errors: "{{ ansible_check_mode }}" + +- name: Copy service nginx configuration + when: nginx.servers is defined and nginx.servers|length > 0 + template: + src: "nginx/sites-available/service.j2" + dest: "/etc/nginx/sites-available/{{ nginx.service_name }}" + owner: root + group: root + mode: 0644 + notify: Reload nginx + +- name: Activate local nginx service site + when: nginx.servers is defined and nginx.servers|length > 0 + file: + src: "/etc/nginx/sites-available/{{ nginx.service_name }}" + dest: "/etc/nginx/sites-enabled/{{ nginx.service_name }}" + owner: root + group: root + state: link + notify: Reload nginx + ignore_errors: "{{ ansible_check_mode }}" + +- name: Copy 50x error page + template: + src: www/html/50x.html.j2 + dest: /var/www/html/50x.html + owner: www-data + group: www-data + mode: 0644 + +- name: Copy robots.txt file + when: nginx.deploy_robots_file + template: + src: www/html/robots.txt.j2 + dest: /var/www/html/robots.txt + owner: www-data + group: www-data + mode: 0644 + +- name: Indicate role in motd + template: + src: update-motd.d/05-service.j2 + dest: /etc/update-motd.d/05-nginx + mode: 0755 + +- name: Install passwords + when: nginx.auth_passwd|length > 0 + template: + src: nginx/passwd.j2 + dest: /etc/nginx/passwd + mode: 0644 + +- name: Copy 401 error page + when: nginx.auth_passwd|length > 0 + template: + src: www/html/401.html.j2 + dest: /var/www/html/401.html + owner: www-data + group: www-data + mode: 0644 diff --git a/roles/nginx/templates/letsencrypt/dhparam.j2 b/roles/nginx/templates/letsencrypt/dhparam.j2 new file mode 100644 index 0000000..9b182b7 --- /dev/null +++ b/roles/nginx/templates/letsencrypt/dhparam.j2 @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- diff --git a/roles/nginx/templates/nginx/passwd.j2 b/roles/nginx/templates/nginx/passwd.j2 new file mode 100644 index 0000000..6e61ce2 --- /dev/null +++ b/roles/nginx/templates/nginx/passwd.j2 @@ -0,0 +1,4 @@ +# {{ ansible_managed }} +{% for user, hash in nginx.auth_passwd.items() -%} +{{ user }}: {{ hash }} +{% endfor -%} diff --git a/roles/nginx/templates/nginx/sites-available/redirect.j2 b/roles/nginx/templates/nginx/sites-available/redirect.j2 new file mode 100644 index 0000000..28e9b7d --- /dev/null +++ b/roles/nginx/templates/nginx/sites-available/redirect.j2 @@ -0,0 +1,67 @@ +# {{ ansible_managed }} + +{% for site in nginx.redirect_sites %} +# Redirect http://{{ site.from }} to http://{{ site.to }} +server { + listen 80; + listen [::]:80; + + server_name {{ site.from }}; + + location / { + return 302 http://{{ site.to }}$request_uri; + } +} + +# Redirect https://{{ site.from }} to https://{{ site.to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ site.from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + location / { + return 302 https://{{ site.to }}$request_uri; + } +} + +{% endfor %} + +{# Also redirect for DNAMEs #} +{% for dname in nginx.redirect_dnames %} +{% for site in nginx.redirect_sites %} +{% set from = site.from | regex_replace('crans.org', dname) %} +{% if from != site.from %} +# Redirect http://{{ from }} to http://{{ site.to }} +server { + listen 80; + listen [::]:80; + + server_name {{ from }}; + + location / { + return 302 http://{{ site.to }}$request_uri; + } +} + +# Redirect https://{{ from }} to https://{{ site.to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + location / { + return 302 https://{{ site.to }}$request_uri; + } +} + +{% endif %} +{% endfor %} +{% endfor %} diff --git a/roles/nginx/templates/nginx/sites-available/reverseproxy.j2 b/roles/nginx/templates/nginx/sites-available/reverseproxy.j2 new file mode 100644 index 0000000..d29d13c --- /dev/null +++ b/roles/nginx/templates/nginx/sites-available/reverseproxy.j2 @@ -0,0 +1,56 @@ +# {{ ansible_managed }} + +# Automatic Connection header for WebSocket support +# See http://nginx.org/en/docs/http/websocket.html +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +{% for site in nginx.reverseproxy_sites %} +# Redirect http://{{ site.from }} to https://{{ site.from }} +server { + listen 80; + listen [::]:80; + + server_name {{ site.from }}; + + location / { + return 302 https://$host$request_uri; + } +} + +# Reverse proxify https://{{ site.from }} to http://{{ site.to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ site.from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + # Log into separate log files + access_log /var/log/nginx/{{ site.from }}.log; + error_log /var/log/nginx/{{ site.from }}_error.log; + + # Keep the TCP connection open a bit for faster browsing + keepalive_timeout 70; + + # Custom error page + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /var/www/html; + } + + set_real_ip_from 10.231.136.0/24; + set_real_ip_from 2a0c:700:0:2::/64; + real_ip_header P-Real-Ip; + + location / { + proxy_pass http://{{ site.to }}; + include "/etc/nginx/snippets/options-proxypass.conf"; + } +} + +{% endfor %} diff --git a/roles/nginx/templates/nginx/sites-available/reverseproxy_redirect_dname.j2 b/roles/nginx/templates/nginx/sites-available/reverseproxy_redirect_dname.j2 new file mode 100644 index 0000000..4edda25 --- /dev/null +++ b/roles/nginx/templates/nginx/sites-available/reverseproxy_redirect_dname.j2 @@ -0,0 +1,37 @@ +# {{ ansible_managed }} + +{% for dname in nginx.redirect_dnames %} +{% for site in nginx.reverseproxy_sites %} +{% set from = site.from | regex_replace('crans.org', dname) %} +{% set to = site.from %} +{% if from != site.from %} +# Redirect http://{{ from }} to http://{{ to }} +server { + listen 80; + listen [::]:80; + + server_name {{ from }}; + + location / { + return 302 http://{{ to }}$request_uri; + } +} + +# Redirect https://{{ from }} to https://{{ to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + location / { + return 302 https://{{ to }}$request_uri; + } +} + +{% endif %} +{% endfor %} +{% endfor %} diff --git a/roles/nginx/templates/nginx/sites-available/service.j2 b/roles/nginx/templates/nginx/sites-available/service.j2 new file mode 100644 index 0000000..3d9db5d --- /dev/null +++ b/roles/nginx/templates/nginx/sites-available/service.j2 @@ -0,0 +1,114 @@ +# {{ ansible_managed }} + +# Automatic Connection header for WebSocket support +# See http://nginx.org/en/docs/http/websocket.html +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +{% for upstream in nginx.upstreams -%} +upstream {{ upstream.name }} { + # Path of the server + server {{ upstream.server }}; +} +{% endfor -%} + +{% if nginx.default_ssl_server -%} +# Redirect all services to the main site +server { + listen 443 default_server ssl; + listen [::]:443 default_server ssl; + include "/etc/nginx/snippets/options-ssl.conf"; + + server_name _; + charset utf-8; + + # Hide Nginx version + server_tokens off; + + location / { + return 302 https://{{ nginx.default_ssl_server }}$request_uri; + } +} +{% endif -%} + +{% if nginx.default_server -%} +# Redirect all services to the main site +server { + listen 80 default_server; + listen [::]:80 default_server; + + server_name _; + charset utf-8; + + # Hide Nginx version + server_tokens off; + + location / { + return 302 http://{{ nginx.default_server }}$request_uri; + } +} +{% endif -%} + +{% for server in nginx.servers %} +{% if server.ssl is defined and server.ssl -%} +# Redirect HTTP to HTTPS +server { + listen 80; + listen [::]:80; + + server_name {{ server.server_name|join(" ") }}; + charset utf-8; + + # Hide Nginx version + server_tokens off; + + location / { + return 302 https://$host$request_uri; + } +} +{% endif -%} + +server { + {% if server.ssl is defined and server.ssl -%} + listen 443 ssl; + listen [::]:443 ssl; + include "/etc/nginx/snippets/options-ssl.conf"; + {% else -%} + listen 80; + listen [::]:80; + {% endif -%} + + server_name {{ server.server_name|join(" ") }}; + charset utf-8; + + # Hide Nginx version + server_tokens off; + + {% if server.root is defined -%} + root {{ server.root }}; + {% endif -%} + {% if server.index is defined -%} + index {{ server.index|join(" ") }}; + {% endif -%} + + {% if server.access_log is defined -%} + access_log {{ server.access_log }}; + {% endif -%} + {% if server.error_log is defined -%} + error_log {{ server.error_log }}; + {% endif -%} + + {% if server.locations is defined -%} + + {% for location in server.locations -%} + location {{ location.filter }} { + {% for param in location.params -%} + {{ param }}; + {% endfor -%} + } + {% endfor -%} +{% endif -%} +} +{% endfor %} diff --git a/roles/nginx/templates/nginx/snippets/fastcgi.conf.j2 b/roles/nginx/templates/nginx/snippets/fastcgi.conf.j2 new file mode 100644 index 0000000..0b21030 --- /dev/null +++ b/roles/nginx/templates/nginx/snippets/fastcgi.conf.j2 @@ -0,0 +1,18 @@ +# {{ ansible_managed }} + +# regex to split $uri to $fastcgi_script_name and $fastcgi_path +fastcgi_split_path_info (^/[^/]*)(.*)$; + +# check that the PHP script exists before passing it +try_files $fastcgi_script_name =404; + +# Bypass the fact that try_files resets $fastcgi_path_info +# see: http://trac.nginx.org/nginx/ticket/321 +set $path_info $fastcgi_path_info; +fastcgi_param PATH_INFO $path_info; + +# Let NGINX handle errors +fastcgi_intercept_errors on; + +include /etc/nginx/fastcgi.conf; +fastcgi_pass unix:/var/run/fcgiwrap.socket; diff --git a/roles/nginx/templates/nginx/snippets/options-proxypass.conf.j2 b/roles/nginx/templates/nginx/snippets/options-proxypass.conf.j2 new file mode 100644 index 0000000..9515d81 --- /dev/null +++ b/roles/nginx/templates/nginx/snippets/options-proxypass.conf.j2 @@ -0,0 +1,19 @@ +# {{ ansible_managed }} + +proxy_redirect off; +proxy_set_header Host $host; + +# Pass the real client IP +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + +# Tell proxified server that we are HTTPS, fix Wordpress +proxy_set_header X-Forwarded-Proto https; + +# WebSocket support +proxy_http_version 1.1; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection $connection_upgrade; + +# For Owncloud WebDav +client_max_body_size 10G; diff --git a/roles/nginx/templates/nginx/snippets/options-ssl.conf.j2 b/roles/nginx/templates/nginx/snippets/options-ssl.conf.j2 new file mode 100644 index 0000000..fee51c6 --- /dev/null +++ b/roles/nginx/templates/nginx/snippets/options-ssl.conf.j2 @@ -0,0 +1,17 @@ +# {{ ansible_managed }} + +ssl_certificate {{ nginx.ssl.cert }}; +ssl_certificate_key {{ nginx.ssl.cert_key }}; +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; +ssl_session_tickets off; +ssl_dhparam /etc/letsencrypt/dhparam; +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; +ssl_prefer_server_ciphers off; + +# Enable OCSP Stapling, point to certificate chain +ssl_stapling on; +ssl_stapling_verify on; +ssl_trusted_certificate {{ nginx.ssl.trusted_cert }}; + diff --git a/roles/nginx/templates/update-motd.d/05-service.j2 b/roles/nginx/templates/update-motd.d/05-service.j2 new file mode 100755 index 0000000..fdff0b8 --- /dev/null +++ b/roles/nginx/templates/update-motd.d/05-service.j2 @@ -0,0 +1,3 @@ +#!/usr/bin/tail +14 +# {{ ansible_managed }} +> NGINX a été déployé sur cette machine. Voir /etc/nginx/. diff --git a/roles/nginx/templates/www/html/401.html.j2 b/roles/nginx/templates/www/html/401.html.j2 new file mode 100644 index 0000000..93fc38a --- /dev/null +++ b/roles/nginx/templates/www/html/401.html.j2 @@ -0,0 +1,18 @@ +{{ ansible_header | comment('xml') }} + + + + Accès refusé + + + +

Accès refusé

+

+ Pour éviter le scan des adresses de diffusions par un robot, cette page demande un identifiant et mot de passe. +

+ + + diff --git a/roles/nginx/templates/www/html/50x.html.j2 b/roles/nginx/templates/www/html/50x.html.j2 new file mode 100644 index 0000000..078e2de --- /dev/null +++ b/roles/nginx/templates/www/html/50x.html.j2 @@ -0,0 +1,63 @@ + + + + + 502 + + + + +

502

+

Whoops, le service prend trop de temps à répondre…

+

Essayez de rafraîchir la page. Si le problème persiste, pensez + à contacter {{ nginx.who }}.

+ + + diff --git a/roles/nginx/templates/www/html/robots.txt.j2 b/roles/nginx/templates/www/html/robots.txt.j2 new file mode 100644 index 0000000..3fbaed7 --- /dev/null +++ b/roles/nginx/templates/www/html/robots.txt.j2 @@ -0,0 +1,4 @@ +{{ ansible_header | comment }} + +User-agent: * +Disallow: / diff --git a/roles/nginx_reverseproxy/templates/nginx/sites-available/redirect.j2 b/roles/nginx_reverseproxy/templates/nginx/sites-available/redirect.j2 index 28e9b7d..9b0e8ca 100644 --- a/roles/nginx_reverseproxy/templates/nginx/sites-available/redirect.j2 +++ b/roles/nginx_reverseproxy/templates/nginx/sites-available/redirect.j2 @@ -9,7 +9,7 @@ server { server_name {{ site.from }}; location / { - return 302 http://{{ site.to }}$request_uri; + return 302 http://{{ site.to }}{% if site.norequesturi is not defined %}$request_uri{% endif %}; } } @@ -24,7 +24,7 @@ server { include "/etc/nginx/snippets/options-ssl.conf"; location / { - return 302 https://{{ site.to }}$request_uri; + return 302 https://{{ site.to }}{% if site.norequesturi is not defined %}$request_uri{% endif %}; } } @@ -43,7 +43,7 @@ server { server_name {{ from }}; location / { - return 302 http://{{ site.to }}$request_uri; + return 302 http://{{ site.to }}{% if site.norequesturi is not defined %}$request_uri{% endif %}; } } @@ -58,7 +58,7 @@ server { include "/etc/nginx/snippets/options-ssl.conf"; location / { - return 302 https://{{ site.to }}$request_uri; + return 302 https://{{ site.to }}{% if site.norequesturi is not defined %}$request_uri{% endif %}; } } diff --git a/roles/nginx_reverseproxy/templates/nginx/sites-available/reverseproxy.j2 b/roles/nginx_reverseproxy/templates/nginx/sites-available/reverseproxy.j2 index d29d13c..9c8c152 100644 --- a/roles/nginx_reverseproxy/templates/nginx/sites-available/reverseproxy.j2 +++ b/roles/nginx_reverseproxy/templates/nginx/sites-available/reverseproxy.j2 @@ -47,6 +47,12 @@ server { set_real_ip_from 2a0c:700:0:2::/64; real_ip_header P-Real-Ip; +{% if site.custom_args is defined -%} +{% for arg in site.custom_args %} + {{ arg }}; +{% endfor %} +{% endif %} + location / { proxy_pass http://{{ site.to }}; include "/etc/nginx/snippets/options-proxypass.conf"; diff --git a/roles/router/tasks/main.yml b/roles/router/tasks/main.yml index 2014572..cfbf28e 100644 --- a/roles/router/tasks/main.yml +++ b/roles/router/tasks/main.yml @@ -30,11 +30,19 @@ mode: 0644 when: "'routeur-aurore' in ansible_hostname" +- name: Install ipset + apt: + name: ipset + update_cache: true + register: apt_result + retries: 3 + until: apt_result is succeeded + - name: Install aurore-firewall (re2o-service) import_role: name: re2o-service vars: - service_repo: https://gitlab.federez.net/aurore/aurore-firewall.git + service_repo: https://gitea.auro.re/Aurore/aurore-firewall.git service_name: aurore-firewall service_version: aurore service_config: diff --git a/roles/router/templates/firewall_config.py b/roles/router/templates/firewall_config.py index 4f6b755..9971765 100644 --- a/roles/router/templates/firewall_config.py +++ b/roles/router/templates/firewall_config.py @@ -31,7 +31,7 @@ role = ['routeur'] ### Specify each interface role interfaces_type = { - 'routable' : ['ens20', 'ens21'], + 'routable' : ['ens20', 'ens21', 'ens23'], 'sortie' : ['ens19'], 'admin' : ['ens18'] } @@ -57,9 +57,53 @@ nat = [ }, 'ip_sources' : '10.{{ subnet_ids.users_wired }}.0.0/16', 'extra_nat' : { - '10.129.{{ apartment_block_id }}.{{ '1' if "backup" in inventory_hostname else '2' }}40' : '45.66.108.25{{ + 'ens19': { + '10.129.{{ apartment_block_id }}.{{ '1' if "backup" in inventory_hostname else '2' }}40' : '45.66.108.25{{ apartment_block_id }}', - '10.129.{{ apartment_block_id }}.254' : '45.66.108.25{{ apartment_block_id }}' + '10.129.{{ apartment_block_id }}.254' : '45.66.108.25{{ apartment_block_id }}', + }, } + }, + { + 'name': 'Accueil', + 'ip_sources': '10.{{ subnet_ids.users_accueil }}.0.0/16', + 'extra_nat': { + 'ens19': { + '10.{{ subnet_ids.users_accueil }}.1.0/24': '45.66.108.25{{ apartment_block_id }}', + '10.{{ subnet_ids.users_accueil }}.2.0/24': '45.66.108.25{{ apartment_block_id }}', + }, + 'ens23' : { + '10.{{ subnet_ids.users_accueil }}.1.0/24': '10.{{ subnet_ids.users_accueil }}.0.240', + '10.{{ subnet_ids.users_accueil }}.2.0/24': '10.{{ subnet_ids.users_accueil }}.0.240', + }, + }, + 'extra_nat_group': { + 'ens19': 'accueil_ens23_allowed', + }, + }, +] + +# ATTENTION: on doit avoir retry ≥ grace +# ATTENTION: il faut que ip_redirect gère tous les ports +# autorisés dans le profile re2o, sinon on laisse sortir +# du trafic +accueils = [ + { + 'iface': 'ens23', + 'grace_period': 1800, + 'retry_period': 86400, + 'ip_sources': [ + '10.{{ subnet_ids.users_accueil }}.1.0/24', + '10.{{ subnet_ids.users_accueil }}.2.0/24', + ], + 'ip_redirect': { + "tcp": { + "10.{{ subnet_ids.users_accueil }}.0.247": ["80", "443"], + } + }, + 'triggers': [ + ('4', 'tcp', '46.255.53.35', 443), # ComNPay + ('4', 'tcp', '46.255.53.35', 80), + ] } ] diff --git a/roles/router/templates/firewall_config_aurore.py b/roles/router/templates/firewall_config_aurore.py index c41fd92..9565e3b 100644 --- a/roles/router/templates/firewall_config_aurore.py +++ b/roles/router/templates/firewall_config_aurore.py @@ -41,9 +41,11 @@ nat = [ { 'name' : 'AdminVlans', 'extra_nat' : { - '10.129.0.254/32' : '45.66.111.{{ router_hard_ip_suffix }}', - '10.128.0.0/16' : '45.66.111.{{ router_hard_ip_suffix }}', - '10.130.0.0/16' : '45.66.111.{{ router_hard_ip_suffix }}' + 'ens18': { + '10.129.0.254/32' : '45.66.111.{{ router_hard_ip_suffix }}', + '10.128.0.0/16' : '45.66.111.{{ router_hard_ip_suffix }}', + '10.130.0.0/16' : '45.66.111.{{ router_hard_ip_suffix }}', + }, } } ] diff --git a/roles/router/templates/keepalived.conf b/roles/router/templates/keepalived.conf index cd217f3..45f5661 100644 --- a/roles/router/templates/keepalived.conf +++ b/roles/router/templates/keepalived.conf @@ -50,6 +50,9 @@ vrrp_instance VI_ROUT_{{ apartment_block }}_IPv4 { # Wifi 10.{{ subnet_ids.users_wifi }}.0.254/16 brd 10.{{ subnet_ids.users_wifi }}.255.255 dev ens21 scope global + + # Accueil + 10.{{ subnet_ids.users_accueil }}.0.254/16 brd 10.{{ subnet_ids.users_accueil }}.255.255 dev ens23 scope global } diff --git a/roles/unbound/templates/recursive.conf.j2 b/roles/unbound/templates/recursive.conf.j2 index efdebe1..6956ae5 100644 --- a/roles/unbound/templates/recursive.conf.j2 +++ b/roles/unbound/templates/recursive.conf.j2 @@ -23,12 +23,14 @@ server: interface: 10.{{ subnet_ids.ap }}.0.{{ dns_host_suffix }} interface: 10.{{ subnet_ids.users_wired }}.0.{{ dns_host_suffix }} interface: 10.{{ subnet_ids.users_wifi }}.0.{{ dns_host_suffix }} + interface: 10.{{ subnet_ids.users_accueil }}.0.{{ dns_host_suffix }} # IPv6 interface: {{ ipv6_base_prefix }}:{{ subnet_ids.ap }}::0:{{ dns_host_suffix }} interface: {{ ipv6_base_prefix }}:{{ subnet_ids.users_wired }}::0:{{ dns_host_suffix }} interface: {{ ipv6_base_prefix }}:{{ subnet_ids.users_wifi }}::0:{{ dns_host_suffix }} + interface: {{ ipv6_base_prefix }}:{{ subnet_ids.users_accueil }}::0:{{ dns_host_suffix }} # By default, anything other than localhost is refused. @@ -36,12 +38,11 @@ server: access-control: 10.{{ subnet_ids.ap }}.0.0/16 allow access-control: 10.{{ subnet_ids.users_wired }}.0.0/16 allow access-control: 10.{{ subnet_ids.users_wifi }}.0.0/16 allow + access-control: 10.{{ subnet_ids.users_accueil }}.0.0/16 allow access-control: {{ ipv6_base_prefix }}::/32 allow # Fuck it... :) num-threads: {{ ansible_processor_vcpus }} - private-address: 10.0.0.0/8 - # The host cache TTL affects blacklisting of supposedly bogus hosts. # The default was 900 (15 minutes). infra-host-ttl: 60 diff --git a/services_web.yml b/services_web.yml index 6bc6a6d..62b7044 100755 --- a/services_web.yml +++ b/services_web.yml @@ -15,3 +15,11 @@ roles: - certbot - nginx_reverseproxy + +- hosts: portail.adm.auro.re + vars: + certbot: '{{ glob_certbot | default({}) | combine(loc_certbot | default({})) }}' + nginx: '{{ glob_nginx | default({}) | combine(loc_nginx | default({})) }}' + roles: + - certbot + - nginx