Convention comptes et service accounts
Standards de création, naming et gestion des comptes pour chaque couche du homelab.
Pour la politique credentials (mots de passe, rotation, stockage) : politique.md. Pour le hardening technique par host : hardening.md.
Principe général
Chaque service a 3 niveaux d'acces :
Règle d'or : si un humain se connecte, c'est gabins. Si une machine se connecte, c'est svc-<consumer>. Root ne sert qu'en urgence.
La règle était documentée et appliquée à moitié. Mesure du jour :
| Système | Comptes de service | Conformes |
|---|---|---|
| Proxmox VE | 5 | 0 |
| PBS | 4 | 2 (svc-pve-backup, svc-homepage-monitor) |
| Unix (penny, galahad, lancelot) | 0 | — (l'automatisation tourne en root) |
Les comptes non conformes sont déclarés en dérogation datée dans
scripts/comptes-convention-check.sh. Au 2026-11-04, la liste en compte cinq :
homepage@pve, terraform@pve, pulse-monitor@pam, pulse@pbs,
pulse-monitor@pbs. homelable@pve (retiré le 2026-11-03 avec Homelable) et
pulse@pve n'y figurent plus.
Ils ne sont pas renommés tout de suite, et c'est délibéré : chaque renommage oblige à régénérer un jeton et à mettre à jour son consommateur. Un jeton changé et un consommateur oublié ne produisent aucune erreur — juste un widget vide ou un plan Terraform qui ment. On migre au fil de l'eau, quand on touche déjà au consommateur.
Deux points à revoir en priorité : pulse possède deux comptes pour un seul
consommateur (pulse@pve et pulse-monitor@pam), et le second vit dans le
royaume pam — donc adossé à un compte Unix sur les nœuds — alors qu'un jeton
API suffirait.
Une sonde quotidienne vérifie désormais la règle (comptes-convention-check,
04:10). Elle ne crie pas sur les dérogations déclarées : elle crie sur ce qui
apparaît en plus. Une règle que rien ne vérifie n'est pas une règle, c'est
un souhait — la dérive y est invisible et gratuite, et c'est ainsi que
homepage@pve a traîné « à migrer » sans que personne sache depuis quand.
Matrice par type de système
Machines physiques (penny, galahad, lancelot)
| Compte | Naming | Auth | Usage |
|---|---|---|---|
| root (OS) | root | Password fort (Vault) + SSH interdit (PermitRootLogin no) | Break-glass via console physique ou sudo -i |
| Admin perso | gabins | Clé SSH Ed25519 + sudo NOPASSWD | Quotidien SSH, administration |
| Service | N/A | Pas de service account OS — les services tournent en containers | — |
SSH : port custom (2806/2807/2808), clé uniquement, MaxAuthTries 3.
Root SSH : toujours no. Acces root = ssh gabins@host puis sudo -i.
Tailscale SSH : mode check (MFA navigateur) quand activé.
Proxmox VE (galahad, lancelot)
| Compte | Naming | Auth | Usage |
|---|---|---|---|
| root@pam | root@pam | Password fort (Vault) | Break-glass, opérations cluster (pvecm) |
| Admin perso | gabins@authelia | OIDC Authelia (two_factor) | Quotidien UI PVE |
| Service Homepage | homepage@pve!homepage | Token API (PVEAuditor) | Widget Homepage |
| Service futur | svc-<consumer>@pve!<tokenname> | Token API (rôle minimum) | Automation |
root@pam : inevitable sur Proxmox (opérations cluster, API interne). Garder actif, password fort, ne jamais l'utiliser pour le login UI quotidien.
Realm : @authelia pour humains (OIDC SSO), @pve pour service accounts (tokens API natifs).
Authelia (SSO / IdP)
| Compte | Naming | Auth | Usage |
|---|---|---|---|
| Admin/user | gabins | Password Argon2id + TOTP + WebAuthn FIDO2 | Source de vérité auth |
| Clients OIDC | client_id: <service> | Client secret (PBKDF2 hash dans config, plain dans Vault) | SSO pour Proxmox, Grafana, PBS, Pulse, Forgejo, Outline |
Pas de root : Authelia n'a pas de concept root. gabins est le seul user, protégé par 2FA.
Pas de service account : les clients OIDC sont des "applications", pas des users.
Proxmox Backup Server (LXC 103)
| Compte | Naming | Auth | Usage |
|---|---|---|---|
| root@pam | root@pam | Password fort (Vault) | Break-glass |
| Admin perso | gabins@pbs | Password + TOTP | Quotidien UI PBS |
| Service PVE backup | svc-pve-backup@pbs!pve | Token API (DatastorePowerUser) | PVE Datacenter → PBS |
| Service futur | svc-<consumer>@pbs!<tokenname> | Token API (rôle minimum) | Automation future |
Realm : @pbs pour tout (realm interne PBS, pas PAM). Évite de créer des users Linux inutiles.
root@pam : garder actif (requis pour certaines opérations CLI proxmox-backup-manager).
Containers Docker (penny)
| Compte | Naming | Auth | Usage |
|---|---|---|---|
| Service inter-container | N/A | Pas de comptes — Docker socket-proxy limité l'API | — |
Docker n'a pas de comptes : l'isolation est au niveau réseau (bridge proxy / socket) + capabilities (cap_drop: ALL).
LXC applicatifs (dns-failover, vault, logs)
| Compte | Naming | Auth | Usage |
|---|---|---|---|
| root (LXC) | root | Password fort (Vault) ou login désactivé | pct enter depuis l'hyperviseur |
| Admin perso | gabins | Clé SSH Ed25519 | SSH direct si besoin debug |
| Service app | Dépend de l'app | — | — |
Unprivileged : toujours sauf contrainte technique (cf. PBS LXC 103 si le bug tar persiste).
SSH dans les LXC : optionnel. pct enter depuis l'hyperviseur est souvent suffisant. SSH direct utile pour penny → LXC (scripts backup, monitoring).
Services web (Grafana, AdGuard, Homepage)
| Service | Admin perso | Service account | Break-glass |
|---|---|---|---|
| Grafana | gabins@authelia (OIDC, GrafanaAdmin) | N/A | Admin désactivé en DB (volontaire) |
| AdGuard | gabins (ForwardAuth Authelia) | N/A | bcrypt local gabins |
| Homepage | ForwardAuth Authelia (transparent) | Tokens API (PVE, PBS, Pulse, AdGuard, CrowdSec) dans .env | N/A |
| Vaultwarden | Master password + TOTP | N/A | Hors Authelia (pas de dépendance circulaire) |
Convention de naming
Comptes humains
<prenom><initiale_nom>
Exemple : gabins (Gabin S.)
- Un seul compte humain par personne, partout
- Jamais
admin,pi,user→ cibles de brute-force - Même login sur toutes les couches (SSH, Proxmox, Authelia, PBS, Grafana)
Service accounts
svc-<consumer>-<function>@<realm>
Exemples :
svc-pve-backup@pbs→ PVE qui backup vers PBSsvc-homepage@pve→ Homepage qui lit l'API PVE (actuel :homepage@pve, a migrer)svc-grafana-oidc→ client OIDC Grafana dans Authelia
Consumer = le service qui UTILISÉ le compte (pas le service qui l'HEBERGE).
Function = ce qu'il fait (backup, monitor, read, push).
Realm = scope d'auth (@pbs, @pve, @pam).
Tokens API
<user>!<tokenname>
Exemples :
svc-pve-backup@pbs!pve→ tokenpvedu service accountsvc-pve-backup@pbshomepage@pve!homepage→ tokenhomepagedu userhomepage@pve
Tokenname = court, decrit l'usage ou le consumer. Un user peut avoir plusieurs tokens (un par consumer différent, ou un par environnement).
Clients OIDC (Authelia)
client_id: <service-name>
Exemples : proxmox, grafana, pulse, forgejo
Pas de prefix svc- : les clients OIDC ne sont pas des "users" mais des "applications" dans le modèle Authelia.
Quand créer quoi — arbre de decision
Stockage dans Vaultwarden — convention
Chaque secret = 1 item Login dans Vaultwarden avec :
| Field standard | Contenu |
|---|---|
| Name | <Service> — <user> (<role/usage>) |
| URI | URL du service |
| Username | Login complet (svc-pve-backup@pbs!pve) |
| Password | Password ou token value |
| Folder | Homelab/<categorie> |
| Custom field | Contenu |
|---|---|
| Type | API Token, OIDC Client, User Password, SSH Key |
| Scope | Rôle + path (DatastorePowerUser on /datastore/main) |
| Used by | Service consumer (PVE Datacenter Storage 'pbs') |
| Created | Date ISO (2026-04-15) |
| Rotation | Période (12 months) |
| Next rotation | Date ISO (2027-04-15) |
Folders Vaultwarden :
Homelab/
├── Authelia/
│ ├── OIDC/ → client secrets (proxmox, grafana, pbs, pulse, forgejo, outline)
│ └── Internals/ → jwt, session, storage, hmac secrets
├── OS-Infra/
│ ├── SSH/ → cles SSH par machine
│ ├── Backup/ → PBS tokens, restic passwords, credentials Cloudflare R2
│ └── Break-glass/ → root@pam passwords (urgence)
└── Externals/ → Cloudflare, Tailscale, ntfy
Le backend B2 était décommissionné depuis le 2026-05-29 après la migration vers Cloudflare R2, mais la clé applicative était restée active — trois mois d'exposition côté fournisseur sur un service plus utilisé.
Le compte Backblaze a été supprimé dans son intégralité le 2026-08-26. Il n'y
a donc plus ni clé à révoquer, ni entrée à retirer : l'exposition est close à la
source plutôt que gérée. Vérifié côté homelab le même jour — plus aucune variable
B2_* sur penny, ni dans .restic-env, ni dans la configuration rclone.
La leçon vaut au-delà de ce cas : décommissionner un backend et révoquer ses identifiants sont deux gestes distincts, et le second est celui qu'on oublie parce que rien ne casse quand il manque.
Rotation
| Type | Période | Procédure |
|---|---|---|
| Passwords humains | A la compromission | Changer + update Vault |
| Tokens API | 12 mois max | Delete token + regenerate + update consumer + update Vault |
| Clients OIDC | 12 mois max | openssl rand -hex 32 + hash pbkdf2 + update Authelia + update service + update Vault |
| SSH keys | Par appareil, a la compromission | ssh-keygen + deploy + revoke ancienne |
| Break-glass (root) | 24 mois max | passwd + update Vault |
Voir aussi
- Politique credentials — modèle de menace, mots de passe, inventaire secrets
- Hardening — mesures techniques par couche
- Break-glass — procédure de reconstruction d'urgence