Skip to content

Terraform#

Terraform can be used to directly read and write secrets in Vault.

Warning

Caution should be taken as reading and writing secrets with terraform presents the security risk of secrets being included either in your configuration (terraform write resource) or in your terraform state file (terraform write resource, terraform read datasource). Security best practice would only be to use the terraform ephemeral vault_kv_secret_v2 datasource as the secret data will only be read at plan/apply time and not stored to the terraform state. Other examples have been included but should be evaluated to meet your team's security standards.

Note

For examples on how to configure a team's Vault namespace with terraform (i.e. policies, approles, etc.), see this example repository

Provider Authentication#

If you would like to use your own permissions in vault and have the vault CLI installed, the easiest way to get started is to run the following command which will generate a 1 hour token.

Bash Session
vault login --method=saml --namespace=admin

You can also set the VAULT_TOKEN environment variable instead. With either of these methods, there is no need to specify the token attribute in the Vault provider block.

Github Actions Provider Authentication#

If you would like to run terraform from a github action, you can use the hashicorp/vault-action along with JWT auth to retrieve a token. Setting exportToken: true will make the token available as the VAULT_TOKEN environment variable for subsequent steps (terraform will automatically recognize).

YAML
- name: Authenticate to Vault
  id: vault-auth
  uses: hashicorp/vault-action@v3
  with:
    url: ${{ env.VAULT_ADDRESS }}
    role: secm_repo_github_actions
    namespace: ${{ env.NAMESPACE }}
    path: jwt-github-actions
    method: jwt
    jwtGithubAudience: https://github.com/umn-<CESI>
    exportToken: true

- uses: actions/setup-node@v4
  with:
    node-version: 20 

- uses: hashicorp/setup-terraform@v3

- name: Terraform Init
  id: tf_init
  run: >-
    terraform init

- name: Terraform Apply
  id: tf_apply
  run: >-
    terraform apply -auto-approve

Provider Config#

Terraform
provider "vault" {
  address          = "https://hcp-vault-private-vault-fc507e0d.5d5b1f21.z1.hashicorp.cloud:8200/"
  # Either specify the namespace here in the provider block or at the individual resource level, not both
  namespace        = "admin/<CESI>"
  skip_child_token = true
}

terraform {
  required_providers {
    vault = {
      source  = "hashicorp/vault"
      version = "5.0.0"
    }
  }
}

Ephemeral vault_kv_secret_v2 (read)#

See this article for more information on terraform ephemeral resources, or this article for the provider documentation.

Terraform
# Ephemeral resource to read a secret from Vault
ephemeral "vault_kv_secret_v2" "example" {
  mount = "secret"
  name  = "db/creds/myapp"
}

# Use the secret to create a database user (just an example)
resource "postgresql_role" "app_user" {
  name     = "app_user"
  login    = true
  password = ephemeral.vault_kv_secret_v2.example.data["password"]
}

Datasource vault_kv_secret_v2 (read)#

Warning

See the warning at the top of the article for more information on why this datasource may not follow security best practices. This datasource has also been depreciated in favor of the ephemeral datasource.

Terraform
data "vault_kv_secret_v2" "example" {
  mount = "secret"
  name  = "db/creds/myapp"
}

Resource vault_kv_secret_v2 (write)#

Warning

See the warning at the top of the article for more information on why this resource may not follow security best practices.

Terraform
resource "vault_kv_secret_v2" "example" {
  mount               = "secret"
  name                = "db/creds/myapp"
  cas                 = 1
  delete_all_versions = true
  data_json = jsonencode(
    {
      zip = "zap",
      foo = "bar"
    }
  )
  custom_metadata {
    max_versions = 5
    data = {
      foo = "vault@example.com",
      bar = "12345"
    }
  }
}