diff options
| author | 2022-03-14 22:58:58 +0000 | |
|---|---|---|
| committer | 2022-03-14 23:42:37 +0000 | |
| commit | c6357463caf3c0f63e152e9ec6f5fce3d7b9d145 (patch) | |
| tree | 12f0cacd06e999645324be69be211664d334ac42 | |
| parent | Miscellaneous 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.yml | 3 | ||||
| -rw-r--r-- | roles/certbot/README.md | 3 | ||||
| -rw-r--r-- | roles/certbot/tasks/main.yml | 99 | ||||
| -rw-r--r-- | roles/certbot/templates/renewal-hook.sh.j2 | 6 | ||||
| -rw-r--r-- | roles/certbot/vars/main/main.yml | 6 | ||||
| -rw-r--r-- | roles/certbot/vars/main/vault.yml | 9 |
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 |