# 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/`:

```bash
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
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:

```bash
# 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

```json
{
  "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

```bash
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

```bash
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

```bash
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

```bash
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:**
```bash
# 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
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.
