diff --git a/README.md b/README.md index 2b3758a..e4412c5 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,17 @@ ansible-playbook -i inventory.yml --ask-vault-pass main.yml ``` You need to provide a user with sudo rights and the vault password. + +## HTTPS ingress configuration + +HTTPS ingress is controlled by the server [holmium](https://wiki.netz39.de/admin:servers:holmium) and forwarded to the configured servers. + +To set up a new HTTPS vhost, the following steps need to be taken: + +1. Select a domain (for internal services we use sub-domains of `.n39.eu`). +2. Create an external CNAME from this domain to `dyndns.n39.eu`. +3. Create an internal DNS entry in the [Descartes DNS config](https://gitea.n39.eu/Netz39_Admin/config.descartes/src/branch/prepare/dns_dhcp.txt). This is usually an alias on an existing server. +4. Add the entry to the [holmium playbook](holmium.yml). +5. Set up Dehydrated and vhost on the target host, e.g. using `setup-http-site-proxy`. + +Do not forget to execute all playbooks with relevant changes. diff --git a/holmium.yml b/holmium.yml index 392bb2f..753092b 100644 --- a/holmium.yml +++ b/holmium.yml @@ -6,7 +6,27 @@ ansible_python_interpreter: /usr/bin/python3 roles: - - tasks: - - handlers: + - role: nginx-https-ingress + vars: + ingress: + - server: kant + hosts: + - jabber.n39.eu + - conference.jabber.n39.eu + - spaceapi.n39.eu + - server: krypton + hosts: + - entities.svc.n39.eu + - server: pottwal + hosts: + - gitea.n39.eu + - uritools.n39.eu + - entities-validation.svc.n39.eu + - sl.n39.eu + - pad.n39.eu + - brotherql-web.n39.eu + - server: radon + hosts: + - nodered.n39.eu + - rabbitmq.n39.eu + - pwr-meter-pulse-gw-19i.svc.n39.eu diff --git a/roles/nginx-https-ingress/files/apt-preference-99nginx b/roles/nginx-https-ingress/files/apt-preference-99nginx new file mode 100644 index 0000000..1513083 --- /dev/null +++ b/roles/nginx-https-ingress/files/apt-preference-99nginx @@ -0,0 +1,4 @@ +Package: * +Pin: origin nginx.org +Pin: release o=nginx +Pin-Priority: 900 diff --git a/roles/nginx-https-ingress/files/nginx.conf b/roles/nginx-https-ingress/files/nginx.conf new file mode 100644 index 0000000..896c9a5 --- /dev/null +++ b/roles/nginx-https-ingress/files/nginx.conf @@ -0,0 +1,34 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +include /etc/nginx/passthrough.conf; + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/dehydrated-hosts/*; +} diff --git a/roles/nginx-https-ingress/handlers/main.yml b/roles/nginx-https-ingress/handlers/main.yml new file mode 100644 index 0000000..53aebbb --- /dev/null +++ b/roles/nginx-https-ingress/handlers/main.yml @@ -0,0 +1,7 @@ +# Handlers für nginx-https-proxy +--- +- name: restart nginx + service: + name: nginx + state: restarted + enabled: yes diff --git a/roles/nginx-https-ingress/tasks/main.yml b/roles/nginx-https-ingress/tasks/main.yml new file mode 100644 index 0000000..ff095d1 --- /dev/null +++ b/roles/nginx-https-ingress/tasks/main.yml @@ -0,0 +1,89 @@ +# Tasks für nginx-https-proxy +--- +### Install required packages +# +# At this point, we also check that apt is available, +# which is assumed for all future operations. +- name: Install nginx prerequisites + ansible.builtin.apt: + state: present + name: + - apt-transport-https + - ca-certificates + - gnupg2 + +### Setup APT cache for the nginx repository +# +# We need the nginx repository to get the ngx_stream_core_module +# for SSL passthrough. + +- name: Add nginx apt-key + apt_key: + url: https://nginx.org/keys/nginx_signing.key + state: present + +- name: Add nginx's APT repository + ansible.builtin.template: + src: templates/nginx.list.j2 + dest: /etc/apt/sources.list.d/nginx.list + register: apt_repo + +- name: Set nginx APT preference + ansible.builtin.copy: + src: files/apt-preference-99nginx + dest: /etc/apt/preferences.d/99nginx + +- name: Update package cache + ansible.builtin.apt: + update_cache: true + when: apt_repo.changed + +### Install nginx + +- name: Install nginx + ansible.builtin.apt: + state: present + name: + # This version of nginx comes with the ngx_stream_core_module module + - nginx + + +### Configuration +- name: Setup passthrough matrix + ansible.builtin.template: + src: templates/passthrough.conf.j2 + dest: /etc/nginx/passthrough.conf + owner: root + group: root + mode: '0644' + notify: restart nginx + +- name: Create directory for dehydrated forwardings + ansible.builtin.file: + path: /etc/nginx/dehydrated-hosts + state: directory + owner: root + group: root + mode: '0755' + +- name: Setup dehydrated forwardings + ansible.builtin.template: + src: templates/dehydrated-host.conf.j2 + dest: "/etc/nginx/dehydrated-hosts/{{ item.server }}.conf" + owner: root + group: root + mode: '0644' + loop: "{{ ingress }}" + notify: restart nginx + +- name: Setup nginx configuration + # Note the order here: The nginx configuration _needs_ he dehydrated-hosts + # directory and the passthrough.conf file, so we do them first to ensure + # a valid configuration in case the playbook is cancelled mid-way. + ansible.builtin.copy: + src: files/nginx.conf + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: '0644' + notify: restart nginx diff --git a/roles/nginx-https-ingress/templates/dehydrated-host.conf.j2 b/roles/nginx-https-ingress/templates/dehydrated-host.conf.j2 new file mode 100644 index 0000000..7647271 --- /dev/null +++ b/roles/nginx-https-ingress/templates/dehydrated-host.conf.j2 @@ -0,0 +1,14 @@ +# Dehydrated forwardings for server {{ item.server }} +{% if 'hosts' in item %} +{% for host in item.hosts %} +server { + listen 80; + listen [::]:80; + server_name {{ host }}; + + location /.well-known/acme-challenge { + proxy_pass http://{{ item.server }}.n39.eu:80; + } +} +{% endfor %} +{% endif %} diff --git a/roles/nginx-https-ingress/templates/nginx.list.j2 b/roles/nginx-https-ingress/templates/nginx.list.j2 new file mode 100644 index 0000000..9e4235f --- /dev/null +++ b/roles/nginx-https-ingress/templates/nginx.list.j2 @@ -0,0 +1,2 @@ +deb https://nginx.org/packages/debian/ {{ ansible_distribution_release }} nginx +deb-src https://nginx.org/packages/debian/ {{ ansible_distribution_release }} nginx diff --git a/roles/nginx-https-ingress/templates/passthrough.conf.j2 b/roles/nginx-https-ingress/templates/passthrough.conf.j2 new file mode 100644 index 0000000..b5deb41 --- /dev/null +++ b/roles/nginx-https-ingress/templates/passthrough.conf.j2 @@ -0,0 +1,25 @@ +# SSL passthrough matrix + +stream { + map $ssl_preread_server_name $name { +{% for i in ingress %} +{% if 'hosts' in i %} +{% for host in i.hosts %} + {{ host }} {{ i.server }}; +{% endfor %} +{% endif %} +{% endfor %} + } + +{% for i in ingress %} + upstream {{ i.server }} { + server {{ i.server }}.n39.eu:443; + } +{% endfor %} + + server { + listen 443; + proxy_pass $name; + ssl_preread on; + } +}