feat(auth): annuaire Authentik + portail consoles Guacamole (#76)

- k8s/apps/authentik : IdP OIDC (auth.lab.local), namespace auth —
  server + worker 2026.5.3, Redis in-cluster, PG sur storage-01, PVC media
- k8s/apps/guacamole : portail consoles SSH web s01/g01 (portail.lab.local) —
  guacd + webapp 1.6.0, SSO OIDC vers Authentik, Job initdb idempotent
- ansible : rôle console_user (user sans sudo pour les consoles, s01 + g01),
  bases PG authentik/guacamole, secrets vault (mdp PG + clé SSH console)
- doc : admin/k8s/auth-portal.md (déploiement, config initiale, pièges)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
ALI YESILKAYA 2026-07-06 21:24:46 +02:00 committed by GitHub
parent 09ca0be469
commit 87b786eb57
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 775 additions and 64 deletions

103
admin/k8s/auth-portal.md Normal file
View file

@ -0,0 +1,103 @@
# Annuaire + portail consoles — Authentik & Guacamole
Annuaire d'identités **Authentik** (IdP OIDC/LDAP) et portail **Guacamole** donnant
accès aux consoles SSH de storage-01 et gpu-01 **dans le navigateur**, avec un compte
unique par utilisateur. Namespace k8s : **`auth`**.
## Vue d'ensemble
```
Utilisateur ──▶ portail.lab.local (Guacamole) ──login OIDC──▶ auth.lab.local (Authentik)
└──▶ guacd ──SSH (user « console », clé ed25519)──▶ s01 / g01
```
| URL | Service | Rôle |
|---|---|---|
| `http://auth.lab.local` | Authentik | Annuaire : comptes, groupes, SSO OIDC |
| `http://portail.lab.local` | Guacamole | Portail : consoles SSH web s01/g01 |
## Composants
- **Authentik** (`k8s/apps/authentik/`) : server + worker (`ghcr.io/goauthentik/server:2026.5.3`),
Redis in-cluster, PVC `authentik-media` (RWX, nfs), base **PostgreSQL sur storage-01**
(même pattern que Ghostfolio/n8n).
- **Guacamole** (`k8s/apps/guacamole/`) : webapp `guacamole/guacamole:1.6.0` + proxy
`guacamole/guacd:1.6.0`, base PostgreSQL sur storage-01 (connexions, permissions).
Le Job ArgoCD `guacamole-initdb` pose le schéma si absent (idempotent).
- **Ansible** : rôle `postgresql` (bases `authentik` + `guacamole`), rôle **`console_user`**
(user `console` **sans sudo** sur s01 et g01, clé publique Guacamole).
## Secrets
Vault Ansible (`make vault-view`) :
| Variable | Usage |
|---|---|
| `vault_pg_authentik_password` | Base PG `authentik` |
| `vault_pg_guacamole_password` | Base PG `guacamole` |
| `vault_console_ssh_private_key` | Clé privée SSH des connexions Guacamole (user `console`) |
Secrets k8s (créés à la main, **hors git**, comme `ghostfolio-secret`) — mots de passe
identiques au vault, `secret-key` = 48+ caractères aléatoires :
```bash
kubectl create ns auth
kubectl -n auth create secret generic authentik-secret \
--from-literal=secret-key='<clé aléatoire>' \
--from-literal=pg-password='<vault_pg_authentik_password>' \
--from-literal=redis-password='<aléatoire>'
kubectl -n auth create secret generic guacamole-secret \
--from-literal=pg-password='<vault_pg_guacamole_password>'
```
## Déploiement (ordre)
1. `ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags postgresql,console_user`
2. `ansible-playbook -i inventory.yml playbooks/gpu-01.yml --tags console_user`
3. Créer les secrets k8s ci-dessus (avant le premier sync, sinon pods en `CreateContainerConfigError`)
4. Merge sur `main` → ArgoCD crée les Applications `authentik` et `guacamole` (~3 min)
## Configuration initiale — Authentik
1. **Compte admin** : ouvrir `http://auth.lab.local/if/flow/initial-setup/` (valable
uniquement tant qu'aucun admin n'existe) → définir mot de passe de `akadmin`.
2. **Provider OIDC** pour Guacamole — Admin → Applications → Providers → Create
*OAuth2/OpenID Provider* :
- Name : `guacamole` — Authorization flow : *implicit-consent*
- Client type : **Public** (Guacamole utilise le flux implicite, pas de client secret)
- Client ID : `guacamole`
- Redirect URI : `http://portail.lab.local/`
- **Signing Key : sélectionner le certificat self-signed** (sinon JWKS vide → login KO)
3. **Application** — Applications → Create : Name `Portail consoles`,
**slug `guacamole`** (doit correspondre à `/application/o/guacamole/` configuré côté
Guacamole : issuer + JWKS), Provider `guacamole`.
4. **Utilisateurs** — Directory → Users → Create (+ groupes si besoin). Le
`preferred_username` Authentik devient le nom de compte Guacamole.
## Configuration initiale — Guacamole
1. Se connecter en **`guacadmin` / `guacadmin`** (formulaire local, extension base) et
**changer ce mot de passe immédiatement** (portail exposé à tout le LAN).
2. Settings → Connections → New connection (×2) :
- Protocol `SSH` — Hostname `192.168.10.1` (s01) ou `192.168.10.20` (g01) — Port `22`
- Username `console` — Private key : coller `vault_console_ssh_private_key`
3. Settings → Users : les comptes Authentik apparaissent après leur **premier login**
(`POSTGRESQL_AUTO_CREATE_ACCOUNTS=true`) → leur assigner les connexions (READ).
## Pièges / notes
1. **Tout est en HTTP** (pas de TLS sur `*.lab.local`) — OK pour un LAN privé, mais ne
**jamais** exposer le portail sur Internet en l'état.
2. **JWKS via le Service interne** (`authentik.auth.svc.cluster.local:9000`) : l'appel
serveur→serveur de Guacamole ne dépend pas de la résolution `lab.local` des pods.
L'issuer, lui, reste `http://auth.lab.local/...` (doit matcher le claim `iss` des
tokens émis via le navigateur).
3. **`EXTENSION_PRIORITY="*, openid"`** : garde le formulaire local (guacadmin) accessible
en plus du SSO — sans ça, redirection OIDC forcée et plus d'accès admin local.
4. **User `console` sans sudo** (volontaire) : le portail sert à observer/opérer léger.
L'administration passe par les comptes admin habituels, pas par Guacamole.
5. **Enregistrement des sessions** : possible (guacd + volume partagé) mais non configuré
— gap connu, à ajouter si le portail s'ouvre à d'autres utilisateurs.
6. La config Authentik (provider, app, utilisateurs) et les connexions Guacamole vivent
**en base, pas en IaC** — comme le Server Manager Satisfactory. Backup PG = gap connu.