La Key/Value Secrets Engine fait partie intégrante de presque toute implémentation de Vault. Il constitue la base du stockage sécurisé des secrets statiques et est, en pratique, utilisé bien plus fréquemment que de nombreux Secrets Engines dynamiques.
Après l’introduction théorique dans la partie 2a, nous abordons dans cet article le travail concret avec le Secrets Engine KV. Nous montrons comment écrire, lire, mettre à jour et supprimer des secrets, et analysons de manière pratique les différences entre les versions 1 et 2 de KV. L’accent est mis sur les commandes pertinentes en production, les écueils réalistes et des recommandations concrètes pour le quotidien opérationnel, c’est pourquoi je vous transmets ces connaissances sous forme de tutoriel mêlé à une fiche mémo.
La commande vault kv : votre boîte à outils du quotidien
L’interaction avec le Secrets Engine KV se fait via la commande vault kv. Cette commande abstrait en interne les différences entre les versions, mais indique clairement dans sa sortie s’il s’agit d’un Secrets Engine v1 ou v2. Les sous-commandes de base se répartissent en deux groupes :
Opérations de base (disponibles dans KV v1 et v2) :
- put : écrire ou mettre à jour des secrets
- get : lire des secrets
- delete : supprimer des secrets (pas nécessairement de manière définitive)
- list : afficher tous les chemins disponibles
Opérations avancées (uniquement KV v2) :
- patch : mettre à jour des clés spécifiques sans écraser les autres
- rollback : revenir à une version spécifique
- undelete : restaurer des versions supprimées
- destroy : supprimer définitivement des versions
Ces commandes avancées ne sont disponibles qu’avec KV v2 car elles s’appuient sur les métadonnées stockées en interne. L’ancienne v1 ne prend pas encore en charge les métadonnées.
Écrire des secrets avec put : simple, mais avec des pièges
La commande d’écriture vault kv put est la méthode centrale pour écrire des secrets dans le Secrets Engine KV :
vault kv put <chemin> <clé>=<valeur> [<clé>=<valeur>...]
Un exemple simple : commençons par activer les Secrets Engines :
$ vault secrets enable kv
Success! Enabled the kv secrets engine at: kv/
$
$ vault secrets enable -path=kvv2 kv-v2
Success! Enabled the kv-v2 secrets engine at: kvv2/
La commande suivante enregistre ensuite le secret sous le chemin kv/app/db avec la clé pass et la valeur 123. La sortie varie selon la version utilisée :
KV Version 1 :
$ vault kv put kv/app/db pass=123 Success! Data written to: kv/app/db $
KV Version 2 :
$ vault kv put kvv2/app/db pass=123 == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T10:52:07.551872783Z custom_metadata <nil> deletion_time n/a destroyed false version 1 $
La version 2 fournit des métadonnées, telles que la date de création et la version actuelle.
Remarque importante : avec KV v2, l’enregistrement a lieu dans un chemin interne avec le préfixe supplémentaire /data/. Cela est particulièrement important lors de l’utilisation directe de l’API, car cela signifie qu’on ne peut pas migrer simplement de v1 vers v2 sans adapter le cas échéant les scripts et applications concernés !
Enregistrer plusieurs paires Key/Value en une seule fois
Une commande put unique peut enregistrer autant de clés que souhaité :
$ vault kv put kv/app/db pass=123 user=admin api=myapisecret Success! Data written to: kv/app/db $ vault kv put kvv2/app/db pass=123 user=admin api=myapisecret == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T10:56:04.624145825Z custom_metadata <nil> deletion_time n/a destroyed false version 2 [rramge@ol9 terraform-vault-kv]$
En pratique, cela permet d’économiser des commandes, mais n’oubliez pas : le contenu entier au chemin indiqué est remplacé. En cas de doute, procédez clé par clé pour améliorer la lisibilité des scripts et réduire le risque d’erreur - ou utilisez des fichiers comme montré dans la section suivante.
Importer des secrets à partir de fichiers JSON
Pour les environnements automatisés ou les structures de secrets complexes, il est recommandé d’utiliser des fichiers pour saisir plusieurs paires Key/Value :
$ vault kv put kv/app/db @secrets.json
Contenu exemple du fichier secrets.json :
{ "pass": "123", "user": "admin", "api": "myapisecret" }
Différence importante entre put et patch
De nombreux utilisateurs de Vault commettent tôt une erreur aux conséquences importantes : ils utilisent put pour mettre à jour des valeurs individuelles.
Dans KV v1 et v2, cela entraîne toujours la suppression de toutes les données existantes du secret si elles ne sont pas présentes dans la nouvelle commande put.
Exemple :
# État initial
$ vault kv put kv/app/db pass=123 user=admin api=myoldapisecret
Success! Data written to: kv/app/db
$
# Mise à jour de la clé API, par erreur via "put" $ vault kv put kv/app/db pass=123 user=admin api=myoldapisecret
Success! Data written to: kv/app/db
$
# Résultat : seul "api" est conservé $ vault kv get kv/app/db
=== Data ===
Key Value
--- -----
api mynewapisecret
$
Les clés user et pass sont donc perdues.
vault kv put était la mauvaise commande pour conserver les clés user et pass existantes. En effet, seul patch empêche leur suppression. Nous reviendrons sur ce point plus bas. Retenez pour l’instant que put est destructif :
Important : Une commande vault kv put remplace toujours toutes les données au chemin spécifié. Il ne s’agit pas d’une opération de fusion !
Lire des secrets avec get : un coup d'œil dans le stockage
Avec vault kv get, vous récupérez des secrets. Par défaut, la version la plus récente est toujours affichée.
Par exemple, cette commande affiche :
vault kv get kv/app/db
Avec KV v1 :
$ vault kv get kv/app/db
==== Data ====
Key Value
--- -----
api myapisecret
pass 123
user admin
$
Avec KV v2 :
$ vault kv get kvv2/app/db == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T10:56:04.624145825Z custom_metadata <nil> deletion_time n/a destroyed false version 2 ==== Data ==== Key Value --- ----- api myapisecret pass 123 user admin $
Remarque : Ici aussi, le chemin /data/ est visible dans KV v2. Si vous analysez cette sortie dans des scripts ou des applications, vous devez en tenir compte.
Sortie JSON pour les scripts et l’automatisation
Avec -
format=json, vous obtenez des données lisibles par machine :
$ vault kv get -format=json kv/app/db { "request_id": "7de43863-d7c4-837f-b59c-4b5e546a1d65", "lease_id": "", "lease_duration": 2764800, "renewable": false, "data": { "api": "myapisecret", "pass": "123", "user": "admin" }, "warnings": null, "mount_type": "kv" } $
Vous pouvez combiner cela avec jq :
$ vault kv get -format=json kv/app/db | jq -r '.data.api' myapisecret $
Astuce pro : vous pouvez définir le format de sortie par défaut sur JSON de manière permanente via la variable d’environnement VAULT_FORMAT :
export VAULT_FORMAT=json
Récupérer des versions spécifiques d’un secret avec -version
Le comportement de lecture de get est assez simple à comprendre, mais il faut d’abord connaître les différences. Les règles suivantes s’appliquent :
- Une commande get normale renvoie toujours la dernière version.
- Pour les secrets supprimés (KV v2), vous obtenez des métadonnées, mais aucune donnée.
- Des versions spécifiques peuvent être récupérées avec --version=X (également uniquement avec KV v2).
Exemple de récupération d’une version spécifique d’un secret :
$ vault kv get --version=1 kvv2/app/db == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T10:52:07.551872783Z custom_metadata <nil> deletion_time n/a destroyed false version 1 ==== Data ==== Key Value --- ----- pass 123 $ vault kv get --version=2 kvv2/app/db == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T10:56:04.624145825Z custom_metadata <nil> deletion_time n/a destroyed false version 2 ==== Data ==== Key Value --- ----- api myapisecret pass 123 user admin $
Je l’ai déjà dit plusieurs fois, mais il ne faut pas se lasser de le répéter : La gestion de versions des secrets n’est disponible que dans KV v2. Cela signifie également que seul le Secrets Engine KV v2 permet une inspection ciblée de l’historique d’un secret donné. Cela peut être très important pour les audits ultérieurs, par exemple pour prouver si et à quelle fréquence des secrets ont réellement été renouvelés.
Mises à jour ciblées et restauration de secrets
patch : Mettre à jour précisément la bonne clé
Plus haut dans cet article, nous avons déjà clairement souligné que la commande put écrase entièrement les secrets existants et risque donc de supprimer des données présentes. Utilisez donc patch pour modifier précisément des valeurs spécifiques à l’intérieur d’un secret.
Dans KV v1, cela ne fonctionne pas à cause de l’absence de métadonnées :
$ vault kv patch kv/app/db user=dbadmin
KV engine mount must be version 2 for patch support
$
Dans KV v2, en revanche, cela fonctionne :
$ vault kv patch kvv2/app/db user=dbadmin == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T11:07:50.365256138Z custom_metadata <nil> deletion_time n/a destroyed false version 3 $
Résultat : seule la clé user est mise à jour, le reste du secret reste inchangé.
rollback : Revenir en toute sécurité à une version antérieure
Un secret enregistré par erreur ? Vous avez utilisé vault kv put par inadvertance ? Aucun problème avec KV v2. Si vous avez écrasé des données accidentellement, KV v2 vous permet de revenir à une version antérieure grâce à la commande rollback :
$ vault kv get kvv2/app/db == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T11:07:50.365256138Z custom_metadata <nil> deletion_time n/a destroyed false version 3 ==== Data ==== Key Value --- ----- api myapisecret pass 123 user dbadmin $
$ vault kv rollback -version=2 kvv2/app/db
Key Value --- ----- created_time 2025-07-01T11:10:44.341592593Z custom_metadata <nil> deletion_time n/a destroyed false version 4 $
Cela crée une nouvelle version contenant les données de la version spécifiée. Dans notre exemple :
- La version 2 contient les données d’origine
- La version 3 était la tentative de mise à jour erronée
- La version 4 est le résultat du rollback
Astuce pro : Le système ne revient donc pas au moment de la création de la version 2, mais crée une nouvelle version avec les données de la version 2. L’historique reste donc intact.
Suppression des données : delete vs. destroy
Il est impératif de retenir que la commande delete agit différemment dans KV v1 et v2.
KV v1 : Suppression définitive (hard delete)
Avec le Secrets Engine KV v1, la commande delete supprime les données de manière irréversible :
$ vault kv delete kv/app/db Success! Data deleted (if it existed) at: kv/app/db $ $ vault kv get kv/app/db No value found at kv/app/db $
Les données sont donc supprimées sans possibilité de retour. Une restauration ne peut se faire qu’en réinjectant un snapshot Vault.
KV v2 : Suppression logique (soft delete)
Avec KV v2, une suppression via delete est seulement logique :
$ vault kv delete kvv2/app/db
Success! Data deleted (if it existed) at: kvv2/data/app/db
$
$ vault kv get kvv2/app/db
== Secret Path ==
kvv2/data/app/db
======= Metadata =======
Key Value
--- -----
created_time 2025-07-01T11:10:44.341592593Z
custom_metadata <nil>
deletion_time 2025-07-01T11:13:33.705332433Z
destroyed false
version 4
$
Les données ne sont plus visibles, mais elles existent toujours dans le système. Les métadonnées, en revanche, sont toujours présentes - notez ici la nouvelle valeur du champ deletion_time, qui auparavant était n/a.
Les secrets supprimés logiquement peuvent être restaurés avec undelete ou définitivement supprimés avec destroy.
undelete : Restaurer des versions supprimées
Si une suppression a été effectuée par erreur :
$ vault kv undelete -versions=4 kvv2/app/db Success! Data written to: kvv2/undelete/app/db $ $ vault kv get kvv2/app/db == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T11:10:44.341592593Z custom_metadata <nil> deletion_time n/a destroyed false version 4 ==== Data ==== Key Value --- ----- api myapisecret pass 123 user admin $
Les données sont de nouveau accessibles. À condition qu’aucun destroy n’ait été exécuté entre-temps.
destroy : Suppression définitive de versions spécifiques
Important : destroy est irréversible - même undelete et rollback ne fonctionneront plus. À utiliser uniquement si vous êtes sûr, et ne jamais le confondre avec delete !
Après exécution, aucune restauration n’est possible :
$ vault kv destroy -versions=2 kvv2/app/db Success! Data written to: kvv2/destroy/app/db $
Vous pouvez aussi supprimer plusieurs versions en une seule commande :
$ vault kv destroy -versions=1,3,4 kvv2/app/db Success! Data written to: kvv2/destroy/app/db $
Après un destroy, le champ destroyed affiche la valeur true :
$ vault kv get kvv2/app/db == Secret Path == kvv2/data/app/db ======= Metadata ======= Key Value --- ----- created_time 2025-07-01T11:10:44.341592593Z custom_metadata <nil> deletion_time n/a destroyed true version 4 $
Ce champ est principalement destiné aux audits. Un rollback ou undelete est alors exclu, et cela constitue une preuve qu’un destroy a bien été effectué.
Conseils pratiques pour votre quotidien et votre stratégie KV
1. Utiliser le contrôle de version
Vérifiez régulièrement quelle version de KV vous utilisez :
$ vault secrets list --detailed | grep kv kv/ kv kv_11a18e23 system system false replicated false false map[] n/a 4a479e06-6b44-e721-bbff-5ab3df0b7134 n/a v0.21.0+builtin n/a supported kvv2/ kv kv_be4ef9a0 system system false replicated false false map[version:2] n/a 390c2b5f-45cd-6774-ae17-3d643d951401 n/a v0.21.0+builtin n/a supported $
Cherchez version:2 dans la colonne Options (l’avant-dernière colonne).
2. Utiliser des chemins structurés
Établissez une convention de nommage cohérente pour les chemins dans votre Secret Engine, par exemple :
apps/ └── payment-service/ ├── prod/ │ ├── db-credentials │ └── api-keys └── dev/ ├── db-credentials └── api-keys
3. patch au lieu de put
Pour les mises à jour de valeurs individuelles, utilisez toujours patch au lieu de put, afin d’éviter toute perte de données.
4. Sortie JSON pour les workflows automatisés
Dans les scripts, utilisez systématiquement :
vault kv get -format=json kv/app/db | jq -r '.data.password'
5. Définir une stratégie de rollback
Documentez les versions importantes et préparez des procédures de rollback. Par exemple :
# Sauvegarder la version actuelle $ CURRENT_VERSION=$(vault kv get -format=json kvv2/app/db | jq -r '.data.metadata.version') $ echo $CURRENT_VERSION # En cas de problème : rollback $ vault kv rollback --version=$((CURRENT_VERSION-1)) kvv2/app/db
Éviter les erreurs courantes
1. L’erreur "write is not merge"
Le problème le plus fréquent : écrasement involontaire de données avec put au lieu de patch.
2. Confusion des chemins dans KV v2
Gardez à l’esprit :
- Différences de chemins dues à la casse dans KV v2
- KV v2 insère automatiquement /data/ dans le chemin interne. La CLI gère cela en arrière-plan, mais pour les appels API directs, vous devez en tenir compte.
3. Confusion entre delete et destroy
- delete = suppression logique (restaurable) avec KV v2, suppression définitive avec KV v1
- destroy = suppression définitive (irrécupérable) avec KV v2
4. Pas de remise à zéro des numéros de version après un delete
Les numéros de version dans KV v2 sont incrémentaux et ne sont jamais réinitialisés, même après un delete.
Conclusion
Le Secrets Engine Key/Value est facile à expliquer, mais son utilisation pratique regorge de subtilités. Le Secrets Engine est facile à expliquer, mais son utilisation pratique regorge de subtilités. Une compréhension solide du versionnement, des commandes et de leurs effets secondaires est essentielle pour garantir un fonctionnement stable et sécurisé.
Celui qui utilise put avec discernement, patch pour les modifications ciblées, et qui maîtrise rollback en cas de problème, a une bonne maîtrise de l’outil KV Engine. Et celui qui évite destroy tant que ce n’est pas strictement nécessaire s’épargne bien des ennuis et conserve une voie de retour en cas d’erreur.
À retenir dans la pratique : dans KV v2, presque tout est récupérable - sauf après un destroy.
Profitez de cette sécurité, mais concevez malgré tout vos processus avec prévoyance.