From d8d7a2bff3c9d4a5a383aaafc28940b6582a6320 Mon Sep 17 00:00:00 2001 From: Matthew Evans Date: Mon, 15 Jul 2024 15:22:01 +0100 Subject: [PATCH 1/6] Linting fix --- ansible/roles/datalab/tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/roles/datalab/tasks/main.yml b/ansible/roles/datalab/tasks/main.yml index f487c01..9b4eaad 100644 --- a/ansible/roles/datalab/tasks/main.yml +++ b/ansible/roles/datalab/tasks/main.yml @@ -72,5 +72,5 @@ minute: "5" hour: "2" day: "1" - month: "1,4,7,10" + month: 1,4,7,10 job: cd /home/{{ ansible_ssh_user }}/datalab; docker compose exec api pipenv run invoke admin.create-backup --strategy-name quarterly-snapshots From 5056b310b9b63e1b0df3691c9a80831cc78d286e Mon Sep 17 00:00:00 2001 From: Matthew Evans Date: Mon, 15 Jul 2024 16:49:08 +0100 Subject: [PATCH 2/6] Adjust certbot scheduling strategy --- ansible/roles/nginx/tasks/main.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ansible/roles/nginx/tasks/main.yml b/ansible/roles/nginx/tasks/main.yml index 4dab4df..1bf8e03 100644 --- a/ansible/roles/nginx/tasks/main.yml +++ b/ansible/roles/nginx/tasks/main.yml @@ -56,7 +56,7 @@ - certbot-www:/var/www/certbot restart_policy: always -- name: Launch certbot container that renews every 24h +- name: Launch certbot container community.docker.docker_container: name: datalab-certbot image: certbot/certbot:latest @@ -65,5 +65,17 @@ - certbot-conf:/etc/letsencrypt - certbot-www:/var/www/certbot restart_policy: always - entrypoint: | - /bin/sh -c 'trap exit TERM; while :; do certbot certonly --webroot -w /var/www/certbot --agree-tos --no-eff-email -d {{ app_url }} -d {{ api_url }}; sleep 24h & wait $${!}; done;' + detach: true + entrypoint: + - /bin/sh + - -c + - certbot renew + +- name: Scheduled SSL renewal with certbot + ansible.builtin.cron: + name: SSL renewal with certbot + minute: "38" + hour: "10" + day: "2" + month: "*" + job: docker run -v certbot-www:/var/www/certbot -v certbot-conf:/etc/letsencrypt certbot/certbot:latest renew From 457ba6b2ca6597e0e9cedd0b354466b6ac8abb26 Mon Sep 17 00:00:00 2001 From: Matthew Evans Date: Thu, 18 Jul 2024 20:18:32 +0200 Subject: [PATCH 3/6] Add certbot helper script --- ansible/roles/nginx/tasks/main.yml | 8 +++++++- ansible/roles/nginx/templates/certbot-docker.sh.j2 | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 ansible/roles/nginx/templates/certbot-docker.sh.j2 diff --git a/ansible/roles/nginx/tasks/main.yml b/ansible/roles/nginx/tasks/main.yml index 1bf8e03..ea90bfa 100644 --- a/ansible/roles/nginx/tasks/main.yml +++ b/ansible/roles/nginx/tasks/main.yml @@ -37,6 +37,12 @@ dest: /home/{{ ansible_ssh_user }}/nginx/rendered/nginx_ssl.conf mode: "0644" +- name: Render templated certbot config + ansible.builtin.template: + src: certbot-docker.sh.j2 + dest: /home/{{ ansible_ssh_user }}/nginx/rendered/certbot-docker.sh + mode: "0644" + - name: Build nginx image community.docker.docker_image: name: datalab-nginx @@ -64,7 +70,7 @@ volumes: - certbot-conf:/etc/letsencrypt - certbot-www:/var/www/certbot - restart_policy: always + restart_policy: false detach: true entrypoint: - /bin/sh diff --git a/ansible/roles/nginx/templates/certbot-docker.sh.j2 b/ansible/roles/nginx/templates/certbot-docker.sh.j2 new file mode 100644 index 0000000..28e7195 --- /dev/null +++ b/ansible/roles/nginx/templates/certbot-docker.sh.j2 @@ -0,0 +1 @@ +docker run -v certbot-www:/var/www/certbot -v certbot-conf:/etc/letsencrypt certbot/certbot certonly --webroot -w /var/www/certbot --no-eff-email --agree-tos -d {{ app_url }} -d {{ api_url }} From 39741c95b62d661d11635d623bcc81bf39b19d7a Mon Sep 17 00:00:00 2001 From: Matthew Evans Date: Mon, 22 Jul 2024 10:23:09 +0100 Subject: [PATCH 4/6] Add separate role for SSL setup --- ansible/Makefile | 3 + ansible/playbook.yml | 12 +++- ansible/roles/nginx/tasks/main.yml | 46 +------------ ansible/roles/ssl_first_run/files/Dockerfile | 12 ++++ ansible/roles/ssl_first_run/files/nginx.conf | 44 ++++++++++++ ansible/roles/ssl_first_run/tasks/main.yml | 68 +++++++++++++++++++ .../templates/certbot-docker.sh.j2 | 2 + 7 files changed, 140 insertions(+), 47 deletions(-) create mode 100644 ansible/roles/ssl_first_run/files/Dockerfile create mode 100644 ansible/roles/ssl_first_run/files/nginx.conf create mode 100644 ansible/roles/ssl_first_run/tasks/main.yml create mode 100644 ansible/roles/ssl_first_run/templates/certbot-docker.sh.j2 diff --git a/ansible/Makefile b/ansible/Makefile index f9ad616..8d4ea3f 100644 --- a/ansible/Makefile +++ b/ansible/Makefile @@ -9,3 +9,6 @@ setup: maintenance: ansible-playbook -v -i inventory.yml --ask-vault-pass playbook.yml --tags="maintenance" + +ssl: + ansible-playbook -v -i inventory.yml --ask-vault-pass playbook.yml --tags="ssl" diff --git a/ansible/playbook.yml b/ansible/playbook.yml index e5a06fa..7da5e9d 100644 --- a/ansible/playbook.yml +++ b/ansible/playbook.yml @@ -3,18 +3,26 @@ hosts: all roles: - role: setup + name: Run OS and disk set up tasks tags: [setup] - role: docker + name: Install and configure Docker tags: [setup] - role: fail2ban + name: Install and configure fail2ban tags: [setup] + - role: ssl_first_run + name: Run stripped down nginx and SSL for the first time + tags: [setup, ssl] - role: datalab + name: Build and launch datalab services tags: [deploy] - role: nginx - tags: [setup, maintenance] + name: Launch nginx container with autorenewing certbot + tags: [setup, maintenance, ssl] tasks: - name: Keep all packages up-to-date ansible.builtin.include_role: name: apt_upgrade - tags: [setup, maintenance] + tags: [maintenance] diff --git a/ansible/roles/nginx/tasks/main.yml b/ansible/roles/nginx/tasks/main.yml index ea90bfa..c668794 100644 --- a/ansible/roles/nginx/tasks/main.yml +++ b/ansible/roles/nginx/tasks/main.yml @@ -1,23 +1,9 @@ --- -- name: Create a Docker volume for certbot-conf (mounted to /etc/letsencrypt) - community.docker.docker_volume: - name: certbot-conf - -- name: Create a Docker volume for certbot-www (mounted to /var/www/certbot) - community.docker.docker_volume: - name: certbot-www - -- name: Build/pull certbot image - community.docker.docker_image: - name: certbot/certbot:latest - source: pull - state: present - force_source: true - - name: Synchronize nginx files to remote ansible.posix.synchronize: src: "{{ role_path }}/files/" dest: /home/{{ ansible_ssh_user }}/nginx + delete: true - name: Make directory for rendered templates ansible.builtin.file: @@ -37,12 +23,6 @@ dest: /home/{{ ansible_ssh_user }}/nginx/rendered/nginx_ssl.conf mode: "0644" -- name: Render templated certbot config - ansible.builtin.template: - src: certbot-docker.sh.j2 - dest: /home/{{ ansible_ssh_user }}/nginx/rendered/certbot-docker.sh - mode: "0644" - - name: Build nginx image community.docker.docker_image: name: datalab-nginx @@ -61,27 +41,3 @@ - certbot-conf:/etc/letsencrypt - certbot-www:/var/www/certbot restart_policy: always - -- name: Launch certbot container - community.docker.docker_container: - name: datalab-certbot - image: certbot/certbot:latest - network_mode: host - volumes: - - certbot-conf:/etc/letsencrypt - - certbot-www:/var/www/certbot - restart_policy: false - detach: true - entrypoint: - - /bin/sh - - -c - - certbot renew - -- name: Scheduled SSL renewal with certbot - ansible.builtin.cron: - name: SSL renewal with certbot - minute: "38" - hour: "10" - day: "2" - month: "*" - job: docker run -v certbot-www:/var/www/certbot -v certbot-conf:/etc/letsencrypt certbot/certbot:latest renew diff --git a/ansible/roles/ssl_first_run/files/Dockerfile b/ansible/roles/ssl_first_run/files/Dockerfile new file mode 100644 index 0000000..c12f46e --- /dev/null +++ b/ansible/roles/ssl_first_run/files/Dockerfile @@ -0,0 +1,12 @@ +FROM nginx:1.25.3 + +WORKDIR /app + +COPY nginx.conf /etc/nginx/nginx.conf +COPY ./rendered/nginx_ssl.conf /etc/nginx/nginx_ssl.conf +COPY ./rendered/include /etc/nginx/include +RUN rm -f /etc/nginx/conf.d/default.conf + + +EXPOSE 80 +EXPOSE 443 diff --git a/ansible/roles/ssl_first_run/files/nginx.conf b/ansible/roles/ssl_first_run/files/nginx.conf new file mode 100644 index 0000000..35feb90 --- /dev/null +++ b/ansible/roles/ssl_first_run/files/nginx.conf @@ -0,0 +1,44 @@ +worker_processes 1; +user nobody nogroup; +# 'user nobody nobody;' for systems with 'nobody' as a group instead + +pid /var/run/nginx.pid; + +events { + worker_connections 1024; # increase if you have lots of clients + accept_mutex off; # set to 'on' if nginx worker_processes > 1 + # 'use epoll;' to enable for Linux 2.6+ + # 'use kqueue;' to enable for FreeBSD, OSX +} + +http { + sendfile on; + include mime.types; + + # Add some security headers + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload;"; + add_header X-Frame-Options "DENY"; + add_header X-XSS-Protection "1; mode=block;"; + add_header X-Content-Type-Options "nosniff;"; + + # Include upstream definitions + # When SSL needs to be nuked, comment out this line and regenerate certs + # include /etc/nginx/include/*; + + # Proxy all HTTP requests to the HTTPS server + server { + listen 80; + listen [::]:80; + server_name _; + + # For certbot challenges + location ^~ /.well-known/acme-challenge { + root /var/www/certbot; + allow all; + } + + location / { + return 301 https://$host$request_uri; + } + } +} diff --git a/ansible/roles/ssl_first_run/tasks/main.yml b/ansible/roles/ssl_first_run/tasks/main.yml new file mode 100644 index 0000000..9b5cfdc --- /dev/null +++ b/ansible/roles/ssl_first_run/tasks/main.yml @@ -0,0 +1,68 @@ +--- +- name: Create a Docker volume for certbot-conf (mounted to /etc/letsencrypt) + community.docker.docker_volume: + name: certbot-conf + +- name: Create a Docker volume for certbot-www (mounted to /var/www/certbot) + community.docker.docker_volume: + name: certbot-www + +- name: Build/pull certbot image + community.docker.docker_image: + name: certbot/certbot:latest + source: pull + state: present + force_source: true + +- name: Synchronize nginx files to remote + ansible.posix.synchronize: + src: "{{ role_path }}/files/" + dest: /home/{{ ansible_ssh_user }}/nginx + +- name: Render templated certbot config + ansible.builtin.template: + src: certbot-docker.sh.j2 + dest: /home/{{ ansible_ssh_user }}/nginx/rendered/certbot-docker.sh + mode: "0744" + +- name: Build nginx image + community.docker.docker_image: + name: datalab-nginx + source: build + state: present + force_source: true + build: + path: /home/{{ ansible_ssh_user }}/nginx + +- name: Launch nginx container without services + community.docker.docker_container: + name: datalab-nginx + image: datalab-nginx + network_mode: host + volumes: + - certbot-conf:/etc/letsencrypt + - certbot-www:/var/www/certbot + restart_policy: false + +- name: Launch certbot container + community.docker.docker_container: + name: datalab-certbot + image: certbot/certbot:latest + network_mode: host + volumes: + - certbot-conf:/etc/letsencrypt + - certbot-www:/var/www/certbot + - /home/{{ ansible_ssh_user }}/nginx/rendered/certbot-docker.sh:/opt/certbot-docker.sh + restart_policy: false + detach: true + entrypoint: + - /opt/certbot-docker.sh + +- name: Scheduled SSL renewal with certbot + ansible.builtin.cron: + name: SSL renewal with certbot + minute: "38" + hour: "10" + day: "2" + month: "*" + job: docker run -v certbot-www:/var/www/certbot -v certbot-conf:/etc/letsencrypt certbot/certbot:latest renew diff --git a/ansible/roles/ssl_first_run/templates/certbot-docker.sh.j2 b/ansible/roles/ssl_first_run/templates/certbot-docker.sh.j2 new file mode 100644 index 0000000..d9837d5 --- /dev/null +++ b/ansible/roles/ssl_first_run/templates/certbot-docker.sh.j2 @@ -0,0 +1,2 @@ +#!/bin/sh +certbot certonly --webroot -w /var/www/certbot --register-unsafely-without-email --no-eff-email --agree-tos -d {{ app_url }} -d {{ api_url }} From bb6e249175bd4042fe1348625017e7705c7eb0f8 Mon Sep 17 00:00:00 2001 From: Matthew Evans Date: Mon, 22 Jul 2024 10:42:51 +0100 Subject: [PATCH 5/6] Allow docker install to break system packages with pip --- ansible/roles/docker/tasks/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ansible/roles/docker/tasks/main.yml b/ansible/roles/docker/tasks/main.yml index 262f800..8a54f8a 100644 --- a/ansible/roles/docker/tasks/main.yml +++ b/ansible/roles/docker/tasks/main.yml @@ -21,6 +21,7 @@ - name: Install Docker Module for Python ansible.builtin.pip: name: docker + break_system_packages: true - name: Add user '{{ ansible_ssh_user }}' to docker group become: true From 6b241f2f48f4a6e149b4a60d0169098fca065acb Mon Sep 17 00:00:00 2001 From: Matthew Evans Date: Mon, 22 Jul 2024 10:45:08 +0100 Subject: [PATCH 6/6] Remove defunct certbot template --- ansible/roles/nginx/templates/certbot-docker.sh.j2 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 ansible/roles/nginx/templates/certbot-docker.sh.j2 diff --git a/ansible/roles/nginx/templates/certbot-docker.sh.j2 b/ansible/roles/nginx/templates/certbot-docker.sh.j2 deleted file mode 100644 index 28e7195..0000000 --- a/ansible/roles/nginx/templates/certbot-docker.sh.j2 +++ /dev/null @@ -1 +0,0 @@ -docker run -v certbot-www:/var/www/certbot -v certbot-conf:/etc/letsencrypt certbot/certbot certonly --webroot -w /var/www/certbot --no-eff-email --agree-tos -d {{ app_url }} -d {{ api_url }}