prole/infrastructure/roles/acme/tasks/main.yml
chrisfu 372496eea2 fix(acme): use shell inline env vars for issue; bypass sudo env_reset
Ansible command module + become does not reliably pass environment:
vars through sudo env_reset. Use ansible.builtin.shell with POSIX
inline assignment (VAR=val cmd) so credentials are set inside the
sudo-spawned shell subprocess, never touching the sudo env barrier.
account.conf writing retained for cron renewal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 15:14:12 -04:00

101 lines
3.1 KiB
YAML

---
- name: Ensure /etc/ssl/certs/prole exists
ansible.builtin.file:
path: /etc/ssl/certs/prole
state: directory
owner: root
group: root
mode: "0750"
- name: Ensure git is installed (required for acme.sh clone)
ansible.builtin.apt:
name: git
state: present
- name: Check if acme.sh is already installed
ansible.builtin.stat:
path: "{{ acme_install_dir }}/acme.sh"
register: acme_sh_stat
- name: Clone acme.sh
ansible.builtin.git:
repo: https://github.com/acmesh-official/acme.sh.git
dest: /tmp/acme.sh-src
depth: 1
when: not acme_sh_stat.stat.exists
- name: Install acme.sh
ansible.builtin.command: >-
./acme.sh --install
--home {{ acme_install_dir }}
--accountemail {{ acme_email }}
--nocron
args:
chdir: /tmp/acme.sh-src
creates: "{{ acme_install_dir }}/acme.sh"
when: not acme_sh_stat.stat.exists
- name: Set default CA to Let's Encrypt
ansible.builtin.command: "{{ acme_install_dir }}/acme.sh --set-default-ca --server letsencrypt"
changed_when: false
- name: Check existing cert status
ansible.builtin.command: "{{ acme_install_dir }}/acme.sh --list"
register: acme_list
changed_when: false
- name: Store name.com credentials in acme.sh account.conf
ansible.builtin.lineinfile:
path: "{{ acme_install_dir }}/account.conf"
regexp: "^{{ item.key }}="
line: "{{ item.key }}='{{ item.value }}'"
create: true
owner: root
group: root
mode: "0600"
loop:
- { key: SAVED_NAMECOM_Username, value: "{{ acme_namecom_username }}" }
- { key: SAVED_NAMECOM_Token, value: "{{ acme_namecom_token }}" }
no_log: true
- name: Issue certs via DNS-01 (name.com) — skip if already issued
ansible.builtin.shell: |
NAMECOM_Username="{{ acme_namecom_username }}" \
NAMECOM_Token="{{ acme_namecom_token }}" \
{{ acme_install_dir }}/acme.sh --issue \
--dns dns_namecom \
-d {{ item.domain }} \
--home {{ acme_install_dir }} \
--server letsencrypt
loop: "{{ acme_certs }}"
register: acme_issue
changed_when: "'Cert success' in acme_issue.stdout"
# rc=2 means cert already exists and is not due for renewal — treat as ok
failed_when: acme_issue.rc not in [0, 2]
when: item.domain not in acme_list.stdout
no_log: true
- name: Install cert files to target paths
ansible.builtin.command: >-
{{ acme_install_dir }}/acme.sh --install-cert
-d {{ item.domain }}
--home {{ acme_install_dir }}
--fullchain-file {{ (item.install | selectattr('src', 'equalto', 'fullchain.cer') | first).dest }}
--key-file {{ (item.install | selectattr('src', 'match', '.*\\.key$') | first).dest }}
loop: "{{ acme_certs }}"
notify: reload prole ssl consumers
- name: Fix permissions on installed cert files
ansible.builtin.file:
path: "{{ file_item.dest }}"
owner: root
group: root
mode: "{{ '0600' if file_item.dest.endswith('.key') else '0644' }}"
loop: "{{ acme_certs | map(attribute='install') | flatten }}"
loop_control:
loop_var: file_item
- name: Install acme.sh renewal cron
ansible.builtin.command: "{{ acme_install_dir }}/acme.sh --install-cronjob"
changed_when: false