Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lego): allow running multiple instances with systemd templates #179

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions roles/lego/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
---
lego_instance: ~
lego_base_path: "/opt/lego"
lego_certificate_store: "{{ lego_base_path }}/certificates"
lego_instance_base_path: >-
/opt/lego{{ ('-' ~ lego_instance) if lego_instance else ''}}
lego_certificate_store: >-
{{ lego_instance_base_path }}/certificates
lego_certificate_store_user: "{{ lego_user_res.uid | default(lego_user) }}"
lego_certificate_store_group: "{{ lego_user_res.group | default(lego_user) }}"
lego_certificate_store_mode: "0750"
Expand All @@ -9,8 +13,10 @@ lego_version: "4.12.3"
lego_system_type: "linux"
lego_system_arch: "amd64"
lego_executable: "{{ lego_base_path }}/lego"
lego_account_base_path: "{{ lego_base_path }}/accounts"
lego_account_base_path: >-
{{ lego_instance_base_path }}/accounts
lego_cap_net_bind_service: true
lego_default_systemd_instance: "lego"

lego_enable_metrics_textfile: false

Expand Down Expand Up @@ -80,7 +86,7 @@ lego_configuration_defaults:
server: "{{ lego_letsencrypt_servers[lego_letsencrypt_environment] }}"
accept-tos: true
email: "{{ lego_certificate.email }}"
path: "{{ lego_base_path }}"
path: "{{ lego_instance_base_path }}"
key-type: "{{ lego_configuration_default_key_type }}"
run: {}
renew:
Expand All @@ -90,7 +96,6 @@ lego_configuration_defaults:
lego_install_dependencies: false
lego_dependencies:
Debian:
"11":
- "python3-cryptography"
all:
- "acl"
- "python3-cryptography"
2 changes: 2 additions & 0 deletions roles/lego/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
---
- name: "Run lego"
listen: lego_run
become: true
become_user: "{{ lego_user_res.name }}"
environment: "{{ lego_configuration_merged.environment }}"
command: "{{ lego_command_playbook }}"
register: "lego_run"

- name: "Reload systemd"
listen: systemd_reload
systemd:
daemon_reload: true
45 changes: 29 additions & 16 deletions roles/lego/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@
tags: ["prepare", "prepare-lego"]

- name: "Ensure base directory for lego is created"
file:
path: "{{ lego_base_path }}"
ansible.builtin.file:
path: "{{ item }}"
state: "directory"
owner: "{{ lego_certificate_store_user }}"
group: "{{ lego_certificate_store_group }}"
mode: "0755"
loop:
- "{{ lego_base_path }}"
- "{{ lego_instance_base_path }}"
tags: ["prepare", "prepare-lego"]

- name: "Ensure certificate directory exists and has the configured permissions"
file:
ansible.builtin.file:
path: "{{ lego_certificate_store }}"
state: "directory"
owner: "{{ lego_certificate_store_user }}"
Expand Down Expand Up @@ -136,7 +139,8 @@
path: "{{ lego_certificate_store }}/{{ lego_certificate.domains[0] }}.crt"
register: "lego_certificate_stat"
changed_when: "not lego_certificate_stat.stat.exists"
notify: ["Run lego"]
notify:
- "lego_run"
tags: ["deploy", "deploy-lego"]

- name: "Fetch certificate info"
Expand All @@ -163,7 +167,8 @@
}}
when: "lego_certificate_stat.stat.exists"
changed_when: "not lego_certificate_sans_equal"
notify: ["Run lego"]
notify:
- "lego_run"
tags: ["deploy", "deploy-lego"]

- name: "Compare pubkey type, notify handler if it differs"
Expand All @@ -177,41 +182,49 @@
}}
when: "lego_certificate_stat.stat.exists"
changed_when: "lego_certificate_pubkey_type_differs"
notify: ["Run lego"]
notify:
- "lego_run"
tags: ["deploy", "deploy-lego"]

- name: "Ensure systemd unit file for lego is templated"
template:
ansible.builtin.template:
src: "lego.service.j2"
dest: "{{ lego_systemd_path }}/lego.service"
dest: "{{ lego_systemd_path }}/lego@.service"
owner: "root"
group: "root"
mode: "0755"
notify: ["Reload systemd"]
notify:
- "systemd_reload"
tags: ["deploy", "deploy-lego"]

- name: "Ensure systemd timer for lego is templated"
template:
ansible.builtin.template:
src: "lego.timer.j2"
dest: "{{ lego_systemd_path }}/lego.timer"
dest: "{{ lego_systemd_path }}/lego{{ ('-' ~ lego_instance) if lego_instance else '' }}.timer"
owner: "root"
group: "root"
mode: "0755"
notify: ["Reload systemd"]
notify:
- "systemd_reload"
tags: ["deploy", "deploy-lego"]

- name: "Ensure env file per instance is templated"
ansible.builtin.template:
src: "lego.env.j2"
dest: "{{ lego_base_path }}/{{ lego_instance | default(lego_default_systemd_instance) }}.conf"

- name: "Flush handlers to ensure systemd has loaded the unit files"
meta: "flush_handlers"

- name: "Enable lego.service"
systemd:
name: "lego.service"
ansible.builtin.systemd:
name: "lego{{ ('@' ~ lego_instance) if lego_instance else '' }}.service"
enabled: true
tags: ["deploy", "deploy-lego"]

- name: "Enable lego.timer"
systemd:
name: "lego.timer"
ansible.builtin.systemd:
name: "lego{{ ('-' ~ lego_instance) if lego_instance else '' }}.timer"
state: "started"
enabled: true
tags: ["deploy", "deploy-lego"]
18 changes: 18 additions & 0 deletions roles/lego/templates/lego.env.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
LEGO_USER={{ lego_user_res.name }}
LEGO_GROUP={{ lego_user_res.group }}
LEGO_CERT_STORE_OWNER={{ lego_certificate_store_user }}
LEGO_CERT_STORE_GROUP={{ lego_certificate_store_group }}
LEGO_CERT_STORE_PATH={{ lego_certificate_store }}
LEGO_CERT_STORE_MODE={{ lego_certificate_store_mode }}
LEGO_CWD={{ lego_instance_base_path }}
LEGO_COMMAND={{ lego_command_systemd }}
{% if lego_enable_metrics_textfile %}
LEGO_ENABLE_METRICS=true
{% endif %}
{% if lego_post_renewal_script is defined %}
LEGO_POST_RENEW_HOOK_PATH={{ lego_post_renewal_script }}
{% endif %}
{% for envvar in lego_configuration_merged.environment %}
{{ envvar }}={{ lego_configuration_merged.environment[envvar] }}
{% endfor %}

26 changes: 9 additions & 17 deletions roles/lego/templates/lego.service.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,16 @@ Description=lego - Let's Encrypt client written in Go
StandardOutput=journal
StandardError=journal
SyslogIdentifier=lego
{% for envvar in lego_configuration_merged.environment %}
Environment={{ envvar }}={{ lego_configuration_merged.environment[envvar] }}
{% endfor %}
EnvironmentFile={{ lego_base_path }}/%i.conf
Type=oneshot
Group={{ lego_user_res.group }}
User={{ lego_user_res.name }}
WorkingDirectory={{ lego_base_path }}
ExecStartPre=+-chown {{ lego_certificate_store_user }}:{{ lego_certificate_store_group }} {{ lego_certificate_store }}
ExecStartPre=+-chmod {{ lego_certificate_store_mode }} {{ lego_certificate_store }}
ExecStart={{ lego_command_systemd }}
ExecStartPost=+-/bin/sh -c 'chown {{ lego_certificate_store_user }}:{{ lego_certificate_store_group }} {{ lego_certificate_store }}/*'
ExecStartPost=+-/bin/sh -c 'chmod 0640 {{ lego_certificate_store }}/*'
{% if lego_enable_metrics_textfile %}
ExecStartPost=+-/usr/bin/python3 {{ lego_base_path }}/metrics-textfile.py
{% endif %}
{% if lego_post_renewal_script is defined %}
ExecStartPost=+-{{ lego_post_renewal_script }}
{% endif %}
ExecStartPre=+-/usr/bin/bash -c 'chown $(getent passwd | awk -F: \'$$3 == ${LEGO_CERT_STORE_OWNER} {print $$1}\'):$(getent group | grep ${LEGO_CERT_STORE_GROUP} | cut -d ':' -f1) ${LEGO_CERT_STORE_PATH}'
ExecStartPre=+-/usr/bin/bash -c "chmod ${LEGO_CERT_STORE_MODE} ${LEGO_CERT_STORE_PATH}"
ExecStart=/usr/bin/bash -c 'cd $LEGO_CWD && sudo -u ${LEGO_USER} -g $(getent group | grep ${LEGO_GROUP} | cut -d ':' -f1) ${LEGO_COMMAND}'
ExecStartPost=+-/bin/sh -c 'chown ${LEGO_CERT_STORE_OWNER}:${LEGO_CERT_STORE_GROUP} ${LEGO_CERT_STORE_PATH}/*'
ExecStartPost=+-/bin/sh -c 'chmod 0640 ${LEGO_CERT_STORE_PATH}/*'
ExecStartPost=+-/usr/bin/bash -c 'test -n "${LEGO_ENABLE_METRICS-}" && /usr/bin/python3 ${LEGO_CWD}/metrics-textfile.py'
ExecStartPost=+-${LEGO_POST_RENEW_HOOK_PATH}

[Install]
WantedBy=multi-user.target
DefaultInstance={{ lego_default_systemd_instance }}
2 changes: 1 addition & 1 deletion roles/lego/templates/lego.timer.j2
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ RandomizedDelaySec={{ lego_timer_random_delay }}
Persistent={{ lego_timer_persistent | string }}
{% endif %}

Unit=lego.service
Unit=lego{{ ('@' ~ lego_instance) if lego_instance else ''}}.service

[Install]
WantedBy=timers.target