| 1 | ---
|
| 2 | # roles/uacme/tasks/main.yml
|
| 3 | # Installs uacme and manages certificates as an unprivileged `acme` user
|
| 4 | #
|
| 5 | # NOTE: uacme account registration is INTERACTIVE (it asks for an email address
|
| 6 | # and to accept the terms). It is done once, by hand:
|
| 7 | #
|
| 8 | # doas -u acme uacme new <email>
|
| 9 | #
|
| 10 | # After that, `acme-update-certs <domain>` (used by the nginx role and the cron)
|
| 11 | # works non-interactively
|
| 12 |
|
| 13 | - name: Install uacme and openssl
|
| 14 | community.general.apk:
|
| 15 | name:
|
| 16 | - uacme
|
| 17 | - openssl
|
| 18 | state: present
|
| 19 | update_cache: true
|
| 20 | tags: [packages, prepare]
|
| 21 |
|
| 22 | - name: Create the acme group
|
| 23 | ansible.builtin.group:
|
| 24 | name: "{{ acme_group }}"
|
| 25 | state: present
|
| 26 | tags: [prepare]
|
| 27 |
|
| 28 | - name: Create the acme user
|
| 29 | ansible.builtin.user:
|
| 30 | name: "{{ acme_user }}"
|
| 31 | home: /var/lib/acme
|
| 32 | system: true
|
| 33 | shell: /sbin/nologin
|
| 34 | groups: "{{ acme_group }},{{ acme_web_group }}"
|
| 35 | append: true
|
| 36 | state: present
|
| 37 | tags: [prepare]
|
| 38 |
|
| 39 | - name: Create the uacme certificates directory
|
| 40 | ansible.builtin.file:
|
| 41 | path: "{{ acme_cert_dir }}"
|
| 42 | state: directory
|
| 43 | owner: "{{ acme_user }}"
|
| 44 | group: "{{ acme_group }}"
|
| 45 | mode: "0750"
|
| 46 | tags: [prepare]
|
| 47 |
|
| 48 | - name: Create the uacme private directory
|
| 49 | ansible.builtin.file:
|
| 50 | path: "{{ acme_cert_dir }}/private"
|
| 51 | state: directory
|
| 52 | owner: "{{ acme_user }}"
|
| 53 | group: "{{ acme_group }}"
|
| 54 | mode: "0750"
|
| 55 | tags: [prepare]
|
| 56 |
|
| 57 | - name: Create the ACME challenge webroot
|
| 58 | ansible.builtin.file:
|
| 59 | path: /var/www/.well-known/acme-challenge
|
| 60 | state: directory
|
| 61 | owner: "{{ acme_user }}"
|
| 62 | group: "{{ acme_web_group }}"
|
| 63 | mode: "0755"
|
| 64 | tags: [prepare]
|
| 65 |
|
| 66 | - name: Create the acme log files
|
| 67 | ansible.builtin.file:
|
| 68 | path: "/var/log/acme-{{ item }}.log"
|
| 69 | state: touch
|
| 70 | owner: "{{ acme_user }}"
|
| 71 | group: "{{ acme_group }}"
|
| 72 | mode: "0640"
|
| 73 | modification_time: preserve
|
| 74 | access_time: preserve
|
| 75 | loop: "{{ vhosts }}"
|
| 76 | tags: [prepare, acme-install]
|
| 77 |
|
| 78 | - name: Install the acme-update-certs wrapper
|
| 79 | ansible.builtin.template:
|
| 80 | src: acme-update-certs.j2
|
| 81 | dest: "{{ acme_wrapper }}"
|
| 82 | owner: root
|
| 83 | group: root
|
| 84 | mode: "0755"
|
| 85 | tags: [prepare, acme-install]
|
| 86 |
|
| 87 | - name: Check whether the uacme account is registered
|
| 88 | ansible.builtin.stat:
|
| 89 | path: "{{ acme_cert_dir }}/private/account.key"
|
| 90 | register: acme_account
|
| 91 | tags: [prepare, acme-install]
|
| 92 |
|
| 93 | - name: Explain the one-time interactive registration
|
| 94 | ansible.builtin.debug:
|
| 95 | msg: |-
|
| 96 | uacme is not registered yet. Registration is interactive: it asks for an
|
| 97 | email address and to accept the terms, so run it by hand, once:
|
| 98 |
|
| 99 | doas -u {{ acme_user }} uacme new <email>
|
| 100 |
|
| 101 | Then re-run deploy.yml to publish HTTPS.
|
| 102 | when: not acme_account.stat.exists
|
| 103 | tags: [prepare, acme-install]
|
| 104 |
|
| 105 | - name: Renew certificates
|
| 106 | ansible.builtin.command:
|
| 107 | cmd: "{{ acme_wrapper }} {{ item }}"
|
| 108 | loop: "{{ vhosts }}"
|
| 109 | register: acme_renew
|
| 110 | changed_when: false
|
| 111 | failed_when: false
|
| 112 | notify: nginx reload
|
| 113 | tags: [renew-certs]
|