Gestionnaire de secrets auto-hébergé : lequel choisir ?
Comparez OpenBao, Infisical, SOPS avec age, les credentials systemd et un fichier env durci pour choisir une solution adaptée à un seul VPS.
Ce qu’un gestionnaire de secrets auto-hébergé fait contrairement à un gestionnaire de mots de passe
Un gestionnaire de secrets auto-hébergé fournit des identifiants aux processus. Un gestionnaire de mots de passe les fournit aux personnes. Tout le reste découle de cette différence. Un gestionnaire de mots de passe est déverrouillé par un humain présent et attentif. Un gestionnaire de secrets doit fournir le mot de passe d’une base de données à votre application à 03:00, alors que personne n’est réveillé.
Les modes de panne sont différents, et cette différence est importante. Un gestionnaire de mots de passe verrouillé est une gêne : vous saisissez de nouveau le mot de passe maître. Un gestionnaire de secrets scellé provoque une interruption de service : chaque service qui redémarre alors qu’il est scellé démarre sans identifiants et reste arrêté. Utiliser Vaultwarden comme gestionnaire de mots de passe personnel résout bien le problème humain. Il ne résout pas le problème des machines, et il n’a jamais été conçu pour cela.
Pour un seul serveur, les options réalistes se répartissent en deux groupes. OpenBao et Infisical sont des services : une API, une base de données, TLS (transport layer security), une étape de connexion et un processus qu’il faut désormais maintenir actif. SOPS avec age, les credentials systemd et les secrets Docker sont des fichiers : chiffrés au repos, déchiffrés par un composant déjà actif, sans élément supplémentaire à superviser.
Voici la réponse directe. Pour une seule machine utilisée par une ou deux personnes, les options basées sur des fichiers sont généralement les plus adaptées. Un OpenBao que personne ne déscelle correctement et dont personne ne renouvelle les secrets est pire qu’un fichier d’environnement en mode 600, car il ajoute un composant mobile et une sauvegarde que vous configurerez mal, sans fournir de rotation que vous ne réalisiez pas déjà manuellement.
Un fichier d’environnement en mode 600 est-il suffisant ?
Souvent, oui. La menace visée est la lecture de votre mot de passe de base de données par un autre utilisateur du serveur. Les permissions Unix empêchent cela, avant même que le réseau soit opérationnel.
sudo install -d -m 750 -o root -g myapp /etc/myapp
sudo install -m 640 -o root -g myapp /dev/null /etc/myapp/env
sudoedit /etc/myapp/envVérifiez-le des deux côtés :
sudo -u myapp cat /etc/myapp/env
sudo -u nobody cat /etc/myapp/envLa première commande affiche le fichier. La seconde affiche cat: /etc/myapp/env: Permission denied, car nobody n’appartient pas au groupe myapp et le fichier ne possède aucun droit pour les autres utilisateurs. C’est tout le modèle de sécurité, et il est bien réel.
La fuite se produit ensuite. Une unité systemd avec EnvironmentFile= copie ces valeurs dans l’environnement du processus, qui est lisible.
[Service]
User=myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/local/bin/myappsudo cat /proc/$(pgrep -n myapp)/environ | tr '\0' '\n'Cette commande affiche vos secrets en clair, car /proc/<pid>/environ est lisible par root et par l’utilisateur sous lequel le processus s’exécute. Un outil de signalement des plantages qui joint l’environnement à un rapport voit la même chose. Il en va de même pour tout outil exécuté sous le même compte. C’est pourquoi retirer les secrets des agents IA commence par les retirer de l’environnement. Associez le fichier à un utilisateur de service dédié avec des privilèges limités afin que « l’utilisateur sous lequel le processus s’exécute » ne soit pas root.
SOPS avec age : chiffrer des secrets que vous pouvez valider dans git
SOPS (secrets operations) chiffre les valeurs d’un fichier YAML ou JSON et laisse les clés en clair. age est un outil de chiffrement léger qui vous fournit une seule paire de clés, sans serveur de clés. Ensemble, ils vous permettent de valider secrets.enc.yaml avec votre code, tandis que git diff indique toujours quel paramètre a changé, sans révéler sa nouvelle valeur.
age est fourni dans Ubuntu 24.04. SOPS ne l’est pas. Téléchargez donc .deb depuis la page des releases. La version 3.13.3 était la version actuelle en août 2026.
sudo apt update && sudo apt install -y age
curl -LO https://github.com/getsops/sops/releases/download/v3.13.3/sops_3.13.3_amd64.deb
sudo apt install -y ./sops_3.13.3_amd64.deb
sops --versionGénérez une paire de clés. age-keygen écrit la clé privée dans le fichier et affiche la clé publique. Vous verrez donc une ligne qui commence par Public key: age1....
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
chmod 600 ~/.config/sops/age/keys.txt
age-keygen -y ~/.config/sops/age/keys.txtPlacez la clé publique dans .sops.yaml à la racine du dépôt. Vous n’aurez ainsi jamais besoin de mémoriser le destinataire sur la ligne de commande.
creation_rules:
- age: age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23csops encrypt secrets.yaml > secrets.enc.yaml
sops decrypt secrets.enc.yamlUne règle sans path_regex correspond à tous les fichiers. C’est ce qu’il faut au début. Si vous en ajoutez une plus tard, écrivez-la pour qu’elle corresponde au fichier transmis à sops, car les règles sont comparées au chemin d’entrée, et non au fichier vers lequel vous redirigez la sortie.
À l’exécution, transmettez les valeurs à un seul processus, et à aucun autre :
sops exec-env secrets.enc.yaml './myapp'sops exec-env déchiffre les valeurs en mémoire et les définit dans l’environnement du processus enfant. Aucun texte en clair n’est donc écrit sur le disque. La réserve concernant l’environnement, présentée dans la section précédente, s’applique toujours à cet enfant.
Deux points posent souvent problème. Sous systemd, l’erreur Failed to get the data key required to decrypt the SOPS file signifie presque toujours que SOPS a cherché dans le mauvais répertoire personnel, car une unité n’hérite pas de votre HOME. Définissez explicitement le chemin avec Environment=SOPS_AGE_KEY_FILE=/etc/sops/age.txt dans l’unité. Par ailleurs, la modification de .sops.yaml ne rechiffre rien de ce qui existe déjà : l’ajout de la clé publique d’un collègue ne concerne que les nouveaux fichiers. Exécutez donc sops updatekeys secrets.enc.yaml sur chaque fichier existant. Si votre configuration passe déjà par Ansible, chiffrer les mêmes valeurs avec Ansible Vault permet d’obtenir le même résultat sans ajouter un second outil.
Identifiants d’authentification systemd : des secrets qui n’atteignent jamais l’environnement
Ubuntu 24.04 fournit systemd 255, vous n’avez donc rien à installer. systemd-creds chiffre un secret sur l’hôte, puis systemd le déchiffre dans un répertoire privé que seul le service concerné peut lire.
sudo systemd-creds setup
sudo install -d -m 700 /etc/myapp
echo -n 'hunter2' | sudo systemd-creds encrypt --name=db_password - /etc/myapp/db_password.cred[Service]
User=myapp
LoadCredentialEncrypted=db_password:/etc/myapp/db_password.cred
ExecStart=/usr/local/bin/myappLe service lit la valeur dans un fichier nommé db_password, situé dans le répertoire indiqué par $CREDENTIALS_DIRECTORY. La valeur ne se trouve pas dans l’environnement. /proc/<pid>/environ n’affiche donc rien d’utile, et le texte en clair n’est jamais écrit dans le système de fichiers racine.
Vérifiez que le fichier peut être déchiffré avant de le référencer dans une unité :
sudo systemd-creds decrypt /etc/myapp/db_password.cred -Identifiez la clé qui a servi au chiffrement, car elle détermine l’utilité de votre sauvegarde. La valeur par défaut de --with-key=auto utilise la puce TPM2 (trusted platform module version 2) lorsqu’elle est présente et utilisable, et la clé de l’hôte dans le cas contraire. La plupart des instances VPS ne disposent pas de TPM2.
systemd-analyze has-tpm2no signifie que la clé de l’hôte a été utilisée. Cette clé se trouve dans /var/lib/systemd/credential.secret, lisible uniquement par root. Restaurez db_password.cred sur un VPS neuf sans ce fichier : plus rien ne pourra le déchiffrer. Copiez credential.secret dans la même sauvegarde ou conservez le texte en clair dans un emplacement auquel vous pourrez toujours accéder.
Secrets Docker : fichiers sous /run/secrets
Compose lit un fichier sur l’hôte et le monte dans le conteneur à l’emplacement /run/secrets/<name>.
services:
app:
image: myapp:latest
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txtdocker compose exec app cat /run/secrets/db_password
docker compose exec app env | grep -i passwordLa première commande affiche le secret. La seconde affiche uniquement DB_PASSWORD_FILE=/run/secrets/db_password, ce qui est précisément l’objectif : la valeur n’est jamais présente dans l’environnement du conteneur et n’apparaît donc pas dans la sortie de docker inspect. De nombreuses images officielles utilisent déjà ce fonctionnement, et l’image Postgres lit POSTGRES_PASSWORD_FILE exactement de cette manière.
Soyez clair sur ce point. En dehors du mode Swarm, il n’y a aucun chiffrement, à aucun niveau : ./db_password.txt est un fichier en clair sur l’hôte, et sa seule protection repose sur ses permissions et son propriétaire. Définissez vous-même ces deux éléments, car Compose montera sans problème un fichier lisible par tous. La comparaison plus complète avec la solution simplifiée env_file figure dans le guide sur les fichiers env et les secrets de Compose.
Ce que coûtent réellement OpenBao et Vault
OpenBao est le fork de HashiCorp Vault maintenu par la Linux Foundation. Il a été lancé après que HashiCorp a placé Vault sous la Business Source License en 2023. OpenBao reste sous MPL 2.0 (Mozilla Public License). La version 2.6.2 était la version actuelle en août 2026. Presque tout ce qui suit s’applique aussi à Vault, car le fork a conservé la même interface de commandes.
docker pull docker.io/openbao/openbaoLes paquets Debian et Ubuntu sont disponibles sur la page de téléchargement d’OpenBao si vous préférez gérer les mises à niveau avec apt. Le serveur a besoin d’un fichier de configuration contenant un listener et un backend de stockage :
listener "tcp" {
address = "127.0.0.1:8200"
tls_cert_file = "/path/to/full-chain.pem"
tls_key_file = "/path/to/private-key.pem"
}
storage "raft" {
path = "/path/to/raft/data"
node_id = "raft_node_1"
}Démarrez-le ensuite une fois :
bao operator initPar défaut, cela divise la clé root en 5 parts et en exige 3 pour le unseal. Ce sont les flags -key-shares et -key-threshold. OpenBao affiche les parts et le token root initial une seule fois, puis ne les affiche plus jamais.
C’est le point que la plupart des comparatifs ignorent. Un serveur redémarré est un serveur sealed. OpenBao conserve la clé root uniquement en mémoire. Après un redémarrage, il ne peut donc plus déchiffrer son propre stockage tant qu’une personne ne lui a pas fourni le seuil de parts requis. Une mise à jour du kernel ou un kill provoqué par un manque de mémoire se termine donc par un serveur sealed et des applications qui ne peuvent plus se connecter.
Sur un VPS utilisé par une seule personne, le partage de Shamir ne protège rien, car les 5 parts finissent dans le même password manager, qui appartient à cette même personne. L’auto-unseal déplace la clé vers un équipement ou un service de confiance. Dans un grand cloud, il s’agit d’un service de gestion de clés managé. Sur votre VPS, il s’agit généralement d’un fichier de clé stocké sur le même disque que les données qu’il protège. Cela réduit réellement la sécurité, en échange d’un serveur qui revient automatiquement après un redémarrage. Faites ce choix en connaissance de cause et notez la solution retenue.
Infisical : une interface, une base de données et une clé principale que vous devez conserver
Infisical est une plateforme de gestion des secrets avec une interface web, des projets, des environnements et un contrôle d’accès par utilisateur. Son auto-hébergement avec Compose est rapide :
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
docker compose -f docker-compose.prod.yml up -dModifiez .env avant d’exécuter la dernière commande. Deux valeurs doivent être les vôtres, et l’une d’elles ne doit plus jamais changer ensuite :
openssl rand -hex 16
openssl rand -base64 32La première est ENCRYPTION_KEY, une chaîne hexadécimale de 16 octets. Il s’agit de la clé utilisée pour chiffrer vos secrets dans PostgreSQL. Si vous la perdez, une sauvegarde parfaite de la base de données devient un ensemble de textes chiffrés. Si vous la modifiez sur une instance en fonctionnement, les secrets existants ne pourront plus être déchiffrés. La seconde est AUTH_SECRET, une chaîne base64 de 32 octets utilisée pour les sessions. SITE_URL doit être l’URL absolue que vous utiliserez réellement pour accéder au service, protocole inclus. Sinon, la redirection après la connexion échoue.
Infisical convient mieux qu’OpenBao lorsque votre besoin principal concerne les utilisateurs : une interface web pour une petite équipe et une séparation entre les environnements, plutôt que des identifiants de base de données qui expirent automatiquement. En contrepartie, vous devez gérer PostgreSQL, Redis et un certificat TLS, et assurer leur mise à jour et leur sauvegarde.
Que se passe-t-il lorsque le service de secrets est indisponible et que votre application redémarre
Cette question détermine si un service de secrets peut fonctionner sur un serveur unique. Les fichiers sont lisibles avant le démarrage du réseau. Ce n’est pas le cas d’un service.
Redémarrez le serveur : votre application et OpenBao démarrent au même moment. L’application demande le mot de passe de sa base de données, OpenBao est encore scellé, la requête échoue et systemd redémarre l’application en boucle jusqu’à ce qu’un administrateur saisisse les fragments de déscellement. Rien n’est défectueux. Mais rien ne fonctionne non plus.
Il existe deux méthodes fiables. Ordonnez les unités et laissez l’application réessayer : After= le service de secrets, avec Restart=on-failure et un RestartSec= suffisamment long pour éviter de marteler l’API. Ou récupérez le secret lors du déploiement plutôt qu’au démarrage : écrivez-le dans un fichier avec le mode 600 ou dans un identifiant systemd, afin que le système en fonctionnement dépende d’un fichier plutôt que d’une API.
L’expiration du token pose le même problème, mais sur une durée plus longue. Les tokens et les leases OpenBao ont une durée de vie. Un processus qui s’exécute longtemps sans renouveler son accès le perd à un moment qui n’a aucun rapport avec un déploiement. Cette panne est déroutante précisément parce que rien n’a changé ce jour-là.
Sauvegarder le magasin lui-même
Chaque option présentée ici possède une clé, et une sauvegarde sans cette clé ne sert à rien. Notez où la vôtre se trouve.
Pour un fichier d’environnement, le fichier constitue le secret : la sauvegarde doit donc être chiffrée. Avec SOPS, le fichier chiffré peut être placé n’importe où, y compris dans un emplacement public. La clé privée age située à ~/.config/sops/age/keys.txt est l’élément à ne surtout pas perdre. Pour les credentials systemd, sauvegardez /var/lib/systemd/credential.secret avec les fichiers .cred. Avec Infisical, effectuez un dump PostgreSQL et stockez ENCRYPTION_KEY dans un emplacement distinct.
OpenBao avec un stockage raft crée son propre snapshot :
bao operator raft snapshot save backup.snap
bao operator raft snapshot restore backup.snapLe snapshot contient votre stockage chiffré. Sa restauration sur un serveur vierge nécessite donc toujours les parts d’unseal de bao operator init. Une tâche nocturne qui copie les snapshots vers un stockage objet alors que les parts ne sont stockées nulle part ne constitue pas une sauvegarde. Testez la restauration sur un VPS jetable avant de vous y fier.
Journalisation d’audit : qui a lu quel secret
Les fichiers ne fournissent aucune trace d’audit. Le mode et le propriétaire indiquent qui pourrait lire le secret. Ils n’indiquent jamais qui l’a effectivement lu. auditd avec une surveillance du chemin est le substitut le plus proche, mais cela indique qu’un fichier a été ouvert, pas quelle valeur a été utilisée.
OpenBao journalise chaque requête dans un périphérique d’audit que vous activez explicitement :
bao audit enable file file_path=/var/log/openbao_audit.logDeux faits concernant ce journal modifient la façon dont vous exploitez le serveur. La plupart des chaînes présentes dans les requêtes et les réponses sont hachées avec HMAC-SHA256 et un sel. Vous pouvez donc comparer au journal une valeur que vous connaissez déjà, sans que le journal contienne lui-même la valeur en clair. Les entiers et les booléens sont écrits en clair. Un secret numérique ne bénéficie donc d’aucune protection grâce à ce hachage.
Vient ensuite le piège opérationnel : OpenBao ne répond plus aux requêtes lorsqu’aucun périphérique d’audit activé ne peut les enregistrer. Un périphérique qui échoue de manière bloquante fait attendre les requêtes jusqu’à la résolution du problème. Un disque plein sur /var/log met donc l’API de secrets hors service, conformément à la conception du système. Réservez un espace distinct au journal d’audit et ajoutez une règle logrotate dès le premier jour, pas après la première panne.
Quel gestionnaire de secrets auto-hébergé devez-vous utiliser ?
Comptez les machines et les personnes, puis choisissez.
- Une machine, une personne : utilisez un fichier d’environnement en mode 600, détenu par root et lisible par un utilisateur de service. Ajoutez les credentials systemd lorsque vous voulez que la valeur ne soit pas présente dans l’environnement du processus.
- Une machine, de deux à cinq personnes, avec une configuration déjà stockée dans git : utilisez SOPS avec age. Chaque personne possède une paire de clés, et
.sops.yamlrépertorie toutes les clés publiques autorisées à déchiffrer. - Plusieurs machines, un dépôt de configuration, sans besoin de credentials qui expirent : utilisez toujours SOPS avec age, avec une clé destinataire par hôte. Ainsi, une clé d’hôte volée ne permet de déchiffrer que les fichiers de cet hôte.
- Plusieurs machines et plusieurs équipes qui ont réellement besoin de credentials de base de données avec une durée de validité, ainsi que d’une piste d’audit effectivement consultée : utilisez OpenBao et prévoyez une heure par mois de temps opérateur dans le budget pour les opérations d’unseal et les exercices de restauration.
La règle commune aux quatre cas est la même. Utilisez la solution la plus simple qui répond à une exigence que vous pouvez énoncer clairement, car un gestionnaire de secrets indisponible est impossible à distinguer d’un gestionnaire de secrets vide.
FAQ
Un gestionnaire de secrets auto-hébergé est-il utile pour un seul VPS ?
En général, non, si vous parlez d’un service comme OpenBao ou Infisical. Sur une seule machine utilisée par une ou deux personnes, un fichier d’environnement en mode 600 ou un identifiant chiffré géré par systemd offre la même protection contre un autre utilisateur local, sans étape d’unseal ni service supplémentaire à maintenir à jour. Un service de secrets devient réellement utile lorsque vous avez plusieurs machines et plusieurs personnes, ou lorsque vous avez besoin que les identifiants expirent sans que personne doive les renouveler manuellement.
Quelle est la différence entre un gestionnaire de mots de passe et un gestionnaire de secrets ?
Un gestionnaire de mots de passe stocke les identifiants saisis par une personne, qui le déverrouille lorsqu’elle est présente. Un gestionnaire de secrets fournit des identifiants aux processus. Il doit donc fonctionner à 03:00 sans personne pour le surveiller. C’est la conséquence principale : un gestionnaire de mots de passe verrouillé vous demande de saisir à nouveau un mot de passe maître, tandis qu’un gestionnaire de secrets scellé arrête chaque service qui redémarre alors qu’il est scellé.
Que deviennent mes applications si OpenBao est scellé après un redémarrage ?
Elles ne peuvent pas récupérer leurs secrets. Elles échouent donc au démarrage, et systemd les redémarre en boucle jusqu’à ce qu’une personne fournisse le seuil de déscellement, qui est de 3 parts sur 5 par défaut. OpenBao conserve la clé root uniquement en mémoire. Chaque redémarrage le scelle donc à nouveau. Vous pouvez activer l’auto-unseal, en acceptant que, sur un VPS unique, la clé de déscellement se retrouve sur le même disque que les données. Vous pouvez aussi générer les secrets dans un fichier au moment du déploiement, afin que le démarrage ne dépende jamais de l’API.
Puis-je valider des fichiers chiffrés avec SOPS dans un dépôt public ?
Les valeurs sont chiffrées. Elles sont donc protégées contre toute personne qui ne possède pas la clé privée age. Les clés, elles, ne sont pas chiffrées : un lecteur peut voir que vous détenez STRIPE_SECRET_KEY et SMTP_PASSWORD, ainsi que la fréquence de modification de chacune. Ces métadonnées sont acceptables pour la plupart des projets, mais pas pour certains. Conservez la clé privée age hors du dépôt et exécutez sops updatekeys sur chaque fichier existant lorsque vous ajoutez ou supprimez un destinataire.