Bitwarden self-hosted sur Kubernetes
Gestionnaire de mots de passe self-hosted, avec sauvegarde chiffrée et procédure de restauration testée en conditions réelles.
Le problème
Le besoin était un gestionnaire de mots de passe avec un contrôle total sur les données et sur la façon de les sauvegarder, plutôt que de dépendre d'une offre hébergée.
Options envisagées et écartées
Bitwarden Cloud, l'offre hébergée gratuite ou payante, a été écartée au profit d'un déploiement self-hosted. Il ne s'agissait pas d'une exigence de conformité. La volonté était surtout de garder la main sur l'infrastructure : définir sa propre stratégie de sauvegarde, chiffrer les backups à sa façon, et ne dépendre d'aucun tiers pour la disponibilité du service.
Architecture
Ingress NGINX (8080 / 4444)
|
v
Bitwarden (chart Helm officiel)
|
+-----------+-----------+
| |
local-path-provisioner Secrets Kubernetes (x5)
(PVC, stockage local) custom-secret, minio/s3
discord-webhook, gpg-public-key
|
v
CronJob de sauvegarde (db-backup.sh)
|
v
Chiffrement GPG (Ed25519 + RSA 4096)
|
v
S3 OVH (s3.rbx.io.cloud.ovh.net)
|
v
Notification Discord (webhook)
Le chart Helm officiel de Bitwarden (charts.bitwarden.com) gère l'application. Le stockage persistant passe par local-path-provisioner (Rancher), avec cinq secrets Kubernetes distincts pour séparer les identifiants applicatifs, les accès S3/MinIO, le webhook Discord et la clé publique GPG. Les certificats TLS sont générés en interne (OpenSSL, courbe EC P-256, validité 365 jours).
Décisions difficiles
La principale difficulté a été Helm lui-même : une première expérience sur cet outil, après avoir surtout manipulé des manifests Kubernetes bruts. Comprendre qu'un seul values.yaml vient injecter des valeurs dans l'ensemble des templates d'un chart a demandé un changement de façon de penser.
Le déploiement du CronJob de sauvegarde s'est aussi révélé être un piège potentiel : contrairement au reste de l'application, il n'est pas installé automatiquement par le helm install et doit être appliqué manuellement ensuite. Un oubli à cette étape signifie qu'aucune sauvegarde ne part, sans qu'aucune erreur ne le signale immédiatement.
La restauration n'est pas non plus un processus totalement automatisé : le script full-restore.sh demande les identifiants S3/MinIO et le chemin de la clé privée GPG, puis marque une pause volontaire pour laisser lancer un helm install en parallèle dans un second terminal, avant de reprendre après validation manuelle.
Vérification
La procédure a été testée en conditions réelles avec une simulation de sinistre complète : désinstallation totale de la release (helm uninstall), puis restauration depuis la sauvegarde chiffrée sur S3 avec full-restore.sh. La vérification finale a été une connexion à l'interface Bitwarden pour confirmer que les comptes et les coffres étaient bien restaurés, pas seulement que le pod avait redémarré.
Ce que je ferais autrement
Sur Helm, l'approche resterait la même, avec peut-être un premier projet plus petit pour apprendre l'outil avant de se lancer sur un chart aussi complet que celui de Bitwarden.
Sur l'opérationnel, le CronJob de sauvegarde ne devrait pas dépendre d'une étape manuelle après l'installation. L'intégrer directement au chart ou à un hook post-install réduirait un risque qui repose aujourd'hui sur la vigilance de la personne qui déploie.