swarm.ymlยถ

---
- name: "๐Ÿ” Read the Wazuh certs completion marker"
  ansible.builtin.slurp:
    src: "{{ WAZUH_CERTS_MARKER_HOST }}"
  register: wazuh_certs_marker
  failed_when: false

- name: "๐Ÿ” Checksum the rendered Wazuh certs.yml"
  ansible.builtin.stat:
    path: "{{ WAZUH_CERTS_CONFIG_HOST }}"
    checksum_algorithm: sha256
  register: wazuh_certs_config

- name: "๐Ÿ” Stat every Wazuh cert file the stack bind-mounts"
  ansible.builtin.stat:
    path: "{{ item }}"
  loop: "{{ WAZUH_CERTS_REQUIRED_FILES }}"
  register: wazuh_certs_files

- name: "๐Ÿ” List the services of a running Wazuh stack"
  ansible.builtin.command:
    argv:
      - container
      - service
      - ls
      - --quiet
      - --filter
      - "label=com.docker.stack.namespace={{ application_id | entity_name }}"
  register: wazuh_certs_stack
  changed_when: false

- name: "๐Ÿงฎ Decide whether the Wazuh certs are current"
  vars:
    expected: "{{ wazuh_certs_config.stat.checksum }} {{ WAZUH_CERTS_TOOL_VERSION }}"
    recorded: "{{ wazuh_certs_marker.content | default('') | b64decode | trim }}"
    present: >-
      {{ wazuh_certs_files.results | selectattr('stat.size', 'defined') | selectattr('stat.size', 'gt', 0) | list | length }}
  ansible.builtin.set_fact:
    wazuh_certs_expected: "{{ expected }}"
    wazuh_certs_recorded: "{{ recorded }}"
    wazuh_certs_present: "{{ present | int }}"
    wazuh_certs_current: "{{ present | int == WAZUH_CERTS_REQUIRED_FILES | length and recorded == expected }}"

- name: "๐Ÿ” Renew the Wazuh certs while the recorded marker is stale"
  when: not (wazuh_certs_current | bool)
  block:
    - name: "โ›” Refuse to rotate the Wazuh CA under a running stack"
      ansible.builtin.fail:
        msg: >-
          Wazuh TLS certs on {{ inventory_hostname }} are not current, and the stack
          '{{ application_id | entity_name }}' is running, so they were NOT regenerated: that would
          swap the CA under the live services.
          Marker {{ WAZUH_CERTS_MARKER_HOST }} reads '{{ wazuh_certs_recorded or 'missing' }}',
          expected '{{ wazuh_certs_expected }}' (sha256 of certs.yml, then tool version);
          {{ wazuh_certs_present }}/{{ WAZUH_CERTS_REQUIRED_FILES | length }} cert files in
          {{ WAZUH_CERTS_DIR_HOST }} exist and are non-empty.
          To regenerate: run 'docker stack rm {{ application_id | entity_name }}', then redeploy.
          To keep certs you know are good (a host deployed before this marker existed): write
          '{{ wazuh_certs_expected }}' to {{ WAZUH_CERTS_MARKER_HOST }}, then redeploy.
      when: wazuh_certs_stack.stdout | trim | length > 0

    - name: "โฌ‡๏ธ Pull the Wazuh certs generator image on the stack host"
      ansible.builtin.command:
        argv:
          - container
          - pull
          - "{{ WAZUH_CERTS_GENERATOR_IMAGE }}"
      register: wazuh_certs_pull
      retries: 10
      delay: 6
      until: wazuh_certs_pull.rc == 0
      changed_when: false

    - name: "๐Ÿ” Run the Wazuh certs generator once on the stack host"
      ansible.builtin.shell: |
        set -euo pipefail
        container ps -aq --filter {{ ('name=^' ~ WAZUH_CERTS_GENERATOR_CONTAINER ~ '$') | quote }} | xargs -r container rm -f
        timeout -k 30 {{ lookup('timeout', 600) | int }} container run --rm \
          --name {{ WAZUH_CERTS_GENERATOR_CONTAINER | quote }} \
          --entrypoint {{ WAZUH_CERTS_ENTRYPOINT_TARGET | quote }} \
          --env CERT_TOOL_VERSION={{ WAZUH_CERTS_TOOL_VERSION | quote }} \
          --env WAZUH_MANAGER_NODE={{ WAZUH_MANAGER_CONTAINER | quote }} \
          {% for mount in WAZUH_CERTS_GENERATOR_MOUNTS %}--mount {{ mount | quote }} {% endfor %}\
          {{ WAZUH_CERTS_GENERATOR_IMAGE | quote }}
      args:
        executable: /bin/bash
      register: wazuh_certs_generate
      retries: 3
      delay: 10
      until: wazuh_certs_generate.rc == 0

- name: "โœ… Verify the generated Wazuh certs and record the marker"
  when: wazuh_certs_generate is not skipped
  block:
    - name: "๐Ÿ” Stat the Wazuh cert files the generator wrote"
      ansible.builtin.stat:
        path: "{{ item }}"
      loop: "{{ WAZUH_CERTS_REQUIRED_FILES }}"
      register: wazuh_certs_written

    - name: "โœ… Assert every Wazuh cert file exists and is non-empty"
      ansible.builtin.assert:
        that:
          - >-
            wazuh_certs_written.results | selectattr('stat.size', 'defined') | selectattr('stat.size', 'gt', 0)
            | list | length == WAZUH_CERTS_REQUIRED_FILES | length
        fail_msg: "The Wazuh certs generator exited 0 but left a required cert file missing or empty."

    - name: "๐Ÿ“ Record the Wazuh certs completion marker"
      ansible.builtin.copy:
        content: "{{ wazuh_certs_expected }}\n"
        dest: "{{ WAZUH_CERTS_MARKER_HOST }}"
        mode: "0644"