Replace lego with acme_sh
This commit is contained in:
parent
82f65d396f
commit
0237271b65
24 changed files with 176 additions and 247 deletions
1
.gitleaksignore
Normal file
1
.gitleaksignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
dnsconfig.js:generic-api-key:63
|
||||
|
|
@ -60,8 +60,8 @@ D("serguzim.me", REG_OVH, DnsProvider(DSP_OVH),
|
|||
|
||||
TLSA("_25._tcp.mail", 3, 1, 1, "70143145ab67680a3b61fe2d0eb63319625fa086f845cce59afdbf1dad79e561"),
|
||||
|
||||
acme_challenge("auth", "18a42983-3d19-4c17-8213-fc275a8be721"),
|
||||
acme_challenge("db", "ca2c86c0-ff3d-458a-89e0-11bcfd2543e4"),
|
||||
acme_challenge("auth", "92924f7c-0859-4941-9e3d-2ecedfb21c1b"),
|
||||
acme_challenge("db", "92924f7c-0859-4941-9e3d-2ecedfb21c1b"),
|
||||
acme_challenge("homeassistant", "596c4bd6-f111-43fd-a1ee-3a4e4cae8988"),
|
||||
acme_challenge("paas", "92924f7c-0859-4941-9e3d-2ecedfb21c1b"),
|
||||
acme_challenge("", "92924f7c-0859-4941-9e3d-2ecedfb21c1b"),
|
||||
|
|
|
|||
25
playbooks/roles/acme_sh/defaults/main.yml
Normal file
25
playbooks/roles/acme_sh/defaults/main.yml
Normal 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 }}"
|
||||
|
|
@ -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
|
||||
3
playbooks/roles/acme_sh/handlers/main.yml
Normal file
3
playbooks/roles/acme_sh/handlers/main.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
- name: Restart service {{ service_name }}
|
||||
ansible.builtin.include_tasks: tasks/restart-service.yml
|
||||
69
playbooks/roles/acme_sh/tasks/main.yml
Normal file
69
playbooks/roles/acme_sh/tasks/main.yml
Normal 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
|
||||
22
playbooks/roles/acme_sh/tasks/systemd.yml
Normal file
22
playbooks/roles/acme_sh/tasks/systemd.yml
Normal 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
|
||||
9
playbooks/roles/acme_sh/templates/acme_sh.service.j2
Normal file
9
playbooks/roles/acme_sh/templates/acme_sh.service.j2
Normal 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
|
||||
|
|
@ -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 }}"
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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.')
|
||||
|
|
@ -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
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart={{ service_path }}/lego.sh %i
|
||||
WorkingDirectory={{ service_path }}
|
||||
|
|
@ -8,6 +8,7 @@ import hcl2
|
|||
|
||||
icon_overrides = {
|
||||
"acme_dns": "lets-encrypt",
|
||||
"acme_sh": "lets-encrypt",
|
||||
"backup": "restic",
|
||||
"calibre_web": "calibre-web",
|
||||
"deploy": "adnanh-webhook",
|
||||
|
|
@ -18,13 +19,13 @@ icon_overrides = {
|
|||
"healthcheck": "healthchecks",
|
||||
"immich_worker": "immich",
|
||||
"jitsi": "jitsi-meet",
|
||||
"lego": "lets-encrypt",
|
||||
"lgtm_stack": "grafana",
|
||||
"mailcowdockerized": "mailcow",
|
||||
"minecraft_3": "minecraft",
|
||||
"node_exporter": "prometheus",
|
||||
"paperless": "paperless-ngx",
|
||||
"phpvms": None,
|
||||
"phpvms_test": None,
|
||||
"reitanlage_oranienburg": "grav",
|
||||
"tandoor": "tandoor-recipes",
|
||||
"tinytinyrss": "tiny-tiny-rss",
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@ services = {
|
|||
database = true
|
||||
},
|
||||
|
||||
"acme_sh" = {
|
||||
host = "*"
|
||||
auth = false
|
||||
database = false
|
||||
},
|
||||
|
||||
"authentik" = {
|
||||
host = "node001"
|
||||
dns = [{
|
||||
|
|
@ -43,7 +49,16 @@ services = {
|
|||
url = "/-/health/live/"
|
||||
group = "3-services"
|
||||
}
|
||||
certificates = ["auth.serguzim.me"]
|
||||
certificates = [{
|
||||
domain = "auth.serguzim.me"
|
||||
hook = "docker"
|
||||
parameters = {
|
||||
DEPLOY_DOCKER_CONTAINER_LABEL = "sh.acme.autoload.domain=auth.serguzim.me"
|
||||
DEPLOY_DOCKER_CONTAINER_KEY_FILE = "/certs/auth.serguzim.me.key"
|
||||
DEPLOY_DOCKER_CONTAINER_CERT_FILE = "/certs/auth.serguzim.me.pem"
|
||||
DEPLOY_DOCKER_CONTAINER_RELOAD_CMD = "ak import_certificate --certificate /certs/auth.serguzim.me.pem --private-key /certs/auth.serguzim.me.key --name auth.serguzim.me"
|
||||
}
|
||||
}]
|
||||
auth = false
|
||||
database = true
|
||||
mail = "auth@serguzim.me"
|
||||
|
|
@ -409,12 +424,6 @@ services = {
|
|||
database = false
|
||||
}
|
||||
|
||||
"lego" = {
|
||||
host = "*"
|
||||
auth = false
|
||||
database = false
|
||||
},
|
||||
|
||||
mailcowdockerized = {
|
||||
host = "node003"
|
||||
dns = [{
|
||||
|
|
@ -670,7 +679,15 @@ services = {
|
|||
"[CONNECTED] == true"
|
||||
]
|
||||
}
|
||||
certificates = ["db.serguzim.me"]
|
||||
certificates = [{
|
||||
domain = "db.serguzim.me"
|
||||
hook = "localcopy"
|
||||
parameters = {
|
||||
DEPLOY_LOCALCOPY_CERTKEY = "/etc/postgresql/cert.key"
|
||||
DEPLOY_LOCALCOPY_FULLCHAIN = "/etc/postgresql/cert.crt"
|
||||
DEPLOY_LOCALCOPY_RELOADCMD = "systemctl reload postgresql"
|
||||
}
|
||||
}]
|
||||
auth = false
|
||||
database = false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -161,7 +161,11 @@ variable "services" {
|
|||
protocol = string
|
||||
type = string
|
||||
})))
|
||||
certificates = optional(list(string))
|
||||
certificates = optional(list(object({
|
||||
domain = string
|
||||
hook = string
|
||||
parameters = map(string)
|
||||
})))
|
||||
auth = bool
|
||||
auth_cert = optional(string)
|
||||
auth_redirects = optional(list(string))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue