# ansipa Setup Guide **ansipa** = **Ans**ible + Free**IPA**: a GPO-like management plane for Linux fleets. FreeIPA provides identity, Kerberos, sudo/HBAC and host/user groups; a lightweight client-side enforcer turns group membership into enforced policy; CheckMK monitors the fleet; Keycloak adds SSO; and an nginx gateway fronts all the web UIs behind one hostname. This guide covers a full deployment: architecture, every port, the reverse-proxy gateway, the exact snippet to expose it behind your own reverse proxy, the NAT / behind-firewall behaviour, and known distro caveats. For the policy catalogue and playbook reference see [FreeIPA & Ansible](freeipa-ansible.md). --- ## Architecture ``` ┌─────────────────────────── docker host ───────────────────────────┐ │ docker network ipa-net (172.30.0.0/24) │ your reverse │ │ proxy (TLS) │ ┌── ansipa-nginx (gateway) ──┐ │ │ │ │ / portal start page │ │ https://ansipa ──┼──►│ /ipa/ ─► freeipa :443 ───┼──► 172.30.0.10 FreeIPA │ .example.com │ │ /cmk/ ─► checkmk :5000 ──┼──► 172.30.0.12 CheckMK │ (:443) │ │ /auth/ ─► keycloak :8080 ──┼──► keycloak Keycloak │ │ └────────────────────────────┘ │ │ │ :8088 (http) └─ postgres (KC backend) │ └────────────────────────────────────────────────────────────────────┘ ▲ ▲ client-initiated only │ (enroll, kinit, policy pull, │ — works across NAT │ CheckMK push :8000) │ ┌────────────────┴───────────┐ ┌──────────────┴─────────────┐ │ enrolled client (Arch) │ │ enrolled client (Fedora…) │ │ ansipa-enforce-policies │ │ SSSD + Kerberos + enforcer │ │ .timer (every 30 min) │ │ │ └─────────────────────────────┘ └────────────────────────────┘ ``` The design is **pull-based**: the server never initiates connections to clients. Every enrolled host runs `ansipa-enforce-policies.sh` on a 30-minute timer, does `kinit -k host/$FQDN`, reads its own group memberships from FreeIPA, and applies the matching policies locally. This is what makes the whole system work when clients are behind NAT (see [Clients behind NAT](#clients-behind-nat)). --- ## Bringing up the server stack ```bash cd setup/modules/FreeipaAnsible/image cp .env.example .env && $EDITOR .env # set domain, realm, passwords, ports # cgroup v2 hosts (WSL2, modern Fedora/Ubuntu/Arch): use the run.sh wrapper — # the FreeIPA container needs --cgroupns host, which compose cannot express. ./run.sh all # freeipa + postgres + keycloak + checkmk + nginx gateway # ./run.sh # freeipa only # ./run.sh down # stop everything # plain cgroup v1 hosts can use compose directly: docker compose up -d docker compose logs -f freeipa # watch first-boot (~10 min) ./keycloak-configure.sh # wire Keycloak → FreeIPA LDAP (once healthy) ``` --- ## Ports ### Server (published on the docker host) | Port | Proto | Service | Notes | |------|-------|---------|-------| | 389 | TCP | LDAP | FreeIPA directory | | 636 | TCP | LDAPS | FreeIPA directory (TLS) | | 88 | TCP+UDP | Kerberos | KDC | | 464 | TCP+UDP | kpasswd | password changes | | 443 | TCP | HTTPS | FreeIPA web UI (also proxied at `/ipa/`) | | 445 | TCP | SMB | Samba shares (scans, LUKS keys, policy store) | | 137 | UDP | NetBIOS name | Samba | | 138 | UDP | NetBIOS datagram | Samba | | 139 | TCP | NetBIOS session | Samba | | 8090 | TCP | CheckMK web UI | container :5000 → host 8090 (also proxied at `/cmk/`) | | 8000 | TCP | CheckMK agent receiver | **push-mode** target for NAT clients | | 6557 | TCP | CheckMK livestatus | optional, external tooling | | 8080 | TCP | Keycloak HTTP | dev mode (also proxied at `/auth/`) | | 8443 | TCP | Keycloak HTTPS | needs a cert for the `start` command | | **8088** | TCP | **nginx gateway** | single entry for the portal + all UIs (`ANSIPA_HTTP_PORT`) | ### Client (only needed for CheckMK **pull** mode) | Port | Proto | Service | Notes | |------|-------|---------|-------| | 6556 | TCP | check_mk agent socket | server → client; **unreachable across NAT**, use push mode instead | | 22 | TCP | sshd | if the client is in `dev_daemon-enable-sshd` and you manage over SSH | --- ## The nginx gateway (portal + reverse proxy) The `ansipa-nginx` service fronts all three web UIs on **one hostname/port** and serves a portal landing page. Each backend is proxied at the path it already uses natively, so there is no path rewriting to fight: | Path | Backend | Notes | |------|---------|-------| | `/` | portal start page | static, links to the three UIs | | `/ipa/` | FreeIPA `:443` | Host + Referer pinned to the IPA hostname (IPA anti-CSRF) | | `/cmk/` | CheckMK `:5000` | CheckMK already serves under `/cmk` | | `/auth/` | Keycloak `:8080` | Keycloak runs with `KC_HTTP_RELATIVE_PATH=/auth` | The gateway speaks plain HTTP on `ANSIPA_HTTP_PORT` (default **8088**) and trusts `X-Forwarded-*`, so it is designed to sit **behind your own TLS-terminating reverse proxy**. ### Exposing ansipa behind your main reverse proxy Point one hostname at the gateway. TLS is terminated by your proxy; ansipa receives plain HTTP and reads `X-Forwarded-Proto` to build correct URLs. **nginx** (add to your main reverse proxy): ```nginx server { listen 443 ssl; server_name ansipa.example.com; # ssl_certificate / ssl_certificate_key ... location / { proxy_pass http://DOCKER_HOST_IP:8088; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; } } ``` **Caddy** (one line): ```caddy ansipa.example.com { reverse_proxy DOCKER_HOST_IP:8088 } ``` **Traefik** (docker labels on the nginx service): route the host rule to the `ansipa-nginx` service on port 80. ### Per-app hostname settings (recommended for production) Both CheckMK and Keycloak generate some absolute URLs from their own configured hostname rather than the forwarded one. For a clean deployment behind a public name, set: - **Keycloak**: `KC_HOSTNAME=https://ansipa.example.com/auth` in `.env`. - **CheckMK**: set the site's URL prefix / base URL to your public `https://ansipa.example.com/cmk/` (OMD → *Global settings → User interface → Base URL*), so login redirects use `https` and the public host. Without these the UIs are still reachable through the proxy; only some redirects fall back to the container-internal scheme/host. --- ## Clients behind NAT The controller can live on the public internet while clients sit behind NAT — the architecture is client-initiated end to end: | Function | Direction | Works behind NAT? | |----------|-----------|-------------------| | Enrollment (`ipa-client-install`) | client → server | ✅ | | Policy enforcement (30-min timer) | client → server (kinit + `ipa` reads) | ✅ | | Policy store sync | client → server SMB | ✅ | | CheckMK **pull** (`:6556`) | **server → client** | ❌ — blocked by NAT | | CheckMK **push** (`cmk-agent-ctl` → `:8000`) | client → server | ✅ | So policies and identity Just Work across NAT. For monitoring, NAT clients must use **push mode**: the server records a push request for each host in `dev_mon_base` (`ansipa-checkmk-setup.sh` writes `/cmk-creds/push-mode-.req`, the CheckMK container consumes it and flips the host to `cmk_agent_connection: push-agent`), and the client registers with `cmk-agent-ctl register --server :8000`. Advertise a **client-routable** CheckMK URL so agents can reach the server — set `CMK_ADVERTISED_URL` in `.env` (e.g. `http://mon.example.com:8090`); it is stored in the `dev_mon_base` group description and must NOT be the container-internal `172.30.0.12`. > **Note:** push mode needs the full CheckMK agent’s `cmk-agent-ctl` binary. > RPM/DEB distros ship it in the agent package; on Arch the portable > `check_mk_agent` fallback lacks it, so an Arch NAT client enrolls and gets > policies but needs `cmk-agent-ctl` installed manually for push monitoring. --- ## Client enrollment ```bash # on the client, as root: sudo ./freeipa-enroll.sh --domain ansipa.example.com --realm ANSIPA.EXAMPLE.COM \ --server ipa.ansipa.example.com --hostname client01.ansipa.example.com # (IPA_PASSWORD env var or --password; --no-dns-update if IPA does not run DNS) ``` Supported distros: **Arch**, **Fedora**, **RHEL/Rocky/AlmaLinux**, **Debian/Ubuntu**. The script picks the right package manager and package names automatically. ### Arch caveat — autofs / freeipa-client from the AUR On Arch, `ipa-client-install` comes from the AUR `freeipa-client` package, which pulls the entire FreeIPA suite plus `autofs` from source — a long build (tens of minutes on a small VM). ansipa bundles its own `autofs-pkgbuild/` that builds autofs from upstream git, because the stock AUR `autofs` currently fails (its pinned `autofs-5.1.9.tar.xz` was pruned from kernel.org). `freeipa-enroll.sh` builds and installs it automatically before the AUR `freeipa-client` step, so no manual intervention is needed — just expect the first enrollment to take a while. --- ## Verifying a deployment ```bash # server docker compose ps # all healthy curl -fsS http://DOCKER_HOST_IP:8088/ | grep ansipa # portal # client (after enrollment + one enforcer run) id admin # SSSD resolves IPA users kinit admin && klist # Kerberos works sudo /usr/local/bin/ansipa-enforce-policies.sh # apply policies now sudo systemctl list-timers ansipa-enforce-policies.timer ```