Comment Terraform 1.10 révolutionne la gestion des secrets en utilisant des valeurs éphémères dans Azure

Antoine LOIZEAUAntoine LOIZEAU
7 min read

Introduction à Terraform 1.10

Terraform est un outil d'infrastructure en tant que code qui permet aux équipes DevOps de provisionner et de gérer leurs infrastructures en toute sécurité et de manière reproductible. La version 1.10 de Terraform apporte une amélioration significative dans la gestion des secrets grâce à l'introduction des valeurs éphémères (ephemeral values). Cette nouveauté est particulièrement utile lorsqu'on travaille avec des secrets sensibles tels que des clés API, des mots de passe, et des certificats.

Dans cet article, je vais explorer comment Terraform 1.10 améliore la gestion des secrets, et je vais vous démontrer dans des exemples pratiques comment l’utiliser sur le cloud Microsoft Azure.

Comprendre les valeurs éphémères

Les valeurs éphémères dans Terraform sont conçues pour protéger les informations sensibles (mots de passes, clés privées, des certificats, des jetons d'API, etc.) en évitant de les stocker dans les fichiers d'état ou dans les plans de Terraform. En activant cette fonctionnalité, vous réduisez considérablement le risque de divulgation des données sensibles. Cela est particulièrement pertinent dans les environnements de cloud où les secrets jouent un rôle crucial pour l'accès aux ressources et aux services.

Jusqu’à cette version 1.10 de Terraform, ces secrets été conservés dans le fichier de plan ou d'état et comme ils été stockés en clair dans ces artefacts, tout accès mal géré aux fichiers les compromettrait.

Avantages des valeurs éphémères

  • Sécurité améliorée : Les secrets sont uniquement temporaires et ne sont pas persistés dans les fichiers d'état de Terraform, réduisant ainsi le risque de fuite.

  • Gestion simplifiée des secrets : Permet une meilleure gestion et rotation des secrets sans risque de fuite ou d'exposition dans les fichiers d'infrastructure.

  • Meilleures pratiques de sécurité : S'aligne avec les meilleures pratiques en matière de gestion des informations sensibles, telles que celles recommandées par des frameworks de sécurité comme CIS et NIST.

Comment utiliser les valeurs éphémères pour vos ressources Azure ?

Prérequis

  • Compte Azure et abonnement actif

  • Azure CLI installé

  • Terraform 1.10 installé

Pour l’exemple, j’utilise un SPN créé sur Entra ID grâce à cette commande Azure CLI où il faudra la mettre à jour votre scope:

az ad sp create-for-rbac --name ephemeral --role owner --scopes /subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY

Exemple : Sauvegarde d’un secret dans Azure Key Vault avec Terraform et utilisation sur un service Azure Microsoft SQL Server

Voici comment configurer et utiliser des valeurs éphémères avec Terraform 1.10 pour gérer un secret stocké dans Azure Key Vault.

💡
Les ressources éphémères sont supportées depuis Terraform 1.10 et supérieure.

Étape 1 : Configuration du fournisseur Azure

Commencez par configurer le fournisseur Azure dans votre fichier Terraform en mettant à jour les valeurs dans le provider liées à votre SPN.

provider "azurerm" {
  features {}
  # TODO: Update this values with your environment context
  tenant_id       = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  subscription_id = "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY"
  client_id       = "ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ"
  client_secret   = "Azur€CloudF0rFun!!!2025"
}

terraform {
  required_version = "1.11.2"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">= 4.0.0"
    }
    random = {
      source  = "hashicorp/random"
      version = ">= 3.7.1"
    }
  }
}

resource "azurerm_resource_group" "example" {
  name     = "ephemeral-example"
  location = "West US"
}

Étape 2: Génération de secrets temporaires

Utilisez le fournisseur random pour générer un mot de passe éphémère tel que:

ephemeral "random_password" "password" {
  length           = 16
  special          = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
}
💡
Plus de détail dans la documentation du provider: Ephemeral Resource - random_password

Étape 3 : Définition du secret dans Key Vault

Définissez votre ressource Key Vault et créez un secret dans celui-ci grâce aux nouveaux arguments “write-only” identifiable par leur nom finissant par “_wo” et “_wo_version” :

  • value_wo

  • value_wo_version

data "azurerm_client_config" "current" {}

resource "azurerm_key_vault" "example" {
  name                      = "ephemeral-key-vault"
  location                  = azurerm_resource_group.example.location
  resource_group_name       = azurerm_resource_group.example.name
  tenant_id                 = data.azurerm_client_config.current.tenant_id
  sku_name                  = "standard"
  enable_rbac_authorization = true
}

resource "azurerm_role_assignment" "secret_officer" {
  scope                = azurerm_key_vault.example.id
  role_definition_name = "Key Vault Secrets Officer"
  principal_id         = data.azurerm_client_config.current.object_id
}

resource "azurerm_key_vault_secret" "example" {
  name             = "vm-password"
  value_wo         = ephemeral.random_password.password.result
  value_wo_version = 1
  key_vault_id     = azurerm_key_vault.example.id
  depends_on       = [azurerm_role_assignment.secret_officer]
}

Étape 4 : Intégration du secret dans la configuration d’un service Azure SQL Server

Ici nous allons de nouveau utiliser une ressource éphémère pour récupérer la valeur du secret pour l'utiliser sur notre service Azure SQL Server.

ephemeral "azurerm_key_vault_secret" "password" {
  name         = azurerm_key_vault_secret.example.name
  key_vault_id = azurerm_key_vault.example.id
}

resource "azurerm_mssql_server" "example" {
  name                                    = "ephemeral-example"
  resource_group_name                     = azurerm_resource_group.example.name
  location                                = azurerm_resource_group.example.location
  version                                 = "12.0"
  administrator_login                     = "aloizeau"
  administrator_login_password_wo         = ephemeral.azurerm_key_vault_secret.password.value
  administrator_login_password_wo_version = 1
  minimum_tls_version                     = "1.2"

  azuread_administrator {
    login_username = "CurrentAzureADUser"
    object_id      = data.azurerm_client_config.current.object_id
  }
}

Et mon state ?

Pour clôturer cet article et vous prouvez que ce secret n’est plus présent dans mon state voici le fichier généré lors du déploiement de mon IaC :

{
  "version": 4,
  "terraform_version": "1.11.2",
  "serial": 51,
  "lineage": "2e3a9eda-4141-9317-df4d-a631412d280f",
  "outputs": {},
  "resources": [
    {
      "mode": "data",
      "type": "azurerm_client_config",
      "name": "current",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "client_id": "ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ",
            "id": "Y2xpZW50Q29uZmlncy9jbGllbnRJZD1jNjNjN2I4ZC0xYjQ3LTQ1MTctYTczMi03YjNkNDc5MmYzOWQ7b2JqZWN0SWQ9NzRlODdjYjUtYTViYS00YThkLWE2YWQtNGY4MjkwMDE2MDE1O3N1YnNjcmlwdGlvbklkPTZhMjVhNmQzLTdlYTQtNGE5MS04MDZiLWUzZDQ2MjlmMTc4Yzt0ZW5hbnRJZD1kZjIyODIyZS1mY2EwLTRmZDMtOTI2Ni0yYzRlYjI1ZTUxOTg=",
            "object_id": "SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS",
            "subscription_id": "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY",
            "tenant_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "timeouts": null
          },
          "sensitive_attributes": []
        }
      ]
    },
    {
      "mode": "managed",
      "type": "azurerm_key_vault",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 2,
          "attributes": {
            "access_policy": [],
            "contact": [],
            "enable_rbac_authorization": true,
            "enabled_for_deployment": false,
            "enabled_for_disk_encryption": false,
            "enabled_for_template_deployment": false,
            "id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example/providers/Microsoft.KeyVault/vaults/ephemeral-key-vault",
            "location": "westus",
            "name": "ephemeral-key-vault",
            "network_acls": [
              {
                "bypass": "AzureServices",
                "default_action": "Allow",
                "ip_rules": [],
                "virtual_network_subnet_ids": []
              }
            ],
            "public_network_access_enabled": true,
            "purge_protection_enabled": false,
            "resource_group_name": "ephemeral-example",
            "sku_name": "standard",
            "soft_delete_retention_days": 90,
            "tags": {},
            "tenant_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "timeouts": null,
            "vault_uri": "https://ephemeral-key-vault.vault.azure.net/"
          },
          "sensitive_attributes": [],
          "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInJlYWQiOjMwMDAwMDAwMDAwMCwidXBkYXRlIjoxODAwMDAwMDAwMDAwfSwic2NoZW1hX3ZlcnNpb24iOiIyIn0=",
          "dependencies": [
            "azurerm_resource_group.example",
            "data.azurerm_client_config.current"
          ]
        }
      ]
    },
    {
      "mode": "managed",
      "type": "azurerm_key_vault_secret",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "content_type": "",
            "expiration_date": null,
            "id": "https://ephemeral-key-vault.vault.azure.net/secrets/password/0878134668b94d3c92c734727ccf66b6",
            "key_vault_id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example/providers/Microsoft.KeyVault/vaults/ephemeral-key-vault",
            "name": "password",
            "not_before_date": null,
            "resource_id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example/providers/Microsoft.KeyVault/vaults/ephemeral-key-vault/secrets/password/versions/0878134668b94d3c92c734727ccf66b6",
            "resource_versionless_id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example/providers/Microsoft.KeyVault/vaults/ephemeral-key-vault/secrets/password",
            "tags": {},
            "timeouts": null,
            "value": "",
            "value_wo": null,
            "value_wo_version": 1,
            "version": "0878134668b94d3c92c734727ccf66b6",
            "versionless_id": "https://ephemeral-key-vault.vault.azure.net/secrets/password"
          },
          "sensitive_attributes": [
            [
              {
                "type": "get_attr",
                "value": "value"
              }
            ]
          ],
          "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInJlYWQiOjE4MDAwMDAwMDAwMDAsInVwZGF0ZSI6MTgwMDAwMDAwMDAwMH19",
          "dependencies": [
            "azurerm_key_vault.example",
            "azurerm_resource_group.example",
            "azurerm_role_assignment.secret_officer",
            "data.azurerm_client_config.current",
            "ephemeral.random_password.password"
          ]
        }
      ]
    },
    {
      "mode": "managed",
      "type": "azurerm_mssql_server",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "administrator_login": "aloizeau",
            "administrator_login_password": null,
            "administrator_login_password_wo": null,
            "administrator_login_password_wo_version": 1,
            "azuread_administrator": [
              {
                "azuread_authentication_only": false,
                "login_username": "CurrentAzureADUser",
                "object_id": "SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS",
                "tenant_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
              }
            ],
            "connection_policy": "Default",
            "fully_qualified_domain_name": "ephemeral-example.database.windows.net",
            "id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example/providers/Microsoft.Sql/servers/ephemeral-example",
            "identity": [],
            "location": "westus",
            "minimum_tls_version": "1.2",
            "name": "ephemeral-example",
            "outbound_network_restriction_enabled": false,
            "primary_user_assigned_identity_id": "",
            "public_network_access_enabled": true,
            "resource_group_name": "ephemeral-example",
            "restorable_dropped_database_ids": [],
            "tags": {},
            "timeouts": null,
            "transparent_data_encryption_key_vault_key_id": "",
            "version": "12.0"
          },
          "sensitive_attributes": [
            [
              {
                "type": "get_attr",
                "value": "administrator_login_password"
              }
            ],
            [
              {
                "type": "get_attr",
                "value": "administrator_login_password_wo"
              }
            ]
          ],
          "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjozNjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjMwMDAwMDAwMDAwMCwidXBkYXRlIjozNjAwMDAwMDAwMDAwfX0=",
          "dependencies": [
            "azurerm_key_vault.example",
            "azurerm_key_vault_secret.example",
            "azurerm_resource_group.example",
            "azurerm_role_assignment.secret_officer",
            "data.azurerm_client_config.current",
            "ephemeral.azurerm_key_vault_secret.password",
            "ephemeral.random_password.password"
          ]
        }
      ]
    },
    {
      "mode": "managed",
      "type": "azurerm_resource_group",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example",
            "location": "westus",
            "managed_by": "",
            "name": "ephemeral-example",
            "tags": {},
            "timeouts": null
          },
          "sensitive_attributes": [],
          "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo1NDAwMDAwMDAwMDAwLCJkZWxldGUiOjU0MDAwMDAwMDAwMDAsInJlYWQiOjMwMDAwMDAwMDAwMCwidXBkYXRlIjo1NDAwMDAwMDAwMDAwfX0="
        }
      ]
    },
    {
      "mode": "managed",
      "type": "azurerm_role_assignment",
      "name": "secret_officer",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "condition": "",
            "condition_version": "",
            "delegated_managed_identity_resource_id": "",
            "description": "",
            "id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example/providers/Microsoft.KeyVault/vaults/ephemeral-key-vault/providers/Microsoft.Authorization/roleAssignments/3c5661a1-e732-a747-87b2-daec9e7056e0",
            "name": "3c5661a1-e732-a747-87b2-daec9e7056e0",
            "principal_id": "SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS",
            "principal_type": "ServicePrincipal",
            "role_definition_id": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/providers/Microsoft.Authorization/roleDefinitions/b86a8fe4-44ce-4948-aee5-eccb2c155cd7",
            "role_definition_name": "Key Vault Secrets Officer",
            "scope": "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ephemeral-example/providers/Microsoft.KeyVault/vaults/ephemeral-key-vault",
            "skip_service_principal_aad_check": null,
            "timeouts": null
          },
          "sensitive_attributes": [],
          "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInJlYWQiOjMwMDAwMDAwMDAwMH19",
          "dependencies": [
            "azurerm_key_vault.example",
            "azurerm_resource_group.example",
            "data.azurerm_client_config.current"
          ]
        }
      ]
    }
  ],
  "check_results": null
}

Conclusion

Terraform 1.10 avec les valeurs éphémères améliore considérablement la gestion des secrets en garantissant leur sécurité et en simplifiant la rotation et l'administration des informations sensibles.

L'utilisation des secrets avec Azure Key Vault permet de renforcer la sécurité des déploiements Azure tout en suivant les meilleures pratiques en matière de gestion de l'infrastructure.

Essayez cette nouvelle fonctionnalité pour sécuriser vos infrastructures cloud dès aujourd'hui et au besoin vous savez qui contacter si vous souhaitez en savoir plus.

💡
Le lien vers le repository GitHub contenant le code source de cet article: https://github.com/aloizeau/tf-ephemeral/

Liens utiles

0
Subscribe to my newsletter

Read articles from Antoine LOIZEAU directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Antoine LOIZEAU
Antoine LOIZEAU

Ayant eu de multiples expériences dans le monde du conseil, j'ai pu acquérir une expertise dans la conception et la construction de services de collaboration d'entreprise. Je suis passionné par les technologies Microsoft et surtout Azure. Aujourd'hui je possède une solide expérience en méthodologie de développement et j'ai mené des équipes de développement technique au succès. Je possède également une solide connaissance de l'infrastructure qui fait de moi une ressource efficace pour mettre en œuvre la transformation numérique vers le cloud Microsoft. Je suis un professionnel efficace et honnête qui aime relever les challenges. Aimant partager mes connaissances; je suis à l'aise en tant que Technical Leader et en tant que membre d'une équipe. Mes compétences techniques sont les suivantes: Azure, DevOps, Architecture Applicative, Développement de solution Cloud Native, écosystème Microsoft... et bien d'autres. Pour voir mes certifications Microsoft : https://www.youracclaim.com/users/antoine-loizeau