
L'examen Terraform Professional cite nommément Vault au sous-objectif
2f. Le problème n'est pas de lire un secret Vault : c'est de le lire sans
qu'il finisse en clair dans le state. Car la façon la plus répandue de le faire,
une data source, recopie la valeur dans terraform.tfstate, et
sensitive_values la marque true sans rien cacher du tout.
Ce guide montre le piège, puis la bonne combinaison : une lecture éphémère et
une écriture write-only, pour qu'un secret externe transite de Vault jusqu'à
son destinataire sans laisser de trace côté Terraform. Tous les exemples ont
été exécutés sur Terraform v1.15.4 avec le provider hashicorp/vault en 5.x,
contre un serveur vault server -dev.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Le piège : pourquoi la data source
vault_kv_secret_v2fait fuiter le secret - La lecture éphémère : le bloc
ephemeral "vault_kv_secret_v2" - L'écriture write-only :
data_json_woet son argument de version - Le duo éphémère + write-only, de bout en bout sans trace
- La rotation : piloter le renvoi par un entier de version
Prérequis
Section intitulée « Prérequis »- Terraform 1.11 ou plus récent (installer Terraform) : les ressources éphémères et les arguments write-only l'exigent.
- Un serveur Vault :
vault server -devsuffit, en mémoire, descellé, avec un jeton racine. Vault Community Edition est libre et gratuit. - Les valeurs éphémères et les arguments write-only (valeurs éphémères, write-only).
Le piège : la data source recopie le secret en clair
Section intitulée « Le piège : la data source recopie le secret en clair »La voie historique pour lire un secret KV v2 est une data source :
data "vault_kv_secret_v2" "source" { mount = "kvv2" name = "app/db"}Elle fonctionne, mais elle recopie la valeur dans le state. Le provider émet d'ailleurs un avertissement de dépréciation sur cette data source.
La lecture éphémère : ephemeral "vault_kv_secret_v2"
Section intitulée « La lecture éphémère : ephemeral "vault_kv_secret_v2" »Le provider hashicorp/vault en 5.x expose la même lecture sous forme
éphémère. Un bloc ephemeral produit une valeur disponible pendant
l'opération, mais jamais écrite dans le state ni le plan :
ephemeral "vault_kv_secret_v2" "source" { mount = "kvv2" name = "app/db"}On référence son résultat par
ephemeral.vault_kv_secret_v2.source.data["password"]. Cette valeur ne peut aller
que dans un contexte éphémère : une configuration de provider, un provisioner,
ou un argument write-only. C'est ce dernier qui complète la chaîne.
L'écriture write-only : data_json_wo
Section intitulée « L'écriture write-only : data_json_wo »La ressource vault_kv_secret_v2 a deux façons d'écrire son contenu :
| Argument | Persisté dans le state ? |
|---|---|
data_json (ordinaire) | oui (marqué sensible, mais présent) |
data_json_wo (write-only) | non, jamais |
L'argument write-only forme un couple obligatoire avec un numéro de version :
resource "vault_kv_secret_v2" "cible" { mount = "kvv2" name = "app/copie"
data_json_wo = jsonencode({ password = ephemeral.vault_kv_secret_v2.source.data["password"] }) data_json_wo_version = 1}Après l'apply, dans terraform show -json : data_json_wo vaut null,
data_json vaut null, data est un objet vide ; seul
data_json_wo_version subsiste, avec un nombre bien réel.
Le duo éphémère + write-only
Section intitulée « Le duo éphémère + write-only »Bout à bout, le secret ne touche jamais le disque côté Terraform : lu par un
ephemeral (pas de state), écrit par un data_json_wo (pas de state). Il transite
en mémoire pendant l'opération, du KV source vers le KV cible. C'est la réponse
complète au sous-objectif 2f, et la seule qui ne laisse aucune trace, ni en clair
ni sous forme dérivée.
La rotation : piloter le renvoi par la version
Section intitulée « La rotation : piloter le renvoi par la version »Comme tout write-only, data_json_wo n'est renvoyé au provider que lorsque son
numéro de version change. Conséquence directe, vérifiée à l'exécution :
- changer le secret dans le KV source sans toucher
data_json_wo_versionne produit aucun plan : Terraform ne suit pas ce qu'il ne stocke pas ; - porter la version de
1à2produit un plan, et l'apply pousse la nouvelle valeur dans la cible, dont la métadonnée KV passe à la version 2.
C'est le mécanisme de rotation : on incrémente un entier, jamais on ne manipule le secret en clair dans la configuration.
À retenir
Section intitulée « À retenir »- La data source
vault_kv_secret_v2fuit le secret dans le state (et est dépréciée) ;sensitiven'y change rien. - Le bloc
ephemeral "vault_kv_secret_v2"lit sans persister ; sa valeur ne va que dans un contexte éphémère. data_json_woécrit sans persister ;data_json_wo,data_jsonvalentnulletdataest vide dans le state.- Seul
data_json_wo_versionsubsiste et pilote la rotation : sans son incrément, un nouveau secret source est ignoré. - Le duo éphémère + write-only ne laisse aucune trace côté Terraform.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous portent sur les points qui bloquent le plus souvent : la data source qui fuit, la façon de lire sans persister, et pourquoi un secret changé côté Vault n'est pas repris. Chaque réponse donne la vérification correspondante.
Réponse courte
Parce qu'elle recopie le secret en clair dans le state, et qu'elle est dépréciée.Détail
sensitive_values marque la valeur true mais ne cache rien : le mot de passe reste lisible dans terraform.tfstate et terraform show -json. Utilisez plutôt un bloc ephemeral "vault_kv_secret_v2", qui lit sans persister.Réponse courte
Un blocephemeral "vault_kv_secret_v2" (provider vault 5.x).Détail
ephemeral "vault_kv_secret_v2" "source" {
mount = "kvv2"
name = "app/db"
}
La valeur est disponible pendant l'opération mais jamais écrite dans le state ni le plan. Elle ne peut aller que dans un contexte éphémère : provider, provisioner, ou un argument write-only.Réponse courte
ephemeral.vault_kv_secret_v2.<nom>.data["<cle>"].Détail
ephemeral.vault_kv_secret_v2.source.data["password"]
La map data porte les clés du secret KV v2. Cette référence ne peut alimenter qu'un contexte éphémère (par exemple un argument data_json_wo) ; ailleurs, Terraform lève « Invalid use of ephemeral value ».Réponse courte
data_json persiste dans le state ; data_json_wo (write-only) ne persiste jamais.Détail
Avecdata_json_wo, terraform show -json montre data_json_wo = null, data_json = null et data = {} : seule reste data_json_wo_version. L'argument write-only forme un couple obligatoire avec ce numéro de version.Réponse courte
Parce quedata_json_wo_version n'a pas changé : la valeur write-only n'est renvoyée qu'au changement de version.Détail
Terraform ne stocke pas le secret, donc il ne peut pas détecter qu'il a changé côté Vault : unplan reste vide. Pour pousser la nouvelle valeur, incrémentez data_json_wo_version (1 vers 2). C'est le mécanisme de rotation.Réponse courte
Non, avec la combinaison lecture éphémère + écrituredata_json_wo.Détail
Le blocephemeral ne produit aucune entrée dans le state ; data_json_wo y laisse null. La valeur du secret n'apparaît donc nulle part dans terraform show -json ni dans terraform.tfstate. Vérifiez-le en cherchant la valeur dans les deux : zéro occurrence.Réponse courte
Non.vault server -dev suffit : serveur en mémoire, descellé, jeton racine choisi.Détail
vault server -dev -dev-root-token-id=root
export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN=root
vault secrets enable -path=kvv2 kv-v2
vault kv put kvv2/app/db username=app password=change-me
Vault Community Edition est libre et gratuit, sans licence ni inscription.Pour aller plus loin
Section intitulée « Pour aller plus loin »- Les valeurs ephemeres : sortir un secret du state, sans le laisser fuir.
- Les arguments write-only : transmettre un secret au provider sans jamais le persister.
- Les donnees sensibles : sensitive : ce que
sensitivemasque, et ce qu'il ne masque pas. - Les providers Terraform : configurer le provider Vault, source et version.
- Ephemeral resources : la reference officielle : le mecanisme sur lequel repose la lecture d'un secret.