Skip to main content

Hard-Coded Secrets

Why is this important?

All modern applications rely on certain secrets to run. Secrets that are provided in configurations to Terraform are usually with significant write permissions that can modify your infrastructure in your cloud service provider (CSP). Keeping these secrets safe and up-to-date is critical to the security of the infrastructure and applications.

If secrets are part of your source configuration, then the whole team or multiple teams have access to them. If the source configuration is public, then everyone has access to them. Source configuration can be public, if it's on a public Github repository, or bundled with your cloud service provider, e.g. the AWS Secret Access Key. This has led to many high-profile breaches as attackers can gain control of your cloud account.

Fixing Hard-coded Secrets for use with Terraform Cloud or Terraform Enterprise

Option A: Use Terraform Login

  1. # terraform login [hostname]
  2. By default, Terraform will obtain an API token and save it in plain text in a local CLI configuration file called credentials.tfrc.json

Option B: Use a Terraform CLI Configuration File

  1. Configure a Terraform CLI Configuration File:

    credentials "app.terraform.io" {
    token = "xxxxxx.atlasv1.zzzzzzzzzzzzz"
    }
  2. The location of the Terraform CLI configuration file can also be specified using the TF_CLI_CONFIG_FILE environment variable like:

    export TF_CLI_CONFIG_FILE="$HOME/.terraformrc-custom"

Option C: [Advance] Write and Use Credentials Helper Plugin

  1. Write a Terraform Credentials Helpers

  2. Replace your configuration block with credentials_helper:

    credentials_helper "example" {
    args = []
    }

Fixing Hard-coded Secrets For Use In Provisioning Infrastructure

Option A: Use a Separate Variable File and Do Not Check File In

  1. Go through the issues that GuardRails identified in the PR

  2. An example file main.tf with hardcoded secret is shown below:

    variable "db_password" {
    description = "The password of the db user."
    type = string
    default = "mydbpassword"
    }
    ...
  3. Remove the line 'default' and main.tf should look like the following:

    variable "db_password" {
    description = "The password of the db user."
    type = string
    }
    ...
  4. Create a new file named terraform.tfvars

  5. It should look like this:

    variable "db_password" {
    type = string
    default = "mydbpassword"
    }
    ... other variables
  6. Your directory should have 2 files: main.tf and terraform.tfvars

  7. If you're using git, add terraform.tfvars to your .gitignore file so git will ignore and not check this file into the repository:

    git rm --cached main.tf
    echo "terraform.tfvars" >> .gitignore
  8. Test it! Add a -var-file flag to your terraform command:

    terraform plan #-var-file=terraform.tfvars
    # If `terraform.tfvars` or any `*.auto.tfvars` files are present, they will be automatically loaded.
  9. Ship it 🚢 and relax 🌴

Option B: Use Provider's Credentials File

  1. Go through the issues that GuardRails identified in the PR

  2. Using AWS (as a provider) for example, a file main.tf with hardcoded AWS secret is shown below:

    provider "aws" {
    region = "us-west-2"
    access_key = "my-access-key"
    secret_key = "my-secret-key"
    }
  3. Locate or create your AWS credentials file (default is "$HOME/.aws/credentials" on Linux and OS X, or "%USERPROFILE%\.aws\credentials" for Windows)

  4. Remove 'access_key' and 'secret_key', add 'profile' and 'shared_credentials_file'; main.tf should look like the following:

    provider "aws" {
    region = "us-west-2"
    shared_credentials_file = "/Users/tf_user/.aws/credentials"
    profile = "customprofile" # if you have multiple profiles, else default is used
    }
  5. Test it!

    terraform plan
  6. Ship it 🚢 and relax 🌴

More information