Chapitre 19 / 39

Le coffre-fort

Le coffre-fort est la source de vérité des comptes et des clés de Sodimo. Chaque mot de passe SaaS, chaque clé SSH privée, chaque JSON de compte de service, chaque token d’API tiers — un seul coffre, un seul chemin de récupération, un seul artefact de passation. Si l’équipe demande un jour « où est l’identifiant pour X ? », la réponse est toujours le coffre-fort. Si la réponse est autre chose, le coffre-fort est faux et doit être mis à jour.

Statut : Planifié — s’active le jour où le Framework Desktop est installé en rack. En attendant, les identifiants vivent dans le 1Password de Tom et sur papier ; la migration vers Vaultwarden fait partie de la checklist de mise en service du harness.


Pourquoi Vaultwarden

Le choix est Vaultwarden — la réimplémentation en Rust du serveur Bitwarden, épinglée à un tag upstream spécifique et exécutée en Podman Quadlet sur le harness. Adoptée, non forkée, conformément au Pivot 2 (la outillage de commodité s’adopte comme quadlet épinglé).

Trois candidats ont été examinés :

  • Bitwarden-server (upstream). Lourd — Microsoft SQL Server, plusieurs services, quadlet non trivial. Surdimensionné pour une équipe de cinq. Écarté pour sa lourdeur.
  • 1Password for Teams. La voie de moindre résistance à court terme, mais c’est un compte SaaS qui vivrait hors du harness, hors de Cloudflare Access, et hors du schéma de sauvegarde. À la passation, ce serait le seul identifiant que l’équipe ne pourrait pas gérer en autonomie. Écarté pour des raisons de souveraineté — le coffre-fort lui-même ne peut pas être un compte SaaS dont Sodimo peut se voir verrouiller l’accès.
  • Vaultwarden. Binaire Rust unique, backend SQLite ou Postgres, configuration propre par variables d’environnement, compatibilité native avec les clients Bitwarden (web, extension navigateur, iOS, Android, CLI). S’inscrit exactement dans le schéma d’un seul dépôt de quadlets. Retenu.

Version épinglée selon le Principe 1 : un tag vaultwarden/server:1.x.y spécifique, engagé dans le dépôt sodimo/harness. Le calendrier de mises à jour de Sodimo, pas celui de l’upstream.


Déploiement

Un seul quadlet et son volume de données. Le déploiement suit le même schéma que tous les autres services du chapitre Le harness.

  • vaultwarden — le conteneur serveur, tag épinglé. Le fichier d’environnement /etc/sodimo/secrets/vaultwarden.env porte le token admin, les identifiants du relais SMTP pour les emails de réinitialisation de mot de passe, et le drapeau de désactivation des inscriptions.
  • vaultwarden-data — un volume nommé sur le LVM chiffré LUKS. Contient la base de données SQLite, les blobs de pièces jointes et les clés RSA que Vaultwarden utilise pour signer les tokens clients.

Le backend est SQLite. Une équipe de cinq avec un trafic modéré dans le coffre-fort ne justifie pas Postgres ; la base de données en fichier unique de SQLite simplifie le schéma de sauvegarde (un seul fichier à snapshoter) et supprime une pièce mobile. Si l’équipe dépasse vingt membres ou si le volume de pièces jointes devient conséquent, la migration vers le Postgres existant openwebui-db est documentée dans le guide de migration upstream Vaultwarden — une opération ponctuelle, pas une préoccupation du premier jour.

Caddy expose Vaultwarden en TLS avec le certificat émis par Cloudflare, même schéma qu’OpenWebUI et Piler. L’URL est vault.sodimo.eu.

L’accès au service emprunte deux chemins :

  • Les employés accèdent à vault.sodimo.eu via Cloudflare Tunnel + Cloudflare Access, authentifiés via le fournisseur d’identité Google Workspace. Même forme que tout autre service on-prem accessible aux employés (voir les chapitres Réseau et Cloudflare). Tailscale n’est pas requis ; un ordinateur avec un accès Google suffit.
  • Tom accède à Vaultwarden de la même façon que les employés — CF Tunnel + CF Access — et dispose aussi d’un chemin Tailscale pour la récupération administrative quand CF est inaccessible. Tailscale est le chemin de secours, pas le chemin quotidien.

Ce qui est stocké

Chaque identifiant dont Sodimo dépend va dans l’une des quatre collections Vaultwarden :

Mots de passe SaaS. Admin Cloudflare, admin Google Workspace, propriétaire de l’organisation GitHub, console Anthropic, login Fedora du Framework Desktop, portail FAI, admin Synology NAS, VPN Sodiwin, manager WhatsApp Business, Stripe (si jamais activé). Chaque entrée comporte l’URL, le nom d’utilisateur, le mot de passe, le seed TOTP le cas échéant, et une courte note en texte libre expliquant à quoi sert le compte et qui l’a créé.

Clés SSH privées. Clés de Tom pour le harness, clé de Rani (quand elle sera émise), clé de Paul (quand elle sera émise), une clé de secours pour le Framework Desktop stockée en pièce jointe dans un élément de récupération verrouillé. Les clés publiques vivent dans les fichiers authorized_keys concernés du dépôt harness — seules les clés privées sont dans le coffre-fort.

JSONs de comptes de service. JSON du compte de service Google Workspace pour Cloudflare Access, tokens API Cloudflare (scopés par usage — un pour cloudflared, un pour la CI, un pour l’admin manuel), clés de déploiement GitHub Actions, identifiants WhatsApp Cloud API, toutes futures clés d’intégration tiers. Chaque JSON est stocké en pièce jointe sur un élément nommé svc-<service>-<purpose>.

Clés API pour les intégrations tiers. Clé API Anthropic, clé OpenAI si jamais provisionnée, clé Tavily, clé Mistral OCR, tout autre fournisseur adjacent aux LLM. Ils ont leur propre collection parce qu’ils tournent plus fréquemment que les mots de passe SaaS et nécessitent un suivi de rotation par clé.

Rien ne vit hors du coffre-fort, à l’exception des trois identifiants nécessaires pour atteindre le coffre-fort lui-même — voir la section Récupération ci-dessous.


Calendrier de rotation

La rotation est par classe, pilotée par la nature de l’identifiant plutôt que par une date calendaire. Un rappel mensuel passe en revue le coffre-fort et remonte tout élément dépassant la cadence de sa classe.

  • Clés SSH — 90 jours. Tom, Rani, Paul. Rotation d’urgence en cas de perte d’ordinateur. Les clés publiques dans le dépôt harness sont mises à jour dans le même commit.
  • Mots de passe admin (Cloudflare, Google Workspace, organisation GitHub) — 180 jours. Chacun avec un TOTP lié à l’authentificateur du téléphone professionnel. La rotation est planifiée, pas réactive.
  • Tokens de service (tokens API Cloudflare, clés de déploiement GitHub, clé API Anthropic) — au départ d’un employé, et tous les 365 jours sinon. La rotation annuelle est une contrainte pour auditer si le token est encore utilisé.
  • Token admin Vaultwarden — 365 jours ou en cas de suspicion de compromission.
  • Éléments de secours (clé de récupération, SSH d’urgence, combinaison du coffre physique) — jamais tournés automatiquement. Tournés uniquement sur un incident précis — perte du coffre physique du bureau, perte de l’enveloppe de récupération, départ du seul opérateur maître du coffre-fort.

Les événements de rotation sont enregistrés comme une ligne dans le tableau de bord Cloudflare — run_ledger comporte une entrée surface=vault_rotation par rotation, de sorte que la piste d’audit vit dans la même table D1 que toutes les autres exécutions IA.


Modèle d’accès

Quatre rôles, des droits distincts.

  • Opérateur maître (Tom, transmis à Michel à la passation). Détient le token admin Vaultwarden dans une enveloppe papier dans le coffre physique du bureau. Peut créer, supprimer et réattribuer des collections. Un seul humain à la fois.
  • Rédacteurs (Tom, Paul à la passation). Lecture et écriture complètes sur toutes les collections. Peuvent ajouter, modifier et supprimer des éléments mais ne peuvent pas modifier l’appartenance aux collections.
  • Lecteurs (Rani, Jack, futurs employés). Accès en lecture seule par collection, limité à ce que leur rôle exige. Rani accède aux entrées SaaS liées au CRM ; Jack aux entrées réseau et FAI ; les clés API LLM sont réservées aux rédacteurs.
  • Comptes de service. Pas de login Vaultwarden humain. Les services qui ont besoin d’un identifiant à l’exécution le lisent depuis /etc/sodimo/secrets/<service>.env sur le harness — ces fichiers d’environnement sont hydratés au déploiement depuis le coffre-fort via un script Vaultwarden-CLI (bw) qui tourne une fois à la mise en service et une fois après chaque rotation. Pas de session Vaultwarden persistante sur la machine.

L’authentification se fait par e-mail + mot de passe maître + TOTP. Les e-mails sont des adresses Google Workspace, donc la posture SSO Google Workspace s’hérite — un compte Workspace désactivé ne peut pas non plus se connecter à Vaultwarden.


Récupération

Le coffre-fort est le seul système qui ne peut pas être récupéré depuis le coffre-fort. Le chemin de récupération est papier, délibéré et répété.

Trois éléments vivent dans une seule enveloppe scellée dans le coffre physique du bureau :

  1. Token admin Vaultwarden — le token d’amorçage qui donne accès maître même si le dispositif TOTP du compte admin est perdu.
  2. Phrase de récupération du compte opérateur maître — imprimée à la mise en service de Vaultwarden, jamais stockée numériquement.
  3. Combinaison du coffre + mot de passe BIOS du Framework Desktop + passphrase LUKS — les identifiants de la couche physique nécessaires pour accéder aux bits où est stocké le coffre-fort.

L’ouverture de l’enveloppe est un événement journalisé — un message Signal à Michel et Tom avant et après, enregistré dans le même run_ledger avec surface=vault_recovery. L’enveloppe est rescellée et rangée après usage ; les éléments sont tournés dans les sept jours suivant l’ouverture.

Un exercice annuel à blanc répète la récupération : faire comme si Tom était injoignable, demander à Michel d’ouvrir l’enveloppe, remonter Vaultwarden depuis la sauvegarde sur un ordinateur vierge, vérifier l’accès. Si l’exercice échoue, la répétition est l’incident et le correctif est livré dans la semaine.


Sauvegarde

Sauvegarde à deux niveaux, même schéma que le reste des données du harness.

  • Nuit, vers le NAS. Le fichier SQLite de Vaultwarden et le répertoire attachments/ sont snapshotés vers SAUVE_DISK sur le réseau 192.168.0.x à 02:15, quinze minutes avant le dump Sodiwin. Rétention : 30 snapshots quotidiens, glissants.
  • Hebdomadaire, vers Cloudflare R2. Chaque dimanche à 03:00, le dernier snapshot NAS est chiffré avec une clé symétrique basée sur age (la clé elle-même est dans le coffre-fort — la sauvegarde est illisible sans le coffre-fort, qui se récupère depuis le papier) et chargé dans le bucket R2 sodimo-backups. Rétention : 12 snapshots hebdomadaires, glissants.

La boucle est délibérée : les sauvegardes sont chiffrées avec une clé du coffre-fort, le coffre-fort se récupère depuis le papier, le papier est dans le coffre physique. Aucune perte d’un seul support n’est fatale.


Note de passation

Quand l’engagement se termine, le prochain opérateur trouve le coffre-fort en lisant ce chapitre et le document de passation dans le coffre physique. Le document de passation liste :

  • L’emplacement physique du coffre physique du bureau et sa combinaison (enveloppe scellée — ouverte uniquement à la passation).
  • Le token admin Vaultwarden et la phrase de récupération (deuxième enveloppe scellée, à l’intérieur du coffre).
  • L’URL vault.sodimo.eu et la politique Cloudflare Access qui la protège.
  • Le rituel de première connexion étape par étape : ouvrir l’enveloppe, se connecter avec le compte maître, vérifier l’accès aux quatre collections, tourner le token admin, resceller et ranger l’enveloppe avec le nouveau token.

La passation n’est pas un fichier sur un ordinateur — c’est un rituel physique. Le harness est reproductible depuis un dépôt git ; le coffre-fort est reproductible depuis le coffre physique. Les deux sont nécessaires ; ni l’un ni l’autre n’est suffisant seul.

Si le prochain opérateur ne trouve pas le coffre physique, l’enveloppe ou le mot de passe maître — l’engagement a échoué le test de passation. C’est le critère de succès explicite de ce chapitre.