Aller au contenu
Sécurité medium

OpenBao : le fork open source de Vault

21 min de lecture

logo openbao

OpenBao est un coffre-fort de secrets open source, fork de HashiCorp Vault (v1.14.0), maintenu par la Linux Foundation via l'OpenSSF. Il offre une alternative 100% open source après le passage de Vault sous licence BSL.

Ce guide vous montre comment installer, configurer et utiliser OpenBao pour gérer vos secrets en production.

Le parcours suit l'ordre dans lequel une installation se construit réellement : d'abord le binaire et un serveur de test jetable, puis les secrets engines qui stockent et chiffrent, ensuite les méthodes d'authentification qui distribuent les tokens, et enfin les policies qui limitent ce que ces tokens peuvent faire. La dernière étape bascule cette configuration vers un serveur persistant avec TLS et stockage Raft.

  • Installer OpenBao v2.5 sur Linux
  • Configurer les secrets engines : KV v2, Transit
  • Mettre en place l'authentification : userpass, AppRole
  • Écrire des policies HCL pour le contrôle d'accès granulaire
  • Préparer une configuration production-ready

La partie découverte de ce guide tourne en mode dev, sans privilèges particuliers ni port réservé. Le passage en production change la donne : il faut sudo pour créer /var/lib/openbao, un certificat TLS valide, et de quoi conserver hors ligne les unseal keys produites à l'initialisation. jq est utilisé pour extraire les valeurs des réponses JSON dans les scripts.

  • Linux (x86_64 ou arm64)
  • curl et jq installés
  • Accès root ou sudo (pour le mode production)

OpenBao est fonctionnellement équivalent à Vault Community Edition 1.14. Voici les différences principales :

AspectVault CEOpenBao
LicenceBSL 1.1 (restrictions commerciales)MPL 2.0 (100% open source)
MainteneurHashiCorpLinux Foundation / OpenSSF
CLIvaultbao
Version actuelle1.18+2.5.5
NamespacesEnterprise onlyInclus (depuis v2.3)
Compatibilité API-Compatible Vault 1.14

OpenBao se distribue comme un binaire statique unique, bao, qui joue à la fois le rôle de serveur et de client. Le même exécutable démarre le service et émet les commandes, la distinction tenant uniquement au sous-commande utilisé. Trois canaux sont disponibles, et le choix a des conséquences sur la mise à jour : le binaire téléchargé se remplace à la main, le paquet dnf suit le dépôt, l'image conteneur s'épingle par tag ou digest.

Les artefacts publiés sur GitHub sont accompagnés de sommes de contrôle et de signatures qu'il est recommandé de vérifier avant l'installation, puisque ce binaire aura accès à l'ensemble de vos secrets.

  1. Télécharger le binaire (v2.5.5, dernière version stable)

    Fenêtre de terminal
    VERSION="2.5.5"
    ARCH="x86_64" # ou arm64
    curl -LO "https://github.com/openbao/openbao/releases/download/v${VERSION}/bao_${VERSION}_Linux_${ARCH}.tar.gz"
  2. Extraire et installer

    Fenêtre de terminal
    tar xzf bao_${VERSION}_Linux_${ARCH}.tar.gz
    sudo mv bao /usr/local/bin/
    sudo chmod +x /usr/local/bin/bao
  3. Vérifier l'installation

    Fenêtre de terminal
    bao version
    # OpenBao v2.5.5 (028992583c693c4de6350b8aa52ff85e30375a99)

Le paquet EPEL installe en plus l'unité systemd et l'utilisateur système openbao, ce que le binaire seul ne fait pas. En contrepartie, la version disponible dans le dépôt suit rarement la dernière release amont.

Fenêtre de terminal
# Activer EPEL si nécessaire
sudo dnf install -y epel-release
# Installer OpenBao
sudo dnf install -y openbao

L'image est publiée à l'identique sur trois registres, ce qui évite de dépendre du seul Docker Hub et de ses quotas de téléchargement. Épinglez toujours une version explicite plutôt que latest : une mise à jour d'image non maîtrisée sur un service qui détient vos secrets est un changement à part entière.

Fenêtre de terminal
# Docker Hub
docker pull openbao/openbao:2.5.5
# GitHub Container Registry
docker pull ghcr.io/openbao/openbao:2.5.5
# Quay.io
docker pull quay.io/openbao/openbao:2.5.5

Le mode dev est parfait pour apprendre. Il démarre un serveur en mémoire, non sécurisé, avec un token root prédéfini.

Fenêtre de terminal
# Démarrer en mode développement
bao server -dev -dev-root-token-id="root"

Dans un autre terminal :

Fenêtre de terminal
# Configurer l'environnement
export BAO_ADDR='http://127.0.0.1:8200'
export BAO_TOKEN='root'
# Vérifier le statut
bao status

Sortie attendue :

Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 1
Threshold 1
Version 2.5.5
Storage Type inmem
HA Enabled false

Le secrets engine KV v2 stocke des secrets avec versioning automatique.

Chaque put remplace l'intégralité du secret et crée une nouvelle version : un champ omis disparaît, il n'est pas conservé. La sortie ne renvoie que les métadonnées, jamais les valeurs écrites.

Fenêtre de terminal
# Stocker des credentials
bao kv put secret/demo \
username="admin" \
password="SuperSecret123"

Sortie :

== Secret Path ==
secret/data/demo
======= Metadata =======
Key Value
--- -----
created_time 2026-03-16T13:16:20.324983703Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1

Le double .data.data du filtre jq n'est pas une faute de frappe : KV v2 imbrique les valeurs du secret dans une enveloppe qui porte aussi les métadonnées. Notez que la valeur s'affiche alors en clair dans le terminal, donc dans l'historique du shell si elle est réutilisée dans une commande.

Fenêtre de terminal
# Lire la dernière version
bao kv get secret/demo
# Sortie JSON (pour scripts)
bao kv get -format=json secret/demo | jq -r '.data.data.password'

Le versioning de KV v2 conserve par défaut les 10 dernières versions du secret. Un mot de passe remplacé reste donc lisible par quiconque a la capability read et connaît son numéro de version : la rotation d'un secret compromis exige un destroy des anciennes versions, pas seulement une réécriture.

Fenêtre de terminal
# Mettre à jour le secret (crée version 2)
bao kv put secret/demo \
username="admin" \
password="NewPassword456"
# Lire une version spécifique
bao kv get -version=1 secret/demo

Trois niveaux de suppression, aux effets très différents : delete marque la version comme supprimée mais conserve la donnée, destroy efface réellement le contenu, et metadata delete supprime le secret et tout son historique. Seul destroy fait disparaître la valeur du stockage.

Fenêtre de terminal
# Soft delete (récupérable)
bao kv delete secret/demo
# Hard delete (définitif)
bao kv destroy -versions=1,2 secret/demo
# Supprimer toutes les métadonnées
bao kv metadata delete secret/demo

4. Secrets Engine : Transit (chiffrement as a service)

Section intitulée « 4. Secrets Engine : Transit (chiffrement as a service) »

Transit permet de chiffrer/déchiffrer des données sans exposer les clés.

Transit se monte par défaut sur le path transit/, qui sert ensuite de préfixe à tous les endpoints et donc à toutes les règles de policy le concernant.

Fenêtre de terminal
bao secrets enable transit

Le drapeau -f force l'écriture sans donnée : la clé est générée par OpenBao et n'est jamais exportable par défaut. C'est tout l'intérêt de Transit, une application qui chiffre n'a à aucun moment la clé en mémoire.

Fenêtre de terminal
bao write -f transit/keys/my-app-key

L'encodage base64 du plaintext est obligatoire, y compris pour du texte simple : l'API refuse les octets bruts. Le préfixe vault:v1: du chiffré retourné indique la version de clé utilisée, ce qui permet le déchiffrement après rotation.

Fenêtre de terminal
# Les données doivent être en base64
bao write transit/encrypt/my-app-key \
plaintext=$(echo "données sensibles" | base64)

Sortie :

Key Value
--- -----
ciphertext vault:v1:5/94SlpHWje32JEfqYZjXEe32FL0...
key_version 1

OpenBao lit la version de clé dans le préfixe du chiffré et sélectionne automatiquement la bonne : aucun paramètre supplémentaire n'est nécessaire. Le résultat revient encodé en base64, à repasser dans base64 -d.

Fenêtre de terminal
bao write transit/decrypt/my-app-key \
ciphertext="vault:v1:5/94SlpHWje32JEfqYZjXEe32FL0..."
# Le plaintext retourné est en base64

La méthode userpass permet une authentification par identifiant/mot de passe, utile pour les développeurs et les tests.

Les méthodes d'authentification se montent sous auth/, à distinguer des secrets engines : userpass produit des tokens, il ne stocke aucun secret applicatif.

Fenêtre de terminal
bao auth enable userpass

Le mot de passe passé en argument atterrit dans l'historique du shell : en usage réel, préférez une lecture sur l'entrée standard. Le champ policies est remplacé en totalité à chaque écriture de l'utilisateur.

Fenêtre de terminal
bao write auth/userpass/users/devuser \
password="devpassword" \
policies="default"

Le unset BAO_TOKEN est indispensable : tant que la variable contient le token root, elle a la priorité et vous testeriez les permissions de root sans le savoir. Le token retourné est écrit dans ~/.bao-token et réutilisé automatiquement.

Fenêtre de terminal
# Unset le token root d'abord
unset BAO_TOKEN
# Login
bao login -method=userpass \
username=devuser \
password=devpassword

Sortie :

Success! You are now authenticated.
Key Value
--- -----
token s.15Wjnl3DVKulHTuNAyrSuyvi
token_accessor u9dKTGCSPnWIPJeHVK6JHiyf
token_duration 768h
token_renewable true
token_policies ["default"]

AppRole est la méthode recommandée pour les applications et pipelines CI/CD. Elle utilise un couple role_id + secret_id.

Le retour en root est nécessaire ici, car devuser ne porte que la policy default, qui n'autorise pas le montage d'une méthode d'authentification.

Fenêtre de terminal
export BAO_TOKEN='root' # Revenir en root
bao auth enable approle

Chacune de ces durées borne une fenêtre d'attaque distincte : secret_id_ttl limite la validité du credential éphémère, token_ttl et token_max_ttl la durée d'exploitation du token obtenu, et token_num_uses le nombre d'appels API qu'il autorise avant de devenir inutilisable.

Fenêtre de terminal
bao write auth/approle/role/my-app \
secret_id_ttl=10m \
token_num_uses=10 \
token_ttl=20m \
token_max_ttl=30m \
secret_id_num_uses=1 \
policies="dev-policy"

La séparation des deux valeurs est le coeur du modèle AppRole : le role_id, stable, peut vivre dans la configuration du pipeline, tandis que le secret_id, généré à la demande et à usage unique, doit être injecté juste avant l'exécution par un composant de confiance. Réunis dans le même dépôt, ils redeviennent un simple mot de passe en dur.

Fenêtre de terminal
# Le role_id est stable (stocké dans la config)
bao read auth/approle/role/my-app/role-id
# role_id fce7ab03-5449-e1c5-e102-5c2b90b3e7b0
# Le secret_id est éphémère (généré à la demande)
bao write -f auth/approle/role/my-app/secret-id
# secret_id 4bb62b7c-8deb-0781-4b7b-854e479483f2

L'échange retourne un token portant les policies du rôle. Avec secret_id_num_uses=1, ce secret_id est consommé et un second appel identique échouera, ce qui rend un rejeu détectable.

Fenêtre de terminal
bao write auth/approle/login \
role_id="fce7ab03-5449-e1c5-e102-5c2b90b3e7b0" \
secret_id="4bb62b7c-8deb-0781-4b7b-854e479483f2"

Les policies définissent qui peut accéder à quoi. Elles utilisent le format HCL.

Une policy est une suite de blocs path, et le path correspond à l'URL de l'API privée de son préfixe /v1/. Le modèle est deny by default : la règle deny sur prod de cet exemple est redondante puisque rien ne l'autorise par ailleurs, mais elle documente l'intention et résiste à l'ajout ultérieur d'une policy plus large sur le même token. Retenez le segment data/ propre à KV v2, absent du chemin que vous tapez dans la CLI.

dev-policy.hcl
# Lecture/écriture sur secret/data/dev/*
path "secret/data/dev/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Lecture seule sur les métadonnées
path "secret/metadata/dev/*" {
capabilities = ["list", "read"]
}
# Interdire l'accès à secret/data/prod/*
path "secret/data/prod/*" {
capabilities = ["deny"]
}

Sur KV v2, écrire exige à la fois create et update : la première version d'un secret passe par create, les suivantes par update. La capability deny l'emporte sur toutes les autres, et sudo est nécessaire pour les endpoints d'administration que même une règle permissive ne couvre pas.

CapabilityHTTP VerbDescription
createPOSTCréer si n'existe pas
readGETLire
updatePOST/PUTModifier
deleteDELETESupprimer
listLISTLister les clés
sudo-Opérations privilégiées
deny-Refuser explicitement

bao policy write écrase intégralement la policy portant ce nom, sans fusion avec la version précédente. Le fichier HCL fourni fait donc foi, ce qui en fait un bon candidat au versionnement dans Git.

Fenêtre de terminal
# Créer la policy
bao policy write dev-policy dev-policy.hcl
# Lister les policies
bao policy list
# Lire une policy
bao policy read dev-policy

Les policies sont inscrites dans le token au moment du login. Modifier l'utilisateur ne change donc rien pour les tokens déjà émis, qui gardent leurs permissions jusqu'à expiration.

Fenêtre de terminal
bao write auth/userpass/users/devops \
password="devopspass" \
policies="dev-policy"

Pour la production, créez un fichier config.hcl :

/etc/openbao/config.hcl
ui = true
# Storage avec Raft (intégré, recommandé)
storage "raft" {
path = "/var/lib/openbao/data"
node_id = "node1"
}
# Listener HTTPS (TLS obligatoire en prod !)
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/etc/openbao/tls/server.crt"
tls_key_file = "/etc/openbao/tls/server.key"
}
# Addresses
api_addr = "https://openbao.example.com:8200"
cluster_addr = "https://openbao.example.com:8201"
# Sécurité
disable_mlock = false # false si possible (performance)
log_level = "info"

Le répertoire de données doit appartenir à l'utilisateur qui exécute le processus, sans quoi Raft échoue à créer son journal au démarrage. Lancez le service via systemd plutôt qu'en avant-plan, afin qu'il redémarre après un redémarrage machine.

Fenêtre de terminal
# Créer les répertoires
sudo mkdir -p /var/lib/openbao/data
sudo mkdir -p /etc/openbao/tls
sudo chown -R openbao:openbao /var/lib/openbao
# Démarrer
bao server -config=/etc/openbao/config.hcl

Cette commande génère la clé maîtresse qui chiffre le stockage, puis la découpe en 5 parts dont 3 suffisent à la reconstituer (partage de secret de Shamir). Distribuez ces parts à des personnes différentes : réunies au même endroit, elles annulent tout l'intérêt du mécanisme.

Fenêtre de terminal
# Initialiser (une seule fois)
bao operator init -key-shares=5 -key-threshold=3

Au démarrage, OpenBao est scellé : il répond sur le réseau mais refuse toute opération tant que la clé maîtresse n'est pas reconstituée en mémoire. L'opération est à répéter après chaque redémarrage du service, ce qui justifie de mettre en place un mécanisme d'auto-unseal en production.

Fenêtre de terminal
# Répéter avec 3 clés différentes (threshold=3)
bao operator unseal <key1>
bao operator unseal <key2>
bao operator unseal <key3>

La version 2.5 apporte plusieurs améliorations notables :

  • Horizontal Read Scalability : les nœuds standby peuvent servir les lectures, améliorant les performances
  • Distribution de plugins OCI : téléchargement automatique de plugins depuis des registres de conteneurs
  • OIDC Provider Client Credentials : nouveau flow pour l'OIDC
  • Audit HTTP : webhook pour les événements d'audit
  • Namespaces (depuis 2.3) : isolation multi-tenant sans licence Enterprise

Deux points méritent d'être gardés en tête au-delà des commandes. D'abord, OpenBao ne protège que ce qu'il scelle : un serveur déscellé en permanence avec un token root disponible ne vaut pas mieux qu'un fichier de configuration. Ensuite, la compatibilité API avec Vault 1.14 s'arrête à cette version : les fonctionnalités apparues plus tard chez HashiCorp n'ont pas d'équivalent ici.

  1. OpenBao = Vault open source (MPL 2.0), maintenu par Linux Foundation
  2. Compatibilité API avec Vault 1.14, migration transparente
  3. KV v2 pour les secrets avec versioning
  4. Transit pour le chiffrement as a service
  5. AppRole pour l'authentification CI/CD
  6. Policies HCL pour le contrôle d'accès granulaire
  7. Namespaces inclus (vs Enterprise chez HashiCorp)

Installer OpenBao ne règle que le stockage. Reste la question qui provoque les incidents : combien de temps un secret vit-il, qui le fait tourner, et comment prouver après coup qui y a accédé. Le guide sur le cycle de vie d'un secret traite ces quatre étapes, génération, rotation, révocation et audit, indépendamment de l'outil retenu.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn