From 33e783efb594b67063610b1eb2eea2c2d1eb3011 Mon Sep 17 00:00:00 2001 From: Lars Rossen Date: Sat, 22 Aug 2026 20:42:04 +0200 Subject: [PATCH] slides(tappaas): a slide per lifecycle script; correct the identity claim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit install.sh, update.sh and test.sh get one slide each, with the real content of each — including why a 401 from Cockpit is a passing test and why test.sh uses curl -s rather than --fail. Corrects the identity story: Cockpit is not an OIDC client and cannot be configured into one, so the contract shows identity:accessControl and the demo slide is honest that Authentik gates the URL while Cockpit still asks for a local account. Full analysis in the module's DESIGN.md. --- slides/tappaas/how-to/new-module/index.md | 63 +++++++++++++++++++---- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/slides/tappaas/how-to/new-module/index.md b/slides/tappaas/how-to/new-module/index.md index cadc4b0..241d7fa 100644 --- a/slides/tappaas/how-to/new-module/index.md +++ b/slides/tappaas/how-to/new-module/index.md @@ -176,7 +176,7 @@ That is the whole surface. Everything else is the platform's job. "description": "Podman container host — Debian 13 VM with rootless Podman + Cockpit", "vmname": "podman", "vmid": 812, "dependsOn": ["cluster:vm", "templates:debian", "backup:vm", - "network:proxy", "identity:identity"], + "network:proxy", "identity:accessControl"], "config": { "cluster:vm": { "cores": 2, "memory": "2048", "diskSize": "20G", "image": "debian-13-generic-amd64.qcow2" }, @@ -190,15 +190,55 @@ That is the whole surface. Everything else is the platform's job. --- -## The three scripts, honestly +## `install.sh` — called once, at add -| Script | Called | Does | -| --- | --- | --- | -| `install.sh` | once, at add | For podman: `exec update.sh` — install *is* update here | -| `update.sh` | every schedule | apt: `podman`, `podman-compose`, `cockpit`, `cockpit-podman`; enable the rootless socket | -| `test.sh` | on demand + before every update merge | VM reachable · podman present · plugin present · console answers on `:9090` | +```bash +#!/usr/bin/env bash +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "${SCRIPT_DIR}/update.sh" "$@" +``` -If `test.sh` is honest, unattended updates are safe. That is the entire deal. +By the time it runs, `cluster:vm` has built the VM and `templates:debian` has +apt-upgraded it and installed the guest agent. + +For podman there is nothing install-only — **install *is* update**. Five lines is a +perfectly good `install.sh`. + +--- + +## `update.sh` — where the work is + +Runs on the **mothership**, not on the VM. It: + +1. finds the node hosting the VM via `pvesh` — HA-safe, the VM may have moved +2. resolves the VM's IP through the **Proxmox guest agent**, then waits for SSH +3. `apt-get install podman podman-compose slirp4netns uidmap cockpit cockpit-podman` +4. enables the **rootless** `podman.socket`, `loginctl enable-linger`, `cockpit.socket` +5. records `/etc/tappaas-podman.version` +6. polls `https://localhost:9090` until the console answers, then prints the URL + +Every step is re-runnable: apt is a no-op when current, the marker is overwritten, +the sockets are `enable --now`. That is what "idempotent" has to mean in practice. + +--- + +## `test.sh` — the one that earns trust + +| Check | How | +| --- | --- | +| VM reachable | IP resolves via the guest agent | +| podman installed | version marker + `podman --version` actually runs | +| plugin present | `dpkg -s cockpit-podman` | +| console alive | `:9090` answers `200`, `302`, `401` or `403` | + +A login page **is** a pass — pre-auth, `401` is the healthy answer. + +Prints `N passed, M failed` and exits non-zero on any failure. Note `curl -s`, not +`--fail`: `--fail` exits 22 on 4xx and would corrupt the `-w '%{http_code}'` we read. + +Run on demand, and again before every update is merged. If `test.sh` is honest, +unattended updates are safe — that is the entire deal. --- @@ -208,7 +248,7 @@ If `test.sh` is honest, unattended updates are safe. That is the entire deal. - OS prep — `templates:debian` did apt + guest agent - A VLAN, an interface, DHCP, firewall rules — the zone came with the environment - `https://podman.lab1.makerfloss.eu` with a real certificate — `network:proxy` -- A login — `identity:identity`, so it is your TAPPaaS account, not a local one +- An access gate — `identity:accessControl`: only the bound groups reach the URL - Nightly backup to PBS, scheduled updates, health reporting A few lines of json bought all of it. @@ -262,8 +302,9 @@ module-manager module test podman Then open **`https://podman.lab1.makerfloss.eu`** — Cockpit, with the Podman page. - Reachable from the `mgmt` zone only. Not from the internet, by declaration. -- You log in with your **TAPPaaS identity** — that is what the `identity:identity` - dependency buys; no per-VM Linux passwords to hand out. +- Authentik gates the URL: no `devops` group, no console. Then Cockpit asks *again* — + it is not an OIDC client, and a local Unix account is not optional for it. +- Two logins, honestly. `DESIGN.md` in the repo says what it would take to fix. ---