diff --git a/filter_plugins/acmedns_to_lego.py b/filter_plugins/acmedns_to_lego.py new file mode 100644 index 0000000..76a24cd --- /dev/null +++ b/filter_plugins/acmedns_to_lego.py @@ -0,0 +1,18 @@ +class FilterModule(object): + def filters(self): + return { + 'acmedns_to_lego': self.acmedns_to_lego, + } + + def acmedns_to_lego(self, acmedns_registered): + result = {} + for (key, value) in acmedns_registered.items(): + result[key] = { + "fulldomain": value["subd"] + "." + value["host"], + "subdomain": value["subd"], + "username": value["user"], + "password": value["pass"], + "server_url": "https://" + value["host"] + } + + return result diff --git a/node002.yml b/node002.yml index 6d4ddc3..476c5c3 100644 --- a/node002.yml +++ b/node002.yml @@ -6,6 +6,8 @@ tags: [always] - role: backup tags: [backup] + - role: lego + tags: [lego, certificates] - role: caddy tags: [caddy, reverse-proxy, webserver] vars: diff --git a/roles/lego/files/hook.sh b/roles/lego/files/hook.sh new file mode 100644 index 0000000..b060634 --- /dev/null +++ b/roles/lego/files/hook.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +cp -f "$LEGO_CERT_PATH" /certificates +cp -f "$LEGO_CERT_KEY_PATH" /certificates + +exit 33 # special exit code to signal that the certificate has been updated diff --git a/roles/lego/files/lego.sh b/roles/lego/files/lego.sh new file mode 100755 index 0000000..f6a4a04 --- /dev/null +++ b/roles/lego/files/lego.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +domain="$1" +action="${2:-renew}" + +docker compose run --rm app \ + --domains "$domain" \ + "$action" \ + "--$action-hook" "/config/hook.sh" + +if [ "$?" = "33" ] && [ -x "./lego.d/$domain" ]; +then + echo "Running hook for $domain" + "./lego.d/$domain" +fi diff --git a/roles/lego/files/lego@.timer b/roles/lego/files/lego@.timer new file mode 100644 index 0000000..284347f --- /dev/null +++ b/roles/lego/files/lego@.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Renew certificates + +[Timer] +Persistent=true +OnCalendar=*-*-* 01:15:00 +RandomizedDelaySec=2h + +[Install] +WantedBy=timers.target diff --git a/roles/lego/files/node002/db.serguzim.me b/roles/lego/files/node002/db.serguzim.me new file mode 100755 index 0000000..09602b9 --- /dev/null +++ b/roles/lego/files/node002/db.serguzim.me @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +domain="db.serguzim.me" + +docker compose run --rm app "$1" "$domain" + +_install() { + install --owner=postgres --group=postgres --mode=600 \ + "/opt/services/_certificates/$domain.$1" \ + "/var/lib/postgresql/server.$1" +} + +_install crt +_install key + +sudo -u postgres pg_ctl -D /var/lib/postgres/data/ reload diff --git a/roles/lego/files/node002/registry.serguzim.me b/roles/lego/files/node002/registry.serguzim.me new file mode 100755 index 0000000..09e444c --- /dev/null +++ b/roles/lego/files/node002/registry.serguzim.me @@ -0,0 +1,17 @@ +#!/usr/bin/env sh + +domain="registry.serguzim.me" + +docker compose run --rm app "$1" "$domain" + +_install() { + install --owner=root --group=root --mode=600 \ + "/opt/services/_certificates/$domain.$1" \ + "/opt/services/harbor/server.$1" +} + +_install crt +_install key + +export HARBOR_BUNDLE_DIR=/opt/services/harbor +$HARBOR_BUNDLE_DIR/data/install.sh diff --git a/roles/lego/tasks/config.yml b/roles/lego/tasks/config.yml new file mode 100644 index 0000000..266efcb --- /dev/null +++ b/roles/lego/tasks/config.yml @@ -0,0 +1,19 @@ +--- +- name: Set config path + ansible.builtin.set_fact: + config_path: "{{ (service_path, 'config') | path_join }}" +- name: Create config directory + ansible.builtin.file: + path: "{{ config_path }}" + state: directory + mode: "0755" +- name: Copy the acme-dns-accounts + ansible.builtin.template: + src: "json.j2" + dest: "{{ (config_path, 'acme-dns-accounts.json') | path_join }}" + mode: "0644" +- name: Copy the hook script + ansible.builtin.copy: + src: "hook.sh" + dest: "{{ (config_path, 'hook.sh') | path_join }}" + mode: "0755" diff --git a/roles/lego/tasks/lego.d.yml b/roles/lego/tasks/lego.d.yml new file mode 100644 index 0000000..04acb4b --- /dev/null +++ b/roles/lego/tasks/lego.d.yml @@ -0,0 +1,16 @@ +--- +- name: Set lego.d path + ansible.builtin.set_fact: + lego_d_path: "{{ (service_path, 'lego.d') | path_join }}" +- name: Create lego.d directory + ansible.builtin.file: + path: "{{ lego_d_path }}" + state: directory + mode: "0755" +- name: Copy the additional lego scripts + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ lego_d_path }}" + mode: "0755" + with_fileglob: + - "{{ ansible_facts.hostname }}/*" diff --git a/roles/lego/tasks/main.yml b/roles/lego/tasks/main.yml new file mode 100644 index 0000000..3dc6de1 --- /dev/null +++ b/roles/lego/tasks/main.yml @@ -0,0 +1,35 @@ +--- +- name: Set common facts + ansible.builtin.import_tasks: tasks/set-default-facts.yml + +- name: Deploy {{ svc.name }} + vars: + svc: "{{ lego_svc }}" + env: "{{ lego_env }}" + json: "{{ vault_acmedns_registered | acmedns_to_lego }}" + compose: "{{ lego_compose }}" + block: + - name: Import prepare tasks for common service + ansible.builtin.import_tasks: tasks/prepare-common-service.yml + + - name: Create _certificates directory + ansible.builtin.file: + path: "{{ certificates_path }}" + state: directory + mode: "0755" + + - name: Import tasks specific to the config directory + ansible.builtin.import_tasks: config.yml + - name: Import tasks specific to lego.d + ansible.builtin.import_tasks: lego.d.yml + - name: Import tasks specific to systemd + ansible.builtin.import_tasks: systemd.yml + + - name: Copy the run script + ansible.builtin.copy: + src: "lego.sh" + dest: "{{ (service_path, 'lego.sh') | path_join }}" + mode: "0755" + + - name: Import tasks create a service.env file + ansible.builtin.import_tasks: tasks/steps/template-service-env.yml diff --git a/roles/lego/tasks/systemd.yml b/roles/lego/tasks/systemd.yml new file mode 100644 index 0000000..21e99bf --- /dev/null +++ b/roles/lego/tasks/systemd.yml @@ -0,0 +1,23 @@ +--- +- name: Copy the system service + ansible.builtin.template: + src: lego@.service.j2 + dest: /etc/systemd/system/lego@.service + mode: "0644" + become: true +- name: Copy the system timer + ansible.builtin.copy: + src: lego@.timer + dest: /etc/systemd/system/lego@.timer + mode: "0644" + become: true +- name: Enable the system timer for {{ item }} + ansible.builtin.systemd_service: + name: lego@{{ item }}.timer + state: started + enabled: true + daemon_reload: true + loop: + - db.serguzim.me + - registry.serguzim.me + become: true diff --git a/roles/lego/templates/lego@.service.j2 b/roles/lego/templates/lego@.service.j2 new file mode 100644 index 0000000..4b310f2 --- /dev/null +++ b/roles/lego/templates/lego@.service.j2 @@ -0,0 +1,4 @@ +[Service] +Type=oneshot +ExecStart={{ service_path }}/lego.sh %i +WorkingDirectory={{ service_path }} diff --git a/roles/lego/vars/main.yml b/roles/lego/vars/main.yml new file mode 100644 index 0000000..460fb79 --- /dev/null +++ b/roles/lego/vars/main.yml @@ -0,0 +1,31 @@ +--- +lego_svc: + name: lego + +lego_env: + ACME_DNS_API_BASE: https://{{ acme_dns.host }} + ACME_DNS_STORAGE_PATH: /config/acme-dns-accounts.json + + LEGO_EMAIL: "{{ admin_email }}" + LEGO_PATH: /data + +lego_compose: + watchtower: false + network: false + image: goacme/lego + volumes: + - ./config:/config:ro + - "{{ certificates_path }}:/certificates" + - data:/data + file: + services: + app: + restart: never + network_mode: "host" + entrypoint: + - /lego + - --accept-tos + - --email={{ admin_email }} + - --dns=acme-dns + volumes: + data: