--- # freeipa/tasks/main.yml # Provisions a FreeIPA 4.x server on Rocky Linux 9. # The ipa-server-install step is intentionally NOT idempotent — it will # refuse to run if IPA is already installed, which acts as a safety guard. # ── Pre-flight ──────────────────────────────────────────────────────────────── - name: Check IPA is not already installed ansible.builtin.stat: path: /etc/ipa/default.conf register: ipa_installed tags: always - name: Skip install tasks if IPA already exists ansible.builtin.debug: msg: "FreeIPA already installed — skipping install tasks. Use verify tasks to check health." when: ipa_installed.stat.exists tags: install - name: Assert hostname is correct FQDN ansible.builtin.command: cmd: hostname -f register: fqdn_check changed_when: false failed_when: fqdn_check.stdout != ipa_hostname when: - not ipa_installed.stat.exists - ipa_hostname is defined tags: install, preflight - name: Assert /etc/hosts has correct entry ansible.builtin.lineinfile: path: /etc/hosts line: "{{ ipa_ip }} {{ ipa_hostname }} {{ ipa_hostname.split('.')[0] }}" state: present when: - not ipa_installed.stat.exists - ipa_ip is defined - ipa_hostname is defined tags: install, preflight # ── Swap ────────────────────────────────────────────────────────────────────── - name: Check current swap ansible.builtin.command: cmd: swapon --show register: swap_check changed_when: false tags: install, swap - name: Create swap file if absent block: - name: Create swap file ansible.builtin.command: cmd: "dd if=/dev/zero of=/swapfile bs=1M count={{ ipa_swap_size_mb }} status=none" args: creates: /swapfile - name: Set swap permissions ansible.builtin.file: path: /swapfile mode: "0600" - name: Format swap ansible.builtin.command: cmd: mkswap /swapfile changed_when: true - name: Enable swap ansible.builtin.command: cmd: swapon /swapfile changed_when: true - name: Add swap to fstab ansible.builtin.lineinfile: path: /etc/fstab line: "/swapfile none swap defaults 0 0" state: present when: - not ipa_installed.stat.exists - swap_check.stdout == "" tags: install, swap # ── Package install ─────────────────────────────────────────────────────────── - name: Install FreeIPA server packages ansible.builtin.dnf: name: - freeipa-server - freeipa-server-dns state: present when: not ipa_installed.stat.exists tags: install, packages # ── IPA server install ──────────────────────────────────────────────────────── - name: Run ipa-server-install (interactive passwords via env vars) ansible.builtin.shell: cmd: > ipa-server-install --realm={{ ipa_realm }} --domain={{ ipa_domain }} --hostname={{ ipa_hostname }} --ip-address={{ ipa_ip }} --forwarder={{ ipa_dns_forwarder }} --setup-dns --auto-reverse --no-host-dns --mkhomedir --unattended --ds-password="${IPA_DM_PASSWORD}" --admin-password="${IPA_ADMIN_PASSWORD}" environment: IPA_DM_PASSWORD: "{{ ipa_dm_password }}" IPA_ADMIN_PASSWORD: "{{ ipa_admin_password }}" no_log: true when: not ipa_installed.stat.exists tags: install # ── Verification ────────────────────────────────────────────────────────────── - name: Verify IPA services are running ansible.builtin.command: cmd: ipactl status register: ipa_status changed_when: false tags: verify - name: Print IPA service status ansible.builtin.debug: var: ipa_status.stdout_lines tags: verify