--- # Install lego, obtain the DC's LDAPS cert from OpenBao's ACME, deploy it into # Samba's TLS dir, and enable a renewal timer. Idempotent. - name: Check installed lego version ansible.builtin.command: "{{ samba_ad_acme_bin }} --version" register: lego_installed changed_when: false failed_when: false - name: Install lego when missing or version mismatch when: samba_ad_acme_version not in (lego_installed.stdout | default('')) block: - name: Download lego release tarball (checksum-verified) ansible.builtin.get_url: url: "{{ samba_ad_acme_url }}" dest: "/tmp/lego_{{ samba_ad_acme_version }}.tar.gz" checksum: "{{ samba_ad_acme_checksum }}" mode: "0644" retries: 3 delay: 10 - name: Create lego staging dir ansible.builtin.file: path: "/tmp/lego_{{ samba_ad_acme_version }}" state: directory mode: "0755" - name: Extract lego ansible.builtin.unarchive: src: "/tmp/lego_{{ samba_ad_acme_version }}.tar.gz" dest: "/tmp/lego_{{ samba_ad_acme_version }}" remote_src: true - name: Install lego binary ansible.builtin.copy: src: "/tmp/lego_{{ samba_ad_acme_version }}/lego" dest: "{{ samba_ad_acme_bin }}" remote_src: true owner: root group: root mode: "0755" - name: Create ACME state directory ansible.builtin.file: path: "{{ samba_ad_acme_dir }}" state: directory owner: root group: root mode: "0700" - name: Install the obtain/renew wrapper and deploy hook ansible.builtin.template: src: "{{ item.src }}" dest: "{{ item.dest }}" owner: root group: root mode: "0755" loop: - { src: samba-acme.sh.j2, dest: /usr/local/bin/samba-acme.sh } - { src: samba-acme-deploy.sh.j2, dest: /usr/local/bin/samba-acme-deploy.sh } - name: Install the renewal systemd service + timer ansible.builtin.template: src: "{{ item.src }}" dest: "{{ item.dest }}" owner: root group: root mode: "0644" loop: - { src: samba-acme.service.j2, dest: /etc/systemd/system/samba-acme.service } - { src: samba-acme.timer.j2, dest: /etc/systemd/system/samba-acme.timer } register: acme_units - name: Reload systemd ansible.builtin.systemd_service: daemon_reload: true when: acme_units is changed # --- Preflight: the two things that actually make http-01 fail here ------------ - name: Confirm nothing else is bound to port 80 # lego binds :80 for the duration of validation. Anything already holding it # makes issuance fail with a bind error rather than anything ACME-shaped. ansible.builtin.shell: cmd: "ss -ltn '( sport = :80 )' | tail -n +2 | wc -l" register: port80 changed_when: false - name: Fail if port 80 is occupied ansible.builtin.fail: msg: "Port 80 is in use on {{ inventory_hostname }}; lego's http-01 cannot bind it." when: port80.stdout | trim | int > 0 - name: Confirm the OpenBao ACME directory is reachable ansible.builtin.uri: url: "{{ samba_ad_acme_server }}" return_content: false validate_certs: true register: acme_dir retries: 3 delay: 10 until: acme_dir is succeeded changed_when: false - name: Obtain/renew the certificate now # Safe to run every time: lego only acts when the cert is missing or within # --renew-days of expiry, and only then fires the deploy hook. ansible.builtin.command: /usr/local/bin/samba-acme.sh register: lego_run changed_when: "'Server responded with a certificate' in (lego_run.stdout | default('') + lego_run.stderr | default(''))" - name: Enable and start the renewal timer ansible.builtin.systemd_service: name: samba-acme.timer enabled: true state: started - name: Report the live LDAPS certificate ansible.builtin.shell: cmd: >- echo | timeout 10 openssl s_client -connect 127.0.0.1:636 2>/dev/null | openssl x509 -noout -subject -issuer -dates register: live_cert changed_when: false - name: Show it ansible.builtin.debug: msg: "{{ live_cert.stdout_lines }}"