aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Joe Banks <[email protected]>2022-03-14 22:58:58 +0000
committerGravatar Joe Banks <[email protected]>2022-03-14 23:42:37 +0000
commitc6357463caf3c0f63e152e9ec6f5fce3d7b9d145 (patch)
tree12f0cacd06e999645324be69be211664d334ac42
parentMiscellaneous fixes to jumpcloud & NGINX mTLS (diff)
Add certbot roles
Add a certbot role that generates a certificate on the first host in the NGINX group and then deploys it to all other NGINX hosts. As of now we generate wildcard certs for pythondiscord.com and pydis.wtf. A unique SSH key is generated for each replica host which is restricted for security purposes. A deploy hook is installed to push renewals to other hosts.
-rw-r--r--playbook.yml3
-rw-r--r--roles/certbot/README.md3
-rw-r--r--roles/certbot/tasks/main.yml99
-rw-r--r--roles/certbot/templates/renewal-hook.sh.j26
-rw-r--r--roles/certbot/vars/main/main.yml6
-rw-r--r--roles/certbot/vars/main/vault.yml9
6 files changed, 125 insertions, 1 deletions
diff --git a/playbook.yml b/playbook.yml
index 126ad47..d7ca9bc 100644
--- a/playbook.yml
+++ b/playbook.yml
@@ -12,9 +12,10 @@
roles:
- prometheus
-- name: Deploy nginx to hosts
+- name: Deploy nginx & certbot to hosts
hosts: nginx
roles:
+ - certbot
- nginx
- nginx-geoip
- nginx-ufw
diff --git a/roles/certbot/README.md b/roles/certbot/README.md
new file mode 100644
index 0000000..b9d3e36
--- /dev/null
+++ b/roles/certbot/README.md
@@ -0,0 +1,3 @@
+# Role "certbot"
+
+Installs certbot and the Cloudflare DNS plugin for certbot to provision and deploy TLS certificates for web properties.
diff --git a/roles/certbot/tasks/main.yml b/roles/certbot/tasks/main.yml
new file mode 100644
index 0000000..19d5e1e
--- /dev/null
+++ b/roles/certbot/tasks/main.yml
@@ -0,0 +1,99 @@
+---
+- name: Install certbot and certbot Cloudflare plugin
+ when: inventory_hostname == ansible_play_hosts_all[0]
+ package:
+ name:
+ - python3-certbot
+ - python3-certbot-dns-cloudflare
+ state: present
+ tags:
+ - role::certbot
+
+- name: Install rsync on certbot hosts
+ package:
+ name: rsync
+ state: present
+ tags:
+ - role::certbot
+
+- name: Generate Cloudflare credentials file on designated leader
+ when: inventory_hostname == ansible_play_hosts_all[0]
+ copy:
+ content: |
+ # This file is managed by Ansible
+ dns_cloudflare_api_token = {{ certbot_cloudflare_token }}
+ dest: /etc/letsencrypt/cloudflare.ini
+ owner: root
+ group: root
+ mode: 0400
+ tags:
+ - role::certbot
+
+- name: Generate SSH key for certificate distribution
+ when: inventory_hostname == ansible_play_hosts_all[0]
+ community.crypto.openssh_keypair:
+ path: /root/.ssh/cert_{{ item }}_key_ed25519
+ type: ed25519
+ state: present
+ comment: certificate distribution key for {{ item }}
+ with_items:
+ - "{{ ansible_play_hosts | reject('in', [inventory_hostname]) }}"
+ tags:
+ - role::certbot
+ register: generated_keys
+
+- name: Create certificate directories on replica certificate hosts
+ when: inventory_hostname != ansible_play_hosts[0]
+ file:
+ path: /etc/letsencrypt/live
+ recurse: true
+ state: directory
+ owner: root
+ group: root
+ mode: 0700
+ tags:
+ - role::certbot
+
+- name: Install certificate distribution keys to other NGINX nodes
+ when: inventory_hostname != ansible_play_hosts[0]
+ ansible.posix.authorized_key:
+ user: root
+ state: present
+ key: |
+ {{ hostvars[ansible_play_hosts_all[0]]['generated_keys']['results']
+ | selectattr('item', 'equalto', inventory_hostname)
+ | map(attribute='public_key')
+ | first }}
+ comment: "certificate distribution key"
+ key_options: 'from="{{ hostvars[ansible_play_hosts_all[0]]["wireguard_subnet"] }}",restrict,command="/usr/bin/rrsync -wo /etc/letsencrypt/live"'
+ tags:
+ - role::certbot
+
+- name: Create renewal hook to synchronize certificates
+ when: inventory_hostname == ansible_play_hosts_all[0]
+ template:
+ src: renewal-hook.sh.j2
+ dest: /etc/letsencrypt/renewal-hooks/deploy/distribute-certs
+ owner: root
+ group: root
+ mode: 0500
+ tags:
+ - role::certbot
+
+- name: Request certificates for configured domains
+ when: inventory_hostname == ansible_play_hosts_all[0]
+ command: |
+ certbot certonly
+ --agree-tos
+ --non-interactive
+ --email {{ certbot_email }}
+ --dns-cloudflare
+ --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini
+ --deploy-hook /etc/letsencrypt/renewal-hooks/deploy/distribute-certs
+ -d {{ item }} -d *.{{ item }} -d there.was.no.christmas.party.pydis.wtf
+ args:
+ creates: "/etc/letsencrypt/live/{{ item }}/fullchain.pem"
+ with_items:
+ - "{{ certbot_domains }}"
+ tags:
+ - role::certbot
diff --git a/roles/certbot/templates/renewal-hook.sh.j2 b/roles/certbot/templates/renewal-hook.sh.j2
new file mode 100644
index 0000000..7fa7252
--- /dev/null
+++ b/roles/certbot/templates/renewal-hook.sh.j2
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -ex
+
+{% for host in ansible_play_hosts if host != inventory_hostname %}
+rsync --copy-links --delete --recursive -e "ssh -i /root/.ssh/cert_{{ host }}_key_ed25519 -o StrictHostKeyChecking=accept-new" /etc/letsencrypt/live/* root@{{ hostvars[host]['wireguard_subnet'] | split("/") | first }}:/etc/letsencrypt/live
+{% endfor %}
diff --git a/roles/certbot/vars/main/main.yml b/roles/certbot/vars/main/main.yml
new file mode 100644
index 0000000..fdfc7b1
--- /dev/null
+++ b/roles/certbot/vars/main/main.yml
@@ -0,0 +1,6 @@
+---
+certbot_cloudflare_token: "{{ encrypted_cloudflare_token }}"
+certbot_email: "[email protected]"
+certbot_domains:
+ - pydis.wtf
+ - pythondiscord.com
diff --git a/roles/certbot/vars/main/vault.yml b/roles/certbot/vars/main/vault.yml
new file mode 100644
index 0000000..c669b69
--- /dev/null
+++ b/roles/certbot/vars/main/vault.yml
@@ -0,0 +1,9 @@
+$ANSIBLE_VAULT;1.1;AES256
+66336535306366333038666137306135663438346366643735383962623339636236343438633766
+6565343931306531623330373936313730353539303264390a333031363634663236636232386461
+34353239643364653464373531653236383963303137326438343239313136376537336636326162
+3537383737323732310a623836363138646434636165643130366362656661393937346534313632
+37663966613031363036623838326666636231313462363831396366363837343632646131303863
+35363032386463346164623733656463633735376161653361343231326166313466643236623762
+31343562323362353238663666303435353138643463656531373466336639316464376632623731
+32646464393438656134