Aller au contenu
Infrastructure as Code medium

Arguments write-only Terraform

12 min de lecture

logo terraform

Les arguments write-only permettent de passer un secret à un provider Terraform sans que cette valeur soit jamais stockée dans le state ou le plan. C'est le dernier maillon de la chaîne de protection des données sensibles : une ressource éphémère génère ou récupère le secret, puis un argument write-only le transmet au provider lors de chaque opération. Terraform envoie la valeur au provider mais ne la conserve nulle part.

  • Déclarer un argument write-only : password_wo sur une ressource
  • Comprendre le mécanisme de version : _wo_version pour déclencher les mises à jour
  • Combiner ephemeral + write-only : zéro secret dans le state
  • Connaître le cycle complet : générer → stocker → récupérer → utiliser

Pensez à un coffre-fort avec une fente de dépôt :

# Argument classique : Terraform lit et écrit
state["password"] = "S3cr3t!" # stocké dans le state
current = state.get("password") # relu au plan suivant
# Argument write-only : Terraform écrit, mais ne stocke jamais
provider.set_password("S3cr3t!") # envoyé au provider
# rien dans le state — Terraform ne peut pas relire la valeur

Un argument write-only c'est une fente de dépôt : vous glissez la valeur, le provider la reçoit et l'utilise, mais personne ne peut la récupérer après. Terraform envoie la valeur à chaque opération parce qu'il ne la stocke pas.

Avec une resource classique, même marquée sensitive = true, le mot de passe d'une base de données se retrouve dans le state :

resource "aws_db_instance" "main" {
instance_class = "db.t3.micro"
engine = "postgres"
username = "admin"
password = var.db_password # ← stocké dans le state
}

Après un terraform apply, la valeur de password est lisible en clair dans terraform.tfstate. L'argument password_wo remplace ce comportement : le provider reçoit la valeur, mais Terraform ne la stocke jamais.

Les providers indiquent dans le Terraform Registry quels arguments sont write-only. Par exemple, la ressource aws_db_instance expose password_wo :

resource "aws_db_instance" "example" {
identifier = "my-database"
instance_class = "db.t3.micro"
allocated_storage = 5
engine = "postgres"
username = "admin"
skip_final_snapshot = true
password_wo = "MonMotDePasse!"
password_wo_version = 1
}

Deux points importants :

  • password_wo accepte la valeur du mot de passe. Terraform l'envoie au provider à chaque opération (plan, apply), mais ne la stocke ni dans le state ni dans le plan.
  • password_wo_version est un entier que Terraform stocke dans le state. Il sert à déclencher une mise à jour du mot de passe quand vous l'incrémentez.

Terraform ne stocke pas la valeur d'un argument write-only. Conséquence : il ne peut pas détecter si cette valeur a changé. Sans l'argument de version, Terraform enverrait toujours la même disposition au provider sans savoir qu'il faut déclencher une mise à jour.

Le pattern est simple :

  1. Déclarer : password_wo = <valeur> et password_wo_version = 1.

  2. Mettre à jour : changer la valeur et incrémenter la version à 2.

  3. Appliquer : Terraform détecte le changement de version dans le state et demande au provider d'appliquer la nouvelle valeur.

resource "aws_db_instance" "example" {
# ...
password_wo = "NouveauMotDePasse!"
password_wo_version = 2
}

Terraform voit que password_wo_version est passée de 1 à 2 dans le state. Il inclut la modification dans le plan et envoie la nouvelle valeur password_wo au provider AWS lors de l'apply.

Le pattern recommandé utilise une ressource éphémère pour générer le secret, puis le transmet via l'argument write-only :

ephemeral "random_password" "db_password" {
length = 16
override_special = "!#$%&*()-_=+[]{}<>:?"
}
resource "aws_db_instance" "example" {
identifier = "my-database"
instance_class = "db.t3.micro"
allocated_storage = 5
engine = "postgres"
username = "admin"
skip_final_snapshot = true
password_wo = ephemeral.random_password.db_password.result
password_wo_version = 1
}

Avec ce pattern, aucune trace du mot de passe :

  • ephemeral "random_password" génère un mot de passe temporaire, jamais stocké dans le state ;
  • password_wo le transmet au provider AWS, qui l'utilise pour créer l'instance RDS ;
  • Terraform oublie la valeur dès que l'opération est terminée.

En production, vous ne voulez pas seulement générer un mot de passe : vous voulez aussi le stocker dans un coffre pour que les applications puissent le récupérer. Le cycle complet avec AWS Secrets Manager :

# 1. Générer un mot de passe éphémère
ephemeral "random_password" "db_password" {
length = 16
override_special = "!#$%&*()-_=+[]{}<>:?"
}
# 2. Stocker dans Secrets Manager (write-only aussi)
resource "aws_secretsmanager_secret" "db_password" {
name = "my-app/db-password"
}
resource "aws_secretsmanager_secret_version" "db_password" {
secret_id = aws_secretsmanager_secret.db_password.id
secret_string_wo = ephemeral.random_password.db_password.result
secret_string_wo_version = 1
}
# 3. Récupérer le secret via une ressource éphémère
ephemeral "aws_secretsmanager_secret_version" "db_password" {
secret_id = aws_secretsmanager_secret_version.db_password.secret_id
}
# 4. Utiliser comme argument write-only sur l'instance RDS
resource "aws_db_instance" "example" {
identifier = "my-database"
instance_class = "db.t3.micro"
allocated_storage = 5
engine = "postgres"
username = "admin"
skip_final_snapshot = true
password_wo = ephemeral.aws_secretsmanager_secret_version.db_password.secret_string
password_wo_version = aws_secretsmanager_secret_version.db_password.secret_string_wo_version
}

Après un terraform apply sur cette configuration :

RessourceDans le state ?Contient le mot de passe ?
aws_secretsmanager_secretOuiNon (juste le nom et l'ARN)
aws_secretsmanager_secret_versionOuiNon (secret_string_wo est write-only)
aws_db_instanceOuiNon (password_wo est write-only)
ephemeral "random_password"Non
ephemeral "aws_secretsmanager_secret_version"Non

Le mot de passe n'apparaît nulle part dans les artefacts Terraform.

L'implémentation est spécifique à chaque provider. Voici les arguments write-only les plus courants :

ProviderRessourceArgument write-onlyArgument version
awsaws_db_instancepassword_wopassword_wo_version
awsaws_secretsmanager_secret_versionsecret_string_wosecret_string_wo_version
azurermazurerm_key_vault_secretvalue_wovalue_wo_version
azurermazurerm_mysql_flexible_serveradministrator_password_woadministrator_password_wo_version
ConceptArgument classiqueArgument write-only
Stocké dans le stateOuiNon
Stocké dans le planOuiNon
Accepte des valeurs éphémèresNonOui
Accepte des valeurs non-éphémèresOuiOui
Détection de changementAutomatique via le stateVia _wo_version
Envoi au providerUniquement si changementÀ chaque opération

1. Toujours utiliser un argument write-only quand il existe

Section intitulée « 1. Toujours utiliser un argument write-only quand il existe »

Si le provider expose password_wo, préférez-le à password. Même si vous protégez votre state avec du chiffrement, ne pas stocker le secret est toujours plus sûr que le chiffrer.

Ne changez jamais la valeur d'un argument write-only sans incrémenter la version correspondante. Sans cette discipline, le provider peut rater la mise à jour.

3. Garder la version dans une variable ou un local

Section intitulée « 3. Garder la version dans une variable ou un local »

Pour les cas complexes, centralisez la version :

locals {
db_password_version = 1
}
resource "aws_db_instance" "example" {
# ...
password_wo = ephemeral.random_password.db_password.result
password_wo_version = local.db_password_version
}
resource "aws_secretsmanager_secret_version" "db_password" {
# ...
secret_string_wo = ephemeral.random_password.db_password.result
secret_string_wo_version = local.db_password_version
}

Même si les arguments write-only acceptent des chaînes en dur, préférez toujours une ressource ephemeral comme source. Cela élimine aussi le risque d'un commit accidentel du secret dans le code.

SymptômeCause probableSolution
password_wo is not a valid argumentLe provider n'expose pas cet argument (version trop ancienne)Mettre à jour le provider AWS ≥ 5.87
Le mot de passe ne change pas après un applypassword_wo_version n'a pas été incrémentéeIncrémenter la version et relancer
password_wo et password définis en même tempsLes deux arguments sont mutuellement exclusifsSupprimer password et utiliser uniquement password_wo
Invalid reference to ephemeral valueValeur éphémère utilisée dans un attribut classiqueUtiliser dans un argument write-only ou un contexte autorisé
  1. Les arguments write-only (_wo) transmettent un secret au provider sans jamais le stocker dans le state ou le plan.
  2. Terraform envoie la valeur à chaque opération (plan et apply), puisqu'il ne la stocke pas.
  3. Le mécanisme de version (_wo_version) permet de déclencher une mise à jour quand le secret change.
  4. Le pattern recommandé est : ephemeral génère → write-only transmet → zéro secret dans le state.
  5. L'implémentation est spécifique au provider : consultez le Terraform Registry pour vérifier quels arguments sont write-only.

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