Rebuild auth on Keycloak OIDC, fix rootless Ansible deploy

Replaces the single shared HTTP Basic service-account credential (which
caused a production outage from a username mismatch) with per-user login:
Keycloak (already running on this VM for gcnm, now also fronted on
auth.friessn.de with its own "homekeeper" realm) authenticates the user
once via the landing page, FastAPI verifies the OIDC id_token and mints
its own signed session JWT as a cookie, and both Shiny apps forward that
per-session token as a Bearer credential instead of a static shared one.
Authorization is a simple ALLOWED_USERS allowlist; the old auth.users
table and bcrypt seeding are gone entirely.

Also carries forward the in-progress rootless Podman/Quadlet migration
(gitea, homekeeper, podman roles) and fixes a pre-existing bug where
each role's handlers were malformed inside tasks/main.yml instead of
their own handlers/main.yml, which broke ansible-playbook entirely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbiCdckkTX2HyAkyi1R39d
This commit is contained in:
friessn
2026-07-13 06:31:36 +00:00
parent 58983e6855
commit 6c9cd67a08
36 changed files with 579 additions and 245 deletions
+24 -20
View File
@@ -1,24 +1,28 @@
# Homekeeper Infrastructure
Ansible setup for a Hetzner VM (Ubuntu 24.04) running Homekeeper via Podman.
Ansible setup for a Hetzner VM (Ubuntu 24.04) running Homekeeper via rootless Podman.
## Architecture
```
nginx (system) ← HTTPS, routes by path
├── / ← static landing page (/var/www/html)
├── /gitea/Gitea on :3000 (git + container registry)
├── /api/ → homekeeper-api on :8000
├── /beekeeper/ → homekeeper-beekeeper on :3838
└── /listkeeper/ → homekeeper-listkeeper on :3839
nginx (system) ← HTTPS
├── home.friessn.de ← landing page (/var/www/html) + path routing
├── / static landing page
├── /api/ → homekeeper-api on 127.0.0.1:8000
├── /beekeeper/ → homekeeper-beekeeper on 127.0.0.1:3838
└── /listkeeper/ → homekeeper-listkeeper on 127.0.0.1:3839
└── git.friessn.de → Gitea on 127.0.0.1:3000 (git + container registry)
own site file, managed outside this role
Podman (rootful, Quadlets → systemd units)
├── homekeeper-db postgres:17, data at /opt/homekeeper/pg_data
Podman (rootless, user Quadlets under {{ deploy_user }} → systemd --user units)
├── homekeeper-db postgres:17, data in named volume {{ homekeeper_db_volume }}
├── homekeeper-api from Gitea registry, auto-update enabled
├── homekeeper-beekeeper from Gitea registry, auto-update enabled
── homekeeper-listkeeper from Gitea registry, auto-update enabled
── homekeeper-listkeeper from Gitea registry, auto-update enabled
└── gitea from docker.io, data in named volume {{ gitea_data_volume }}
gitea container from docker.io, auto-update disabled
All containers run as {{ deploy_user }} (not root) — `loginctl enable-linger`
keeps the user systemd instance (and its containers) running after logout/reboot.
```
## First-time setup
@@ -54,16 +58,16 @@ On your local machine, build and push the three custom images:
```bash
# Login to Gitea registry
docker login git.friessn.de -u nico
docker login git.friessn.de -u friessn
# Build and push
docker build -t git.friessn.de/nico/homekeeper-api:latest ./api
docker build -t git.friessn.de/nico/homekeeper-beekeeper:latest ./beekeeper
docker build -t git.friessn.de/nico/homekeeper-listkeeper:latest ./listkeeper
docker build -t git.friessn.de/friessn/homekeeper-api:latest ./api
docker build -t git.friessn.de/friessn/homekeeper-beekeeper:latest ./beekeeper
docker build -t git.friessn.de/friessn/homekeeper-listkeeper:latest ./listkeeper
docker push git.friessn.de/nico/homekeeper-api:latest
docker push git.friessn.de/nico/homekeeper-beekeeper:latest
docker push git.friessn.de/nico/homekeeper-listkeeper:latest
docker push git.friessn.de/friessn/homekeeper-api:latest
docker push git.friessn.de/friessn/homekeeper-beekeeper:latest
docker push git.friessn.de/friessn/homekeeper-listkeeper:latest
```
### 6. Full playbook run
@@ -76,9 +80,9 @@ ansible-playbook -i inventory/hosts.yml site.yml
After pushing a new image to the Gitea registry, `podman auto-update` picks it up
automatically within `autoupdate_schedule` (default: every 15 minutes).
For an immediate deploy:
For an immediate deploy (containers run rootless as `deploy_user`, not root):
```bash
ssh root@YOUR_IP podman auto-update
ssh nico@YOUR_IP podman auto-update
```
## Secrets management