Make your Terraform deployments more secure with Ephermal resources

Make your Terraform deployments more secure with Ephermal resources

From Terraform version 1.10 and later we now have support for ephermal blocks which are resources that will not be persisted to the Terraform state. A reoccurring issue with Terraform is secrets and sensitive values in state management. Sure, state is for example encrypted at rest when residing in Azure Storage but that does not mean that I as an Azure Administrator with access to the blob can't open it and find the secret values stored in there.

Ephermal resource blocks in Terraform resolve this issue as the resource data is not persisted to the state-file (or any plan or state artifact) as is the case with a data or resource block for example. ephermal blocks are essentially temporary resources used to reference data and connect to other systems. Once Terraform is done reading from the resources it closes it and will only use the data for the duration of the actual run-phase.

Were you aware that secrets were available in Terraform state with resource and data blocks? I don't know if too many are aware of this.

Example with Azure Keyvault

To demonstrate what this looks like in the actual "wild" we will first create a Terraform deployment that contains a key vault and a key vault secret. We do this by first defining our teraraform block and provider configuration:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.12.0"
    }
  }
}

provider "azurerm" {
  features {}
  subscription_id = "-your-subscription-id-"
}

data "azurerm_client_config" "current" {}

The data block will be used by the deployment later

Once we have that we will add our resource group, key vault and key vault secret:

resource "azurerm_resource_group" "this" {
  name     = "rg-prod-we-kv"
  location = "West Europe"
}

resource "azurerm_key_vault" "this" {
  name                       = "kv-prod-we-secret"
  location                   = azurerm_resource_group.this.location
  resource_group_name        = azurerm_resource_group.this.name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  sku_name                   = "premium"
  soft_delete_retention_days = 7

  access_policy {
    tenant_id = data.azurerm_client_config.current.tenant_id
    object_id = data.azurerm_client_config.current.object_id

    key_permissions = [
      "Create",
      "Get",
    ]

    secret_permissions = [
      "Set",
      "Get",
      "Delete",
      "Purge",
      "Recover"
    ]
  }
}

resource "azurerm_key_vault_secret" "this" {
  name         = "secret-sauce"
  value        = "szechuan"
  key_vault_id = azurerm_key_vault.this.id
}

This is what the configuration looks like:

This is for demo purposes, I would not recommend creating secrets this way in a production environment.

Now if we look at the terraform.tfstate file we can drill down into the details of it and sure enough find the secret we created:

Here is the password, in clear text. The first time I learned that state deals with secrets this way I must admit I was a bit shocked. This is why it is important to store the statefiles in a safe place, using services that provide encryption like Azure Storage.

Similar deployment but with an Ephermal resource instead

In my second deployment we will reference the previously created key using the ephermal Terraform resource:

ephemeral "azurerm_key_vault_secret" "this" {
  name         = "secret-sauce"
  key_vault_id = data.azurerm_key_vault.this.id
}

The resulting terraform.tfstate file looks like this instead:

No reference to the key vault secret or its values in this statefile

Here is a side by side comparison of the two different statefiles with my first configuration on the left and the configuration with the ephermal resource on the right:

On the left, key vault secret resource visable whilst on the right it is not there

Conclusion

Today we looked at deploying resources that deal with secrets. It was key vaults and its components but it could also have been a virtual machine where we need to deal with its local administrator password in some way.

There are other resources and deployments that will contain sensitive values. Maybe secrets should be created outside of your IaC configuration and referenced by Terraform using ephermal blocks instead? How would you do it?

Hope you found this useful.

References

Ephemeral resource configuration reference | Terraform | HashiCorp Developer
Learn about ephemeral resource blocks that you can specify in Terraform configurations. Ephemeral resource blocks represent temporary resources that Terraform does not store in state.
Plugin Development - Framework: Ephemeral Resources | Terraform | HashiCorp Developer
How to build ephemeral resources in the provider development framework. Ephemeral resources allow Terraform to reference external data, while guaranteeing that this data will not be persisted in plan or state.

About me

About me
If you have landed on my page you will have already understood my passion for tech, but obviously there is more to life than that. Here I will try and outline a few of my other hobbies. Strength training I am a person who loves to move around and challenge