Aller au contenu
English
English
Infrastructure as Code medium

Arguments write-only Terraform : le secret qui va au provider, pas au state

50 min de lecture

logo terraform

Un argument write-only transmet un secret au provider sans jamais le persister : ni dans le state, ni dans le plan. C'est le pendant, côté ressource gérée, de ce que ephemeral fait pour les valeurs : la réponse la plus propre au problème que sensitive ne résout pas. Arrivé en Terraform 1.11, il ne fonctionne que pour les attributs qu'un provider déclare explicitement write_only, et son usage a des règles précises qu'on découvre souvent par l'erreur.

Ce guide traite la syntaxe *_wo et son argument de version, le couple qui est mutuellement obligatoire, l'alimentation par une valeur éphémère, la vérification qu'un argument est bien write-only, et la solution quand aucun _wo n'existe. Les comportements du langage ont été vérifiés sur Terraform v1.15.4.

  • Ce qu'est un argument write-only, et sa différence avec sensitive
  • Le couple password_wo / password_wo_version, mutuellement obligatoire
  • Alimenter un write-only par une valeur éphémère
  • Vérifier qu'un attribut est write-only, et où s'entraîner
  • La solution quand aucun _wo n'existe

Un attribut write-only (suffixe _wo par convention) reçoit une valeur que le provider consomme, mais que Terraform n'écrit ni dans le state ni dans le plan. C'est un attribut de schéma de provider : il n'existe que si le provider le déclare. Sur aws_db_instance, c'est password_wo :

resource "aws_db_instance" "db" {
# ...
password_wo = ephemeral.random_password.db.result
password_wo_version = 1
}

Contrairement à password (persisté), password_wo ne laisse aucune trace du mot de passe dans le state.

Le couple _wo et _wo_version est mutuellement obligatoire

Section intitulée « Le couple _wo et _wo_version est mutuellement obligatoire »

C'est le piège le plus fréquent, et le guide d'origine le sous-estimait. password_wo et password_wo_version sont mutuellement obligatoires : dans le provider AWS, chacun porte un RequiredWith sur l'autre. password_wo seul est refusé au plan. La validation a été ajoutée en provider AWS v5.89.0.

Le rôle de password_wo_version n'est pas un confort : c'est lui qui décide quand le provider prend en compte une nouvelle valeur. Comme la valeur n'est pas persistée, Terraform ne peut pas la comparer d'un run à l'autre. Il ne planifie donc une mise à jour du secret que si le numéro de version change.

Sur aws_db_instance, password_wo est en conflit avec password (le mot de passe classique persisté) et avec manage_master_user_password (mot de passe géré par Secrets Manager). Les trois sont mutuellement exclusifs : on choisit une seule stratégie de mot de passe.

À noter sur les versions du provider AWS : aws_db_instance.password_wo et aws_secretsmanager_secret_version.secret_string_wo sont arrivés en v5.88.0 ; la v5.87.0 n'avait apporté que aws_rds_cluster.master_password_wo et aws_ssm_parameter.value_wo.

Alimenter un write-only par une valeur éphémère

Section intitulée « Alimenter un write-only par une valeur éphémère »

La source idéale d'un write-only est une valeur éphémère, elle aussi hors du state. Une ressource ephemeral "random_password" (provider random >= 3.7) génère le secret à la volée :

ephemeral "random_password" "db" {
length = 24
}
resource "aws_db_instance" "db" {
password_wo = ephemeral.random_password.db.result
password_wo_version = 1
}

Un argument write-only est l'un des rares contextes où une valeur éphémère est autorisée. Les sept sont : un argument write-only, un autre bloc ephemeral, un locals, une variable ephemeral = true, un output de module enfant ephemeral = true, une configuration de provider, et un provisioner (ou son bloc connection).

Inutile de fouiller le Registry : terraform providers schema -json expose un booléen write_only sur chaque attribut :

Fenêtre de terminal
terraform providers schema -json | jq '.provider_schemas[].resource_schemas.aws_db_instance.block.attributes.password_wo.write_only'

C'est aussi la réponse au dépannage « le provider n'expose pas cet argument » : si le booléen n'existe pas, l'attribut n'est pas write-only, et il faut mettre le provider à jour.

Où s'entraîner : aucun provider gratuit, ou presque

Section intitulée « Où s'entraîner : aucun provider gratuit, ou presque »

Point d'honnêteté rarement dit : hors fournisseurs cloud, presque aucun provider n'expose d'attribut write-only. Vérifié par schéma en 1.15.4, hashicorp/local, null, random, tls, http, time, external, archive et la ressource intégrée terraform_data n'en exposent aucun. Chez HashiCorp, seul hashicorp/vault en expose largement (vault_kv_secret_v2.data_json_wo, etc.). Sans compte cloud ni Vault, on ne peut donc pas vraiment pratiquer le write-only lui-même, seulement la valeur éphémère qui l'alimente.

Quand aucun _wo n'existe : ephemeral de bout en bout

Section intitulée « Quand aucun _wo n'existe : ephemeral de bout en bout »

Si le provider n'offre pas d'attribut write-only, la transposition en primitives du langage est le couple variable { ephemeral = true } en entrée et output { ephemeral = true } en sortie de module enfant. C'est l'exact équivalent du contrat write-only, et la seule option hors provider compatible.

Un point à ne pas confondre : une variable de module ne peut pas être write-only. Le write-only est un attribut de schéma de provider, pas une construction du langage. Pour un secret qui traverse des modules sans être persisté, c'est ephemeral, pas write-only.

Le guide ne doit pas se contenter d'affirmer que le secret « n'apparaît nulle part ». On le constate :

Fenêtre de terminal
terraform show -json # state : pas de password_wo
terraform show -json tfplan # plan : pas de password_wo

Une ressource éphémère ne produit d'ailleurs aucune entrée dans le state (ni mode: managed, ni mode: data) : son absence est la preuve.

Ces symptômes touchent au contrat write-only ou à la frontière éphémère.

SymptômeCauseSolution
Invalid use of ephemeral valueUne valeur éphémère dans un attribut persisté (pas _wo)La router vers un write-only ou un autre contexte éphémère
Ephemeral value not allowedUne valeur éphémère exposée dans un output racineephemeralasnull(), ou output éphémère en module enfant
password_wo refusé au planpassword_wo_version manquant (couple obligatoire)Ajouter password_wo_version
Le mot de passe ne change paspassword_wo modifié sans changer la versionIncrémenter password_wo_version
Conflit sur password_wopassword ou manage_master_user_password aussi définiNe garder qu'une stratégie de mot de passe
L'argument _wo n'existe pasProvider trop ancienMettre à jour le provider (v5.88.0+ pour aws_db_instance)

Les arguments write-only transmettent un secret au provider sans jamais le persister dans le state, ce qui répond au reproche le plus sérieux fait à Terraform sur la gestion des secrets. Le lab se joue contre un émulateur AWS local, donc sans compte ni coût, et la validation vérifie l'absence de la valeur dans le state produit.

  1. Un argument write-only (*_wo) transmet un secret au provider sans le persister ; c'est un attribut de schéma de provider (Terraform 1.11).
  2. _wo et _wo_version sont mutuellement obligatoires ; _wo seul est refusé.
  3. Oublier d'incrémenter la version ne change pas le secret.
  4. La source idéale d'un write-only est une valeur éphémère ; il n'y a pas de dérivée persistable d'un secret éphémère.
  5. terraform providers schema -json expose le booléen write_only ; presque aucun provider gratuit n'en a (sauf vault).
  6. Sans _wo, la transposition est variable/output ephemeral = true ; une variable de module ne peut pas être write-only.

Les questions ci-dessous reprennent les confusions les plus fréquentes sur les arguments write-only : le rôle de la version, les conflits, et la source éphémère.

Ce site vous est utile ?

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

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. 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