# Podman — design notes Primary audience: whoever changes this module next. ## Why Debian and not NixOS The default TAPPaaS module VM is NixOS. Podman ships in Debian 13 (trixie) main, as do `cockpit` and `cockpit-podman`, so a Debian cloud image gets the whole module from apt with no packaging work and no flake to maintain. The trade-off is that the VM's state lives in `update.sh` rather than in a declarative `.nix` file — acceptable for a container *host*, whose real content is the containers the operator runs on it. ## Identity integration — the analysis The module currently authenticates against **Linux (PAM) accounts on the VM**: the cloud-init `tappaas` user has no password until an operator sets one by hand. That is a per-VM credential nobody manages, and it is the one part of this module that is not platform-integrated. ### What TAPPaaS offers The identity module (Authentik) provides two services, and [USERS.md](https://tappaas.org/generated/foundation/identity/) is explicit that they must never be stacked on one app — double login, no benefit: | Mode | `dependsOn` | Mechanism | In-app account | |------|-------------|-----------|----------------| | **OIDC** | `identity:identity` | the app is an OIDC client of Authentik; groups arrive in the `groups` claim | created just-in-time on first login | | **Forward-auth** | `identity:accessControl` | Caddy asks the Authentik outpost, then injects `X-Authentik-*` headers | none — the URL is simply gated | `identity:identity` writes `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` / `OIDC_DISCOVERY_URI` into the VM's secrets env file and restarts a configure service, so the app can register the provider. `identity:accessControl` creates a Proxy Provider in Authentik, attaches it to the embedded outpost, and flips the module's existing Caddy handler to `ForwardAuth=1`. Both bind the application to an allow-list of groups at install time — mandatory, because Authentik fails open. ### What Cockpit can actually consume **Cockpit is not an OIDC client, and cannot become one by configuration.** Its maintainers are direct about the alternatives ([cockpit#20814](https://github.com/cockpit-project/cockpit/discussions/20814)): - launching `cockpit-ws --local-session=cockpit-bridge` behind an authenticating proxy — which means "there is _zero_ authentication on that port", so `:9090` must be made unreachable by anything but the proxy; - writing a custom authentication command in the shape of `cockpit-session` — "this is _difficult_ -- this isn't configuration, this is real development". And in **every** approach, including the proxy one, a **local Unix account must still exist** for the authenticated person: `cockpit-bridge` runs inside a PAM session as that user. Cockpit does not abstract that away. So `identity:identity` is the wrong dependency for this module — the deck was optimistic. There is no configuration that makes Cockpit take an OIDC login. ### The three real options **1. `identity:accessControl` — gate the URL (recommended first step).** Authentik guards `https://podman.` at Caddy and only the bound groups get through; behind it Cockpit still shows its own PAM form. Two logins, but the exposure is centrally managed and group-driven, and it is one line in `dependsOn` plus whatever `zone0` / `proxyDomain` the environment resolves. No new machinery. **2. Authentik LDAP outpost + SSSD on the VM — one credential.** Authentik can serve LDAP; with SSSD on the Debian VM the Linux accounts *are* the Authentik accounts, so Cockpit's own form takes the same username and password as everything else, and `podadmin`-style hand-made users disappear. This is the honest fix for the local-account requirement. It is **not** something this module should carry: TAPPaaS's identity module runs only the *embedded* outpost, so an LDAP outpost plus a posix-accounts service belongs upstream in `identity` (a third service alongside `identity` and `accessControl`). **3. True single sign-on — real development.** Option 1 or 2 plus a custom Cockpit auth command that trusts `X-Authentik-Username`, with `:9090` firewalled to the proxy only. Highest value, highest risk: header-trust auth is a full bypass if the port is reachable any other way, and this module currently *advertises* direct `https://:9090` access as a feature. ### Recommendation Take option 1 now, open an upstream issue for option 2, and treat option 3 as out of scope. Note that the direct `:9090` URL stays open under option 1 — the gate is on the friendly name only, which is honest but worth saying out loud in `README.md`. ### One thing to verify on a live system first `identity:accessControl`'s install-service hard-requires `vmname`, `zone0`, `proxyDomain` and `proxyPort` in the *installed* config and — unlike `identity:identity` — does **not** derive `proxyDomain` when it is absent. This module deliberately sets neither `zone0` nor `proxyDomain`, so that both come from the environment (ADR-007 P5). `copy-update-json.sh` documents that `install-module.sh` "computes vmname/zone0/proxyDomain from the environment file and passes them as explicit overrides", but no such computation is visible in `install-module.sh` for `proxyDomain`. **Check the resolved `/home/tappaas/config/podman-.json` after an install**; if `proxyDomain` is empty, accessControl will `die`, and the fix is upstream — mirror the derivation that `identity/install-service.sh` already does.