
« Workspaces ou configurations séparées ? » se tranche par une propriété
technique, pas par une préférence d'organisation : un bloc backend
n'accepte aucune valeur nommée. Tout ce qui découle de là, ce que les
workspaces peuvent faire varier et ce qu'ils ne pourront jamais, se déduit de
cette seule phrase.
Tout ce qui suit a été exécuté sur Terraform v1.15.4. Deux idées répandues n'y survivent pas, celle des workspaces qui ne sépareraient pas l'état en backend distant, et celle de l'impossibilité d'avoir des droits différents par workspace.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Ce qu'un workspace isole, et surtout ce qu'il n'isole pas
- La contrainte technique qui borne l'usage des workspaces
- Ce qui peut varier par workspace, et ce qui ne le peut jamais
- Les deux motifs de rejet que la documentation énonce
- Comment faire circuler une donnée entre deux configurations séparées
- Ce que coûte la découpe, chiffres à l'appui
Prérequis
Section intitulée « Prérequis »- Terraform 1.11 ou plus récent (installer Terraform).
- Savoir créer et sélectionner un workspace (les workspaces Terraform).
Un workspace isole l'état, pas les objets
Section intitulée « Un workspace isole l'état, pas les objets »C'est le point de départ, et il est plus étroit qu'on ne le croit. Un workspace donne à la configuration un état séparé. Les objets réels, eux, ne savent rien des workspaces.
La démonstration tient en trois commandes. On applique dans dev, qui produit un
fichier, puis on bascule sur prod :
terraform workspace new dev && terraform apply -auto-approveterraform workspace new prodterraform plan # local_file.app will be created
Plan: 1 to add, 0 to change, 0 to destroy.Le fichier produit par dev est pourtant toujours sur le disque. prod ne
le voit pas, parce qu'il n'est pas dans son état, et l'apply suivant
l'écrase sans jamais l'avoir vu.
La contrainte qui explique tout le reste
Section intitulée « La contrainte qui explique tout le reste »Un bloc backend ne peut référencer aucune valeur nommée, ni variable, ni
local, ni terraform.workspace. Mesuré :
terraform { backend "local" { path = "etats/${terraform.workspace}.tfstate" }}Error: Variables not allowed
on main.tf line 3, in terraform: 3: path = "etats/${terraform.workspace}.tfstate"
Variables may not be used here.L'init sort en 1. Tous les workspaces d'un répertoire de travail écrivent
donc forcément dans le même backend, avec les mêmes droits d'accès à
l'état. Aucune option ne contourne cela, et c'est de là que vient toute la liste
des impossibilités qu'on lit ailleurs sans explication.
Mais un provider, lui, accepte les expressions
Section intitulée « Mais un provider, lui, accepte les expressions »Voici la dissymétrie que beaucoup de guides ratent, et elle change la
conclusion.
Le même terraform.workspace, placé dans un bloc provider, passe sans
broncher :
provider "tls" { proxy { url = "http://proxy-${terraform.workspace}.exemple.invalide:3128" }}Mesuré : init et plan sortent en 0.
La conséquence est importante. On peut faire varier par workspace le rôle avec lequel les ressources sont créées, ce que la documentation du backend S3 montre elle-même :
provider "aws" { assume_role = { role_arn = var.workspace_iam_roles[terraform.workspace] }}Les cas où les workspaces sont le bon outil
Section intitulée « Les cas où les workspaces sont le bon outil »Une même infrastructure, des variations légères, les mêmes droits, le même backend. Le motif habituel est une map indexée par le workspace, avec un repli :
locals { tailles = { default = 1 dev = 2 prod = 8 }}
output "taille" { value = lookup(local.tailles, terraform.workspace, local.tailles["default"])}Mesuré : dev rend 2, prod rend 8. Le troisième argument de
lookup est la valeur de repli, employée quand le workspace ne figure pas dans
la map. C'est bien la forme à trois arguments qu'il faut : seule celle à deux
arguments est dépréciée.
L'autre cas mis en avant par la documentation est le court terme, adossé au contrôle de version : « Non-default workspaces are often related to feature branches in version control. The default workspace might correspond to the main or trunk branch. » Le workspace naît avec la branche, et disparaît avec elle.
Les deux motifs de rejet, pas un seul
Section intitulée « Les deux motifs de rejet, pas un seul »La documentation en énonce deux, et les guides n'en retiennent souvent qu'un.
Le premier concerne les droits : « Workspaces are not appropriate for [...] deployments requiring separate credentials and access controls. » Un état de production protégé par des droits distincts ne peut pas partager le backend d'un environnement de développement.
Le second concerne la décomposition : « Workspaces alone are not a suitable tool for system decomposition because each subsystem should have its own separate configuration and backend. » Découper un grand système ne se fait donc pas avec des workspaces, quels que soient les droits.
L'alternative officielle, et ce qu'elle coûte
Section intitulée « L'alternative officielle, et ce qu'elle coûte »La réponse recommandée n'est pas « des répertoires », c'est un module réutilisable pour le code commun, plus une configuration racine par déploiement, chacune avec son propre backend. La racine, dit la documentation, « consists only of a backend configuration and a small number of module blocks ».
Ce n'est pas gratuit, et la documentation le chiffre elle-même : « Terraform installs a separate cache of plugins and modules for each working directory, so maintaining multiple directories can waste bandwidth and disk space. » Mesuré sur deux répertoires de ce guide, chaque cache pèse de l'ordre de 18 Mo. S'y ajoutent la mise à jour depuis le contrôle de version et la réinitialisation de chaque répertoire séparément.
Faire circuler une donnée entre deux racines
Section intitulée « Faire circuler une donnée entre deux racines »Une fois séparées, deux configurations ne se parlent plus. La passerelle officielle est la lecture de l'état distant de l'autre, par ses outputs déclarés :
data "terraform_remote_state" "socle" { backend = "local"
config = { path = "../socle/terraform.tfstate" }}La documentation signale le prix de ce couplage : terraform_remote_state
« creates a tighter coupling between configurations ». Les alternatives qu'elle
cite évitent ce couplage direct, en passant par des conventions : une
ressource étiquetée puis retrouvée par une source de données sur ses tags, un
enregistrement DNS à nom prévisible, ou un espace de clés partagé.
Les pièges mesurés
Section intitulée « Les pièges mesurés »Non, les workspaces ne partagent pas un seul état en backend distant
Section intitulée « Non, les workspaces ne partagent pas un seul état en backend distant »C'est l'erreur de modèle mental la plus coûteuse. « For remote state, the
workspaces are stored directly in the configured backend » : les états sont
bien séparés. Sur S3, chaque workspace non default vit sous
<workspace_key_prefix>/<workspace_name>/<key>, le préfixe valant env: par
défaut.
Ce qui est partagé, ce n'est pas l'état, c'est le backend : le bucket, et les droits qui y donnent accès.
Tous les backends ne gèrent pas les workspaces
Section intitulée « Tous les backends ne gèrent pas les workspaces »Dix seulement le font : AzureRM, Consul, COS, GCS, Kubernetes, Local, OSS, Postgres, Remote et S3. Raisonner comme si tout backend distant les supportait mène à une architecture qui ne tient pas.
Un workspace n'est pas privé
Section intitulée « Un workspace n'est pas privé »On lit souvent que les workspaces CLI seraient réservés au poste de travail. La documentation dit l'inverse : « Workspaces are also meant to be a shared resource. They are not private, unless you use purely local state and do not commit your state to version control. »
Ce qui est local, c'est seulement la sélection courante, rangée dans le
répertoire ignoré .terraform. Mesuré, c'est le fichier
.terraform/environment.
Le tableau de décision
Section intitulée « Le tableau de décision »| Ce que vous devez faire varier | Workspaces | Configurations séparées |
|---|---|---|
| une taille, un nombre d'instances | oui | possible, mais lourd |
| un nom dérivé de l'environnement | oui | possible |
| le rôle qui crée les ressources | oui, par le provider | oui |
| l'emplacement de l'état | non, jamais | oui |
| les droits d'accès à l'état | non, jamais | oui |
| le découpage en sous-systèmes | non | oui |
| une branche de fonctionnalité éphémère | oui | disproportionné |
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Correction |
|---|---|---|
Error: Variables not allowed dans un backend | une valeur nommée dans le bloc, terraform.workspace compris | ce besoin ne relève pas des workspaces : découper en configurations |
| un workspace écrase les objets d'un autre | les noms ne dérivent pas de terraform.workspace | dériver tous les noms d'objets du workspace |
| deux équipes voient l'état l'une de l'autre | un backend unique pour tous les workspaces | une racine par périmètre, chacune son backend |
| une valeur d'un autre périmètre est recopiée à la main | pas de passerelle entre racines | terraform_remote_state, ou une convention de tags |
| le backend choisi ne connaît pas les workspaces | backend hors des dix pris en charge | changer de backend, ou séparer les configurations |
init réinstalle tout dans chaque répertoire | cache de plugins par répertoire de travail | c'est le coût attendu de la découpe |
Mettre en pratique
Section intitulée « Mettre en pratique »Le lab workspaces ou configurations séparées livre une configuration à
arbitrer, dont l'en-tête précise que la production est gérée par une autre équipe
avec ses propres droits. Vous découpez ce qui doit l'être en deux racines, vous
rebranchez leur dépendance par terraform_remote_state, et vous laissez dans
un workspace ce qui ne varie que par la taille. Le contrôle décisif rejoue le
socle avec une autre plage réseau : une valeur recopiée à la main reste figée et
tombe. Il se joue hors ligne.
À retenir
Section intitulée « À retenir »- Un workspace isole un état, jamais les objets : deux workspaces qui visent le même objet s'écrasent en silence.
- Un bloc
backendn'accepte aucune valeur nommée : c'est la contrainte dont tout le reste découle. - Un bloc
provider, lui, accepte les expressions : le rôle qui crée les ressources peut varier par workspace. - Les credentials du backend et ceux du provider ne protègent pas la même chose.
- En backend distant, les états sont séparés (
env:sur S3) ; c'est le backend qui est commun. - La documentation pose deux motifs de rejet : droits distincts, et décomposition de système.
- L'alternative est un module commun plus une racine par déploiement, pas « des répertoires ».
- La découpe coûte : un cache de plugins par répertoire, et une réinitialisation par répertoire.
- Entre deux racines, la donnée passe par les outputs d'un état distant, au prix d'un couplage plus fort.
- Dix backends seulement gèrent des workspaces nommés.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous portent sur ce qui tranche en pratique : ce que le backend refuse, ce que le provider accepte, et ce que la séparation coûte vraiment.
Les deux motifs officiels
« Workspaces are not appropriate for [...] deployments requiring separate credentials and access controls. »« Workspaces alone are not a suitable tool for system decomposition because each subsystem should have its own separate configuration and backend. »La plupart des guides ne retiennent que le premier.La raison technique commune
Un blocbackend ne peut référencer aucune valeur nommée, terraform.workspace compris :Error: Variables not allowed
Variables may not be used here.
Tous les workspaces d'un répertoire écrivent donc dans le même backend, avec les mêmes droits sur l'état. Dès que ce point bloque, le besoin ne relève plus des workspaces.La dissymétrie, mesurée
Dans un blocprovider, une expression passe :provider "tls" {
proxy {
url = "http://proxy-${terraform.workspace}.exemple.invalide:3128"
}
}
init et plan sortent en 0.Dans un bloc backend, la même expression échoue en code 1 :Error: Variables not allowed
Ce que cela autorise
La documentation du backend S3 montre le motif :provider "aws" {
assume_role = {
role_arn = var.workspace_iam_roles[terraform.workspace]
}
}
On fait donc varier le rôle qui crée les ressources. Ce qu'on ne peut pas varier, c'est l'emplacement de l'état et les droits qui le protègent.Ce que dit la documentation
« For remote state, the workspaces are stored directly in the configured backend. »Sur S3, l'emplacement est<workspace_key_prefix>/<workspace_name>/<key>, avec env: comme préfixe par défaut.Sur un backend local, default reste à la racine et les autres vont sous terraform.tfstate.d/<nom>/.La confusion à éviter
Dire que les workspaces « ne séparent pas le state » enseigne le modèle mental inverse de la réalité.Ce qui est commun, c'est le backend : le bucket, le compte, et les droits qui y donnent accès. C'est bien assez pour disqualifier les workspaces quand deux environnements doivent être protégés différemment, mais la raison n'est pas un état partagé.Mesuré en trois commandes
terraform workspace new dev && terraform apply -auto-approve
terraform workspace new prod
terraform plan
# local_file.app will be created
Plan: 1 to add, 0 to change, 0 to destroy.
Le fichier écrit par dev est pourtant toujours sur le disque. prod ne le voit pas, car il n'est pas dans son état, et l'apply suivant l'écrase.La règle qui en découle
Tout nom d'objet doit dériver deterraform.workspace :filename = "${path.root}/sorties/app-${terraform.workspace}.conf"
Sans cela, l'isolation ne porte que sur la comptabilité, pas sur la réalité, et la collision est silencieuse.La formulation officielle
« Use one or more re-usable modules to represent the common elements, and then represent each instance as a separate configuration that instantiates those common elements in the context of a different backend. »La racine de chaque configuration « consists only of a backend configuration and a small number of module blocks ».Le critère, précisément
Ce n'est pas « des répertoires séparés ». Deux répertoires qui pointeraient le même backend et la même clé partageraient toujours un seul état.Ce qui compte est le backend distinct par déploiement. L'arborescence n'en est que la conséquence pratique.Ce que dit la documentation
« Terraform installs a separate cache of plugins and modules for each working directory, so maintaining multiple directories can waste bandwidth and disk space. This approach also requires extra tasks like updating configuration from version control for each directory separately and reinitializing each directory when you change the configuration. »Mesuré
Sur deux répertoires utilisant les mêmes providers, chaque.terraform/ pèse de l'ordre de 18 Mo. Le cache n'est pas mutualisé par défaut.La contrepartie
Ce coût est réel mais borné, et il s'oppose à un risque qui ne l'est pas : un état de production accessible avec les droits du développement. Un cache partagé (TF_PLUGIN_CACHE_DIR) réduit d'ailleurs la part disque du problème.Le mécanisme
data "terraform_remote_state" "socle" {
backend = "local"
config = {
path = "../socle/terraform.tfstate"
}
}
Seuls les outputs déclarés de l'autre configuration sont accessibles : c'est le contrat entre les deux.Le compromis
La documentation le dit :terraform_remote_state « creates a tighter coupling between configurations ».Les alternatives citées
Une ressource étiquetée puis retrouvée par une source de données sur ses tags, un enregistrement DNS à nom prévisible, ou un espace de clés partagé. Elles évitent de donner accès à l'état complet de l'autre périmètre, ce qui compte quand les droits diffèrent.Ce que dit la documentation
« Workspaces are also meant to be a shared resource. They are not private, unless you use purely local state and do not commit your state to version control. »La recommandation réelle est plus étroite que « réservés au local » : « We recommend using alternative approaches for complex deployments requiring separate credentials and access controls. »Ce qui est effectivement local
La sélection courante, et elle seule. Mesuré, elle vit dans.terraform/environment :cat .terraform/environment
dev
Ce fichier n'est jamais versionné : deux personnes sur la même copie de travail peuvent donc être sur deux workspaces différents sans le savoir.Pour aller plus loin
Section intitulée « Pour aller plus loin »- Gérer les variables par environnement : faire varier les valeurs, une fois la stratégie choisie.
- Monorepo vs un repo par stack : où ranger ces configurations séparées.
- Quiz Organiser les environnements Terraform : un contrôle des acquis sur la section.
- Les workspaces d'état : la référence officielle : le périmètre exact et les alternatives.
- Le bloc backend : la référence officielle : l'interdiction des valeurs nommées, et la configuration partielle.