← Index

FreeIPA & Ansible

The FreeIPA/Ansible system provides centralised identity management for a fleet of Arch Linux machines: single sign-on, host-group-driven package and module deployment, LUKS backup key collection, and automatic Keycloak configuration.

All relevant files live under setup/modules/FreeipaAnsible/.


Architecture

┌────────────────────────────────────┐
│  FreeIPA Server                    │
│  (can run in Docker / LXC)         │
│                                    │
│  • User/host directory             │
│  • Kerberos KDC                    │
│  • DNS (optional)                  │
│  • Host group management           │
└──────────┬─────────────────────────┘
           │ SSSD / Kerberos
           ▼
┌────────────────────────────────────┐
│  Enrolled client machine           │
│                                    │
│  • sssd — authentication           │
│  • ipa CLI — host group queries    │
│  • Ansible-deployed timers         │
│    ├── package installer           │
│    ├── module installer            │
│    ├── Flatpak installer           │
│    └── baseuser group sync         │
└────────────────────────────────────┘

FreeIPA Server

Docker / OCI Image

A pre-built Docker image is available via setup/modules/FreeipaAnsible/image/:

cd setup/modules/FreeipaAnsible/image
cp .env.example .env
# Edit .env with your domain, admin password, realm, etc.
docker compose up -d

The container runs ipa-first-boot.sh on first start to initialise the IPA instance, then optionally keycloak-configure.sh to wire up Keycloak as an OIDC provider.

Interactive Server Setup

bash setup/modules/optional-Modules/apps/freeipa-server.sh

Prompts for realm, domain, admin password, and whether to generate client-install scripts.


Client Enrollment

Via Installer Module

Select freeipa-client during tui-install.sh or install-modules.sh.

Manual Enrollment

Three modes:

# Answerfile mode (unattended)
bash setup/modules/FreeipaAnsible/freeipa-client.sh \
    --answerfile setup/modules/FreeipaAnsible/freeipa-client-answerfile.json

# Interactive prompts
bash setup/modules/FreeipaAnsible/freeipa-client.sh --interactive

# Direct flag passthrough to freeipa-enroll.sh
bash setup/modules/FreeipaAnsible/freeipa-client.sh \
    --domain freeipa.example.com \
    --server ipa.example.com \
    --principal admin

Client Answerfile Schema

{
  "domain":      "freeipa.abdelbaki.eu",
  "realm":       "FREEIPA.ABDELBAKI.EU",
  "server":      "freeipa.abdelbaki.eu",
  "hostname":    "",
  "principal":   "admin",
  "password":    "",
  "mkhomedir":   true,
  "sudo":        true,
  "dns_update":  true,
  "ntp_server":  "",
  "fido2":       false,
  "fido2_users": []
}

Leave hostname blank to use the current machine hostname. Leave password blank to be prompted at enrollment time.


Ansible Playbooks

All playbooks live in setup/modules/FreeipaAnsible/ansible/ and require an inventory of enrolled IPA clients.

Deploy Package Auto-Installer

ansible-playbook -i inventory deploy-ansipa-install.yml

Deploys ansipa-install-packages.sh + a systemd timer that runs every 30 minutes. The script queries IPA for host groups named ansipa-install-<package> and installs/removes packages to match.

Group naming convention: ansipa-install-firefox → installs the firefox package.

Deploy Module Auto-Installer

ansible-playbook -i inventory deploy-ansipa-modules.yml \
    [-e ansipa_user=amir]

Deploys ansipa-install-modules.sh + timer. Queries for groups named ansipa-module-<name> and runs the matching script from /usr/local/lib/ansipa-modules/<name>.sh.

Module scripts are the same ones used by install-modules.sh — copied from setup/modules/optional-Modules/apps/*.sh.

Group naming convention: ansipa-module-docker → runs docker.sh on the host.

Each module is applied once and stamped in /var/lib/ansipa-modules/<name>.done. Re-running the timer skips already-applied modules.

Deploy BaseUser Sync

ansible-playbook -i inventory deploy-baseuser-sync.yml

Deploys a systemd.path unit that triggers whenever a user logs in. If the user is a member of the IPA BaseUser group, they are automatically added to the local baseusers group — useful for desktop permission grants.

Collect LUKS Backup Keys

ansible-playbook -i inventory collect-luks-keys.yml \
    [-e luks_keys_store=/secure/location]

For each enrolled host, checks for /_LUKS_BACKUP_KEY (placed there by the M-Archy installer when disk encryption is enabled) and fetches it to the controller as:

<luks_keys_store>/<HOSTNAME>_LUKS_BACKUP_KEY

Keys are stored with mode 0400. The store directory is created with mode 0700.

Schedule for automatic collection:

# Add to crontab on the Ansible controller
0 3 * * * cd /path/to/playbooks && ansible-playbook -i inventory collect-luks-keys.yml

Host Group Reference

Group prefix Handled by Effect
ansipa-install-<pkg> ansipa-install-packages.sh Install/remove native package
ansipa-module-<name> ansipa-install-modules.sh Run module script once
fp_install-<app> ansipa-install-flatpaks.sh Install Flatpak app
BaseUser auto-add-baseuser.sh Add user to local baseusers group

LUKS Key Flow

  Install time (arch-autoinstall.sh or archbaseos-guided-install.sh)
  ─────────────────────────────────────────────────────────────────
  1. User sets primary LUKS passphrase interactively
  2. 64-byte random key generated from /dev/urandom
  3. Key enrolled in second LUKS slot
  4. Key written to /_LUKS_BACKUP_KEY (mode 0400, root-only)
     inside the encrypted Btrfs volume

  Post-install (Ansible)
  ──────────────────────
  5. collect-luks-keys.yml runs from the controller
  6. Fetches /_LUKS_BACKUP_KEY from each client
  7. Stores as luks-keys/<HOSTNAME>_LUKS_BACKUP_KEY (mode 0400)
     on the controller

The backup key lives inside the encrypted partition, so it is only accessible when the disk is already unlocked. Its purpose is to allow an admin to unlock the disk for recovery without knowing the user's passphrase.


Auto Enrollment + Ansible

bash setup/modules/FreeipaAnsible/auto-enroll-ansible.sh

Combines FreeIPA client enrollment and Ansible deployment in one shot. Useful for provisioning scripts that run on first boot.