---
# deploy-ansipa-policies.yml — deploy the policy enforcement daemon to enrolled clients.
#
# Installs ansipa-enforce-policies.sh and a systemd timer that runs it every 30 minutes.
# Policy logic lives in /usr/local/lib/ansipa/policies.d/ (one .sh file per policy type).
# At runtime the enforcer also syncs those files from the ansipa-policystore SMB share
# on the FreeIPA container, so live edits via the share take effect without re-running Ansible.
#
# Device policies (FreeIPA host groups — applied to the whole machine):
#   dev_daemon-enable-<unit>    Ensure <unit> is enabled and running; reverted when host leaves group
#   dev_daemon-disable-<unit>   Ensure <unit> is disabled and stopped; reverted when host leaves group
#   dev_timeshift-backup        Enforce daily Timeshift snapshots (03:00)
#   dev_no-local-users          Lock local account passwords; only FreeIPA accounts can auth
#   dev_local-sudo-<username>   Grant <username> local sudo on this device; reverted when host leaves
#   dev_ssh_<userid>            Distribute <userid>'s SSH public keys from IPA to authorized_keys
#                               on this device; allows that IPA user to SSH in from any of their
#                               registered keys without a password.  Keys stored in IPA via:
#                                 ipa user-mod <userid> --sshpubkey='ssh-ed25519 AAAA...'
#
# User policies (FreeIPA user groups — follow the user across all enrolled devices):
#   usr_admin                   Grant full sudo on every enrolled host (sudoers drop-in, SSSD-resolved)
#   usr_block-binary-<name>     Block execution of <name> via a PATH-priority wrapper
#   usr_prt_<printer>           Auto-add printer at login (per-user); URI in IPA group description
#   usr_smb_r_<name>           Mount read-only Samba share ~/‹name› for members; credentials in IPA group description
#   usr_smb_rw_<name>          Mount read-write Samba share ~/‹name› for members (rw beats r if both)
#   usr_smb_adm_policystore    Mount the policy store at ~/policystore (rw) for admin members;
#                               credential in IPA group description (set by ansipa-smb-setup.sh)
#
# CheckMK monitoring policies (device host-groups, unless noted):
#   dev_mon_base               Install CheckMK agent; register host in CMK; check: installed packages.
#                              Credentials auto-discovered from IPA dev_mon_base description (set by
#                              ansipa-checkmk-setup.sh on the FreeIPA container).
#                              CPU/RAM/disk/uptime reported by built-in agent sections.
#   dev_mon_clamscan           Run daily ClamAV + rkhunter + chkrootkit scan (02:00) and report the
#                              result to CheckMK via a local check (Ansipa_ClamScan). Also add the
#                              host to dev_mod_anti-malware (installs the tools) and dev_mon_base
#                              (installs the agent that collects the check).
#   dev_mon_timeshift          Local check for most recent Timeshift snapshot age.
#                              WARN if >5 days, CRIT if >10 days, CRIT if no snapshots found.
#   dev_mon_power              Local check for CPU package TDP/power via Intel RAPL or lm-sensors.
#   usr_mon_logins             (User group) Local check for SSH login attempts in last 24h.
#                              Reports: successful + failed + invalid-user counts with thresholds.
#
# Prerequisites:
#   - Host enrolled in FreeIPA (sssd + ipa CLI available)
#   - For dev_mon_clamscan tools:  also add host to dev_mod_anti-malware group
#   - For timeshift-backup:        also add host to dev_mod_timeshift group
#   - For dev_mon_*: CheckMK CE must be up; run ansipa-checkmk-setup.sh on the FreeIPA
#                    container first (seeds credentials + groups in IPA)
#   - For usr_smb_r_*/usr_smb_rw_*/usr_smb_adm_policystore: cifs-utils installed (handled below);
#                    Samba service running on the IPA container (ansipa-smb.service auto-starts)
#
# Usage:
#   ansible-playbook -i inventory deploy-ansipa-policies.yml
#
#   To seed the policystore on the FreeIPA container for the first time (bootstrap only;
#   thereafter edit files directly via the SMB share at ~/policystore):
#   ansible-playbook -i inventory deploy-ansipa-policies.yml \
#       -e seed_policystore=true -e ipa_server_host=<ipa-host>

- name: Deploy FreeIPA policy enforcer
  hosts: all
  become: yes

  tasks:

    - name: Create ansipa library and policy directories
      file:
        path: "{{ item }}"
        state: directory
        mode: '0755'
      loop:
        - /usr/local/lib/ansipa
        - /usr/local/lib/ansipa/policies.d
        - /usr/lib/check_mk_agent/local

    - name: Deploy shared policy library
      copy:
        src: lib/ansipa-policy.sh
        dest: /usr/local/lib/ansipa/policy.sh
        mode: '0644'

    - name: Deploy policy modules
      copy:
        src: policies.d/
        dest: /usr/local/lib/ansipa/policies.d/
        mode: '0644'

    - name: Install required packages
      package:
        name: "{{ item }}"
        state: present
      loop:
        - "{{ 'samba' if ansible_os_family == 'Archlinux' else 'samba-client' }}"
        - cups
        - cifs-utils      # needed for usr_smb_* CIFS mounts
        - "{{ 'openssh' if ansible_os_family == 'Archlinux' else 'openssh-server' }}"
        - lm_sensors      # needed for dev_mon_power fallback (Intel RAPL preferred)
      ignore_errors: yes

    - name: Deploy policy enforcer script
      copy:
        src: ansipa-enforce-policies.sh
        dest: /usr/local/bin/ansipa-enforce-policies.sh
        mode: '0755'

    - name: Create policy state directory
      file:
        path: /var/lib/ansipa-policies
        state: directory
        mode: '0700'

    - name: Install policy enforcer systemd service
      copy:
        dest: /etc/systemd/system/ansipa-enforce-policies.service
        mode: '0644'
        content: |
          [Unit]
          Description=Enforce FreeIPA host-group policies (binary blocks, backups, scans)
          After=network-online.target sssd.service
          Wants=network-online.target

          [Service]
          Type=oneshot
          ExecStart=/usr/local/bin/ansipa-enforce-policies.sh
          StandardOutput=journal
          StandardError=journal

    - name: Install policy enforcer systemd timer
      copy:
        dest: /etc/systemd/system/ansipa-enforce-policies.timer
        mode: '0644'
        content: |
          [Unit]
          Description=Periodic FreeIPA policy enforcement

          [Timer]
          OnBootSec=5min
          OnUnitActiveSec=30min

          [Install]
          WantedBy=timers.target

    - name: Reload systemd
      command: systemctl daemon-reload

    - name: Enable and start policy enforcer timer
      systemd:
        name: ansipa-enforce-policies.timer
        enabled: yes
        state: started

    # ── Bootstrap: seed policy files onto the policystore SMB share ──────────
    # Run once with -e seed_policystore=true -e ipa_server_host=<host>.
    # After seeding, edit policies directly via ~/policystore (usr_smb_adm_policystore).
    - name: Seed policystore on IPA server (bootstrap — run once)
      copy:
        src: "policies.d/"
        dest: /data/policy-store/policies.d/
        mode: '0664'
        directory_mode: '02775'
      delegate_to: "{{ ipa_server_host | default(omit) }}"
      run_once: true
      when: (seed_policystore | default(false) | bool) and (ipa_server_host is defined)
