Replace lego with acme_sh

This commit is contained in:
Tobias Reisinger 2026-03-28 20:21:42 +01:00
parent 82f65d396f
commit 0237271b65
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
24 changed files with 176 additions and 247 deletions

View file

@ -0,0 +1,25 @@
---
acme_sh_eab_key_id: "{{ undef() }}"
acme_sh_eab_hmac_key: "{{ undef() }}"
acme_sh_acmedns_user: "{{ undef() }}"
acme_sh_acmedns_pass: "{{ undef() }}"
acme_sh_acmedns_subd: "{{ undef() }}"
acme_sh_ntfy_topic: "{{ undef() }}"
acme_sh_ntfy_token: "{{ undef() }}"
acme_sh_all_certificates: "{{ all_services | services_get_attr('certificates') | flatten }}"
acme_sh_certificates: "{{ host_services | services_get_attr('certificates') | flatten }}"
acme_sh_unwanted_certificates: "{{ acme_sh_all_certificates | difference(acme_sh_certificates) }}"
acme_sh_env:
LE_WORKING_DIR: "{{ certificates_path }}"
ACMEDNS_BASE_URL: "https://{{ acme_dns.host }}"
ACMEDNS_USERNAME: "{{ acme_sh_acmedns_user | mandatory }}"
ACMEDNS_PASSWORD: "{{ acme_sh_acmedns_pass | mandatory }}"
ACMEDNS_SUBDOMAIN: "{{ acme_sh_acmedns_subd | mandatory }}"
NTFY_URL: "https://push.serguzim.me"
NTFY_TOPIC: "{{ acme_sh_ntfy_topic | mandatory }}"
NTFY_TOKEN: "{{ acme_sh_ntfy_token | mandatory }}"

View file

@ -1,10 +1,10 @@
[Unit]
Description=Renew certificates
Description=Daily renewal of certificates
[Timer]
Persistent=true
OnCalendar=*-*-* 01:15:00
OnCalendar=daily
RandomizedDelaySec=2h
Persistent=true
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,3 @@
---
- name: Restart service {{ service_name }}
ansible.builtin.include_tasks: tasks/restart-service.yml

View file

@ -0,0 +1,69 @@
---
- name: Set common facts
ansible.builtin.import_tasks: tasks/set-default-facts.yml
- name: Import tasks to create service directory
ansible.builtin.import_tasks: tasks/steps/create-service-directory.yml
# noqa: command-instead-of-module
- name: Install acme.sh
ansible.builtin.shell:
cmd: set -o pipefail && curl https://get.acme.sh | sh -s home={{ service_path }} --nocron
creates: "{{ (service_path, 'acme.sh') | path_join }}"
environment:
BRANCH: dev
- name: Register zerossl account
ansible.builtin.command:
cmd: ./acme.sh --register-account --server zerossl --eab-kid {{ acme_sh_eab_key_id }} --eab-hmac-key {{ acme_sh_eab_hmac_key }}
chdir: "{{ service_path }}"
environment: "{{ acme_sh_env }}"
register: acme_sh_cmd_result
changed_when: not (acme_sh_cmd_result.stdout | regex_search('Already registered$', multiline=True))
- name: Set default CA
ansible.builtin.command:
cmd: ./acme.sh --set-default-ca --server zerossl
chdir: "{{ service_path }}"
environment: "{{ acme_sh_env }}"
changed_when: false
- name: Set notifications
ansible.builtin.command:
cmd: ./acme.sh --set-notify --notify-hook ntfy
chdir: "{{ service_path }}"
environment: "{{ acme_sh_env }}"
changed_when: false
- name: Remove unwanted certificates
ansible.builtin.command:
cmd: ./acme.sh --remove -d {{ item.domain }}
chdir: "{{ service_path }}"
environment: "{{ acme_sh_env }}"
loop: "{{ acme_sh_unwanted_certificates }}"
register: acme_sh_cmd_result
changed_when: acme_sh_cmd_result.rc == 0
failed_when: false
- name: Get certificates
ansible.builtin.command:
cmd: ./acme.sh --issue --dns dns_acmedns -d {{ item.domain }}
chdir: "{{ service_path }}"
environment: "{{ acme_sh_env }}"
loop: "{{ acme_sh_certificates }}"
register: acme_sh_cmd_result
changed_when: true # TODO
failed_when: not acme_sh_cmd_result.rc in [0, 2]
- name: Deploy certificates
ansible.builtin.command:
cmd: ./acme.sh --deploy --deploy-hook {{ item.hook }} -d {{ item.domain }}
chdir: "{{ service_path }}"
environment: "{{ acme_sh_env | combine(item.parameters) }}"
loop: "{{ acme_sh_certificates }}"
register: acme_sh_cmd_result
changed_when: true # TODO
become: true
- name: Import systemd tasks
ansible.builtin.import_tasks: systemd.yml

View file

@ -0,0 +1,22 @@
---
- name: Copy the system service
ansible.builtin.template:
src: acme_sh.service.j2
dest: /etc/systemd/system/acme_sh.service
mode: "0644"
become: true
- name: Copy the system timer
ansible.builtin.copy:
src: acme_sh.timer
dest: /etc/systemd/system/acme_sh.timer
mode: "0644"
become: true
- name: Enable the system timer
ansible.builtin.systemd_service:
name: acme_sh.timer
state: started
enabled: true
daemon_reload: true
become: true

View file

@ -0,0 +1,9 @@
[Unit]
Description=Renew certificates using acme.sh
After=network-online.target nss-lookup.target
[Service]
Type=oneshot
SyslogIdentifier=acme.sh
Environment=LE_WORKING_DIR="{{ acme_sh_env.LE_WORKING_DIR }}"
ExecStart={{ (service_path, 'acme.sh') | path_join }} --cron

View file

@ -7,3 +7,11 @@
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
become: true
- name: Create _certificates directory
ansible.builtin.file:
path: "{{ certificates_path }}"
state: directory
mode: "0755"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"

View file

@ -50,6 +50,8 @@ authentik_compose:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./certs:/certs
labels:
sh.acme.autoload.domain: auth.serguzim.me
env_file:
- .env
depends_on:

View file

@ -1,33 +0,0 @@
---
lego_host_certificates: "{{ host_services | services_get_attr('certificates') | flatten }}"
lego_acmedns_registered: "{{ undef() }}"
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
CERTIFICATES_PATH: "{{ certificates_path }}"
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:

View file

@ -1,6 +0,0 @@
#!/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

View file

@ -1,12 +0,0 @@
#!/usr/bin/env sh
domain="auth.serguzim.me"
_install() {
install --owner=root --group=root --mode=600 \
"$CERTIFICATES_PATH/$domain.$1" \
"/opt/services/authentik/certs/$domain.$2"
}
_install crt pem
_install key key

View file

@ -1,17 +0,0 @@
#!/usr/bin/env sh
domain="db.serguzim.me"
_install() {
install --owner=postgres --group=postgres --mode=600 \
"$CERTIFICATES_PATH/$domain.$1" \
"/etc/postgresql/cert.$1"
}
_install crt
_install key
#sudo -u postgres pg_ctl -D /var/lib/postgres/data/ reload
systemctl reload postgresql
# vim: ft=sh

View file

@ -1,26 +0,0 @@
#!/usr/bin/env sh
set -a
. ./.env
set +a
domain="$1"
action="run"
exisiting_domains=$(docker compose run --rm app list -n)
if echo "$exisiting_domains" | grep -q "$domain";
then
action="renew"
fi
docker compose run --rm app \
--domains "$domain" \
"$action" \
"--$action-hook" "/config/hook.sh"
if [ "$?" = "33" ] && [ -x "./hooks/$domain" ];
then
echo "Running hook for $domain"
"./hooks/$domain"
fi

View file

@ -1,18 +0,0 @@
class FilterModule(object):
def filters(self):
return {
'lego_from_acmedns': self.from_acmedns,
}
def from_acmedns(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

View file

@ -1,19 +0,0 @@
---
- name: Set config path
ansible.builtin.set_fact:
lego_config_path: "{{ (service_path, 'config') | path_join }}"
- name: Create config directory
ansible.builtin.file:
path: "{{ lego_config_path }}"
state: directory
mode: "0755"
- name: Create the acme-dns-accounts
ansible.builtin.copy:
dest: "{{ (lego_config_path, 'acme-dns-accounts.json') | path_join }}"
content: '{{ lego_acmedns_registered | lego_from_acmedns | to_json }}'
mode: "0644"
- name: Copy the hook script
ansible.builtin.copy:
src: "hook.sh"
dest: "{{ (lego_config_path, 'hook.sh') | path_join }}"
mode: "0755"

View file

@ -1,14 +0,0 @@
---
- name: Set hooks path
ansible.builtin.set_fact:
lego_hooks_path: "{{ (service_path, 'hooks') | path_join }}"
- name: Create hooks directory
ansible.builtin.file:
path: "{{ lego_hooks_path }}"
state: directory
mode: "0755"
- name: Copy the additional hooks
ansible.builtin.copy:
src: hooks/
dest: "{{ lego_hooks_path }}"
mode: "0755"

View file

@ -1,42 +0,0 @@
---
- name: Set common facts
ansible.builtin.import_tasks: tasks/set-default-facts.yml
- name: Deploy {{ service_name }}
vars:
env: "{{ lego_env }}"
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 hooks
ansible.builtin.import_tasks: hooks.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 .env file
ansible.builtin.import_tasks: tasks/steps/template-service-env.yml
- name: Run certificate-script for domains
ansible.builtin.command:
cmd: "./lego.sh {{ item }}"
chdir: "{{ service_path }}"
become: true
loop: "{{ lego_host_certificates }}"
register: lego_cmd_result
changed_when: lego_cmd_result.stderr | regex_search('Server responded with a certificate.')

View file

@ -1,41 +0,0 @@
---
- 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: Get all lego timers
ansible.builtin.shell:
executable: /usr/bin/bash
cmd: "set -o pipefail && systemctl list-timers 'lego@*' --all --output=json | jq -r '.[].unit'"
register: lego_systemd_timers_result
changed_when: false
- name: Generate systemd timer names
ansible.builtin.set_fact:
lego_systemd_timers: "{{ lego_host_certificates | utils_list_prefix_suffix('lego@', '.timer') }}"
- name: Disable unused system timers
ansible.builtin.systemd_service:
name: "{{ item }}"
state: stopped
enabled: false
loop: "{{ lego_systemd_timers_result.stdout_lines | difference(lego_systemd_timers) }}"
become: true
- name: Enable the system timers
ansible.builtin.systemd_service:
name: "{{ item }}"
state: started
enabled: true
daemon_reload: true
loop: "{{ lego_systemd_timers }}"
become: true

View file

@ -1,4 +0,0 @@
[Service]
Type=oneshot
ExecStart={{ service_path }}/lego.sh %i
WorkingDirectory={{ service_path }}