Commit Graph

2 Commits (268feaa1f2f5b5f4e2789e97bd0ffbcd9ba9b0b7)

Author SHA1 Message Date
Amir Alexander Abdelbaki 268feaa1f2 feat(ansipa): add Nextcloud, and make FreeIPA the sole identity source
Adds a built-in Nextcloud to the ansipa stack and wires every service's
logins back to FreeIPA, either through Keycloak or directly.

Nextcloud:
  - nextcloud + redis services, sharing the existing postgres server via a
    second database. The initdb hook only fires on an empty data directory,
    so run.sh also creates the role/DB idempotently for stacks that predate
    Nextcloud.
  - served at the /nextcloud subpath of the gateway (OVERWRITEWEBROOT), with
    the /.well-known/* DAV redirects at the server root that sync clients and
    Nextcloud's own setup checks expect.

Identity:
  - keycloak-configure.sh now provisions confidential OIDC clients per relying
    party (nextcloud, proxmox-ve, proxmox-bs, opnsense) plus a realm-wide
    "groups" claim, writing secrets to .oidc-secrets (0600, gitignored).
  - nextcloud-configure.sh binds the IPA LDAP backend as the account source
    and user_oidc for login. The internal username is pinned to the IPA uid
    and unique-uid is disabled, otherwise every SSO login creates a second,
    empty account beside the LDAP one.
  - checkmk-ldap-configure.sh binds CheckMK straight to FreeIPA. CheckMK
    cannot go through Keycloak: SAML is commercial-edition only and no
    edition supports OIDC. The LDAP REST endpoints landed in 2.4 (werk
    #16527) but the stack pins 2.3, so it writes user_connections.mk —
    generated via Python repr() so quotes in a password cannot produce a
    SyntaxError that takes the GUI down, backed up and rolled back if the
    site fails to load it. Directory type is 389directoryserver, which is
    what gives FreeIPA the correct uid/member attribute defaults.

Monitoring:
  - OPNsense local check (gateways, pf state table vs its hard limit,
    firmware, CARP) plus an installer. POSIX sh, since OPNsense is FreeBSD
    with no bash or GNU grep. Transport is agent-over-SSH rather than inetd
    on 6556, because OPNsense regenerates inetd.conf/services/hosts.allow
    from config.xml and silently reverts those edits on reboot.

Fixes found along the way:
  - keycloak-configure.sh used KC_URL without the /auth relative path and
    probed /health/ready, which lives on management port 9000 and is not
    under that path — so it 404'd and timed out on this deployment.
  - .env.example had an unquoted `cn=Directory Manager`, which the shell
    scripts sourcing it parsed as a command named `Manager`.
  - summary heredocs printed raw escape codes; colours now use ANSI-C quoting.

docs/md/ansipa-sso.md covers the identity chain, the per-service support
matrix, Proxmox VE/PBS OpenID realm setup, and why packet captures should
not be tunnelled through the CheckMK API.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWLuyyrydC1u2FjM7naPcz
2026-08-10 14:51:27 +02:00
Amir Alexander Abdelbaki f66775ce54 setup: add FreeIPA image builder and Keycloak integration
freeipa-image-builder.sh: TUI chooser that builds a FreeIPA server image
and exports it to four target formats:
  docker      — builds via podman/docker, optional registry push
  lxc         — exports container rootfs as .tar.zst Proxmox CT template,
                 generates pct import instructions
  proxmox-vm  — downloads Rocky/Fedora cloud image, customizes with
                 virt-customize, outputs QCOW2 + cloud-init user-data.yml
  oci-archive — skopeo OCI tarball for air-gapped import

Keycloak TUI option generates the full constellation:
  docker-compose.yml   FreeIPA + Keycloak + PostgreSQL stack
  .env                 pre-filled env template (passwords placeholder)
  keycloak-configure.sh  post-start Keycloak REST API config script

image/Dockerfile: Fedora 41 + freeipa-server-dns + ansible-core,
systemd-enabled container (CMD /sbin/init).

image/ipa-first-boot.{sh,service}: systemd oneshot that runs
ipa-server-install on first container/VM boot from env vars
(IPA_DOMAIN, IPA_ADMIN_PASSWORD, IPA_DM_PASSWORD, and optionals).
ConditionPathExists=!/etc/ipa/default.conf makes it idempotent.

image/keycloak-configure.sh: Keycloak REST API automation that:
  - waits for Keycloak readiness
  - creates a realm
  - wires FreeIPA LDAP user federation (READ_ONLY, vendor=rhds)
  - adds attribute mappers: email, firstName, lastName, uidNumber
  - adds group mapper (IPA groups → Keycloak groups, cn=groups,cn=accounts)
  - triggers an initial full user sync

image/docker-compose.yml: freeipa + postgres + keycloak services on
a private 172.30.0.0/24 bridge; FreeIPA has a fixed IP so Keycloak
can resolve it via extra_hosts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:22:48 +02:00