Fanatical Support for AWS
Product Guide

Caution

Information in this section refers to a future offering that may not be available at this time. This documentation may also be updated at any time. Please reach out to your Account Manager for more information.

Managing Secrets

In Terraform

Rackspace recommends storing secrets for Terraform using AWS KMS; embed ciphertext values as data sources in Terraform configurations. Here’s some of the specifics and considerations:

  • Use aws_kms_key to create a KMS key for use by Terraform; you should apply a key policy that allows IAM roles and users to use the key, because federated accounts can’t access KMS keys using the default policy statements (e.g. most Rackers and Customers):
  resource "aws_kms_key" "terraform_config" {
    description = "terraform_config"
    is_enabled  = true

    policy = <<EOF
    {
      "Version": "2012-10-17",
      "Id": "key-default-1",
      "Statement": [
        {
          "Sid": "Default IAM policy for KMS keys",
          "Effect": "Allow",
          "Principal": {
            "AWS": "arn:aws:iam::123456789012:root"
          },
          "Action": "kms:*",
          "Resource": "*"
        },
        {
          "Sid": "Enable IAM user to perform kms actions as well",
          "Effect": "Allow",
          "Principal": {
            "AWS": "${module.terraform_circleci_iam.circleci_user_arn}"
          },
          "Action": "kms:*",
          "Resource": "*"
        }
      ]
    }
  EOF
  }
  • You will need to manually use the AWS CLI (and the key-id for the key you created in the previous step) to encrypt your secrets (mind any line endings if you use file:// to encrypt):
  $ aws kms encrypt \
      --key-id 438290482-e36a-4803-a7d0-db436278 \
      --plaintext "super_secret" \
      --encryption-context resource=my_database,key=password \
      --output text --query CiphertextBlob
  • Equipped with the ciphertext from the previous command, you can now use aws_kms_secrets to expose the secret as a data source for further use in Terraform:
  data "aws_kms_secrets" "example" {
    secret {
      # ... potentially other configuration ...
      name    = "master_password"
      payload = "base64secret=="

      context {
        resource = "db01"
        key      = "password"
      }
    }

    secret {
      # ... potentially other configuration ...
      name    = "master_username"
      payload = "base64secret=="

       context {
         resource = "db01"
         key      = "username"
       }                 
    }
  }

  resource "aws_rds_cluster" "my_database" {
    # ... other configuration ...
    master_password = "${data.aws_kms_secrets.example.plaintext["master_password"]}"
    master_username = "${data.aws_kms_secrets.example.plaintext["master_username"]}"
  }

Note the use of context values; these are used as encryption context key pairs in KMS. These context values can be used by KMS to ensure a specific secret is always accompanied by the same context values (integrity), and may be emitted in CloudTrail logs or included in error messages (debugging).