How to manage secrets in Terraform

To help you manage secrets in Terraform, we’ve built a Terraform provider and a state backend. For a detailed use case, check out the beta announcement.

In this step-by-step guide, you’ll learn how to keep hardcoded secrets out of Terraform code and securely share your .tfstate file.

  1. Install the SecretHub Terraform provider
  2. Write secrets using the secrethub_secret resource
  3. Read secrets using the secrethub_secret data source
  4. Import exisiting secrets into your Terraform project
  5. Use SecretHub as a secure backend for your .tfstate

For full reference, check out the GitHub repository and the reference documentation.

Prerequisites

In this guide we assume that you have installed the SecretHub CLI, created an account and a set up a repository. To do so, you can follow these two simple steps:

  1. Install the CLI
  2. Create a free account

Getting help

Come chat with us on Discord or email us at support@secrethub.io


Step 1: Install the provider

To install the SecretHub Terraform provider, download and extract the latest release and move the binary to your Terraform plugin directory (~/.terraform.d/plugins/, or %APPDATA%\terraform.d\plugins on Windows). You may have to create this directory if it doesn’t exist yet.

Configure the provider

With the provider installed, you can configure it in your project by passing in a credential for your SecretHub account.

provider "secrethub" {
  credential = "${file("~/.secrethub/credential")}"
}

You can also source the credential from the SECRETHUB_CREDENTIAL environment variable.

If upon signup you’ve chosen to lock your credential with a passphrase, you need to set the credential_passphrase field on the provider. You can use a Terraform variable for this and let it prompt on every run:

variable "secrethub_passphrase" {}

provider "secrethub" {
  credential            = "${file("~/.secrethub/credential")}"
  credential_passphrase = "${var.secrethub_passphrase}"
}

These values can also be put in a .tfvars file or defined as an enviroment variable prefixed with TF_VAR to save some typing and help with automation.

With the provider configured, you can run:

terraform init

That’s it. The SecretHub Terraform provider is now properly setup and ready to be used.


Step 2: Write secrets

Before writing secrets, make sure you have created a repo, either in your shared organization workspace or in your personal workspace.

In the examples throughout this guide, we’re using the your-username/start as the repo name. Make sure to change that with yours.

To create a secret, you can use the secrethub_secret resource. You can specify a value directly or you can auto-generate a value:

resource "secrethub_secret" "db_password" {
  path = "your-username/start/db-password"

  generate {
    length      = 22
    use_symbols = true
  }
}

resource "secrethub_secret" "db_user" {
  path  = "your-username/start/db-user"
  value = "mydbuser"
}

Run terraform apply and your secrets are now on SecretHub! You can use them now to create other resources:

resource "heroku_app" "your_app" {
  name   = "your-app"
  region = "us"

  sensitive_config_vars {
    DB_PASSWORD = "${secrethub_secret.db_password.value}"
    DB_USER     = "${secrethub_secret.db_user.value}"
  }
}

Or, for the purposes of this tutorial, just print their values:

output "db_password" {
  value = "${secrethub_secret.db_password.value}"
}

output "db_user" {
  value = "${secrethub_secret.db_user.value}"
}

Now, let’s say the requirements for your password strength change: the password needs to be at least 28 characters long. You can simply change the length field and Terraform will automatically generate a new password for you and propagate it to where it’s used throughout your project:

resource "secrethub_secret" "db_password" {
  path = "your-username/start/db-password"

  generate {
    length = 28
  }
}

You can also manually tell Terraform to generate a new value for the secret, by using the taint command:

terraform taint secrethub_secret.db_password && terraform apply

Path redundancy

To avoid redundancy in secret paths throughout your secret resources, you can specify a path_prefix on the provider, which will be applied to every secret configured using that provider:

provider "secrethub" {
  path_prefix = "your-username/start"
}

resource "secrethub_secret" "db_password" {
  path = "db-password"

  generate {
    length      = 22
    use_symbols = true
  }
}

resource "secrethub_secret" "db_user" {
  path  = "db-user"
  value = "mydbuser"
}

This can be overridden per individual resource:

resource "secrethub_secret" "other_db_password" {
  path_prefix = "your-username/some-other-repo"
  path        = "db-password"

  generate {
    length = 16
  }
}

Alternatively, you can configure a second provider and give that a different path prefix.


Step 3: Read external secrets

To read a secret that has been created outside the scope of this Terraform project (e.g. through the CLI or in a different Terraform project), you can use the secrethub_secret data source. You only need to specify the path of the secret:

provider "secrethub" {
  path_prefix = "your-username/start"
}

data "secrethub_secret" "db_password" {
  path = "db-password"
}

data "secrethub_secret" "db_user" {
  path = "db-user"
}

As you can see in this example, the path_prefix specified on the provider also applies to secret data sources.

Just like the secret resource, you can use the value of the secret data source throughout your project by referencing the value field.

resource "heroku_app" "your_app" {
  name   = "your-app"
  region = "us"

  sensitive_config_vars {
    DB_PASSWORD = "${data.secrethub_secret.db_password.value}"
    DB_USER     = "${data.secrethub_secret.db_user.value}"
  }
}

By default the data source retrieves the latest version of your secret. To insteadget a specific version of a secret, just add the version number to the path:

data "secrethub_secret" "db_password_version_1" {
  path = "your-username/start/db-password:1"
}

Step 4: Import an existing secret

If you already have some secrets on SecretHub and you would like to start managing these using Terraform, you’re going to need them to be added to your .tfstate. For this you can leverage Terraform’s import command.

First declare the resource in your Terraform project:

resource "secrethub_secret" "db_password" {
  path = "your-username/start/db-password"
}

Then, instead of running terraform apply, run the import command, linking the secret on SecretHub to the secrethub_secret resource you’ve just declared:

terraform import secrethub_secret.db_password your-username/start/db-password

The secret has now beed added to your .tfstate. If you decide to remove the resource from your configuration, it will now also delete it on SecretHub.


Step 5: Backend for your .tfstate

Not only does SecretHub integrate with Terraform through a provider, it can also serve as a secure backend for your .tfstate.

Because it simply treats your .tfstate like any other secret in SecretHub, you get all the security features that your .tfstate deserves without any additional setup.

To use SecretHub as a state backend, you need to run the SecretHub HTTP Proxy. You can run it as a Docker container:

docker run -it -p 127.0.0.1:8080:8080 --name secrethub -v $HOME/.secrethub:/secrethub secrethub/http-proxy

For more installation options, check out the GitHub page.

Then add the following backend configuration to your Terraform project:

terraform {
  backend "http" {
    address = "http://localhost:8080/v1beta/secrets/raw/your-username/start/terraform.tfstate"
  }
}

This will write your .tfstate to SecretHub at path your-username/start/terraform.tfstate. To start the state migration, run:

terraform init

Terraform will now prompt to migrate your local .tfstate to SecretHub. Afterwards, Terraform clears the local state, leaving only a local backup copy present. You can verify that the state got migrated correctly by running:

terraform state pull

Alternatively, verify it using the SecretHub CLI:

secrethub read your-username/start/terraform.tfstate

You can then safely delete the remaining .tfstate.backup file.


Next steps

You now know all there is to know to manage secrets in Terraform with the SecretHub integration.

To learn more about SecretHub, check out these resources:

Finally, to get your account back to a clean state, you can run:

terraform destroy

And you can remove the start repository on SecretHub used in this guide:

secrethub repo rm your-username/start

And you’re done. Happy coding!