Aller au contenu
Infrastructure as Code medium

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

20 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)
  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 +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