Categories
Cloud

Create Multiple AWS KMS keys and secrets with Terraform

Intro and Aim:

A quick post here as I didn’t find a suitable example online when researching.

The aim is to create multiple CMKs (Customer Managed Keys) in AWS KMS (Key Management Service) with Terraform with unique aliases from a list of variables.

We will also create secrets in AWS Secrets Manager with the newly created CMKs used for the Encryption key. For now the secrets will be created without contents.

Steps below:

Prerequisites:

Install terraform and set environment variables to connect to my AWS account (rather than entering keys in my terraform code.

export AWS_ACCESS_KEY_ID=<ACCESSKEYID>
export AWS_SECRET_ACCESS_KEY=<SECRET>
export AWS_SESSION_TOKEN=<SESSTOK>

Code:

The key to achieving this aim was the use of count.index in my terraform code to create multiple resources of the same kind, interating through my list of variables.

Files:

$ find .
.
./output.tf
./main.tf
./secrets.tf
./env
./env/eu-west-1.tfvars
./variables.tf

main.tf:

provider "aws" {
  region = var.aws_region
}

resource "aws_kms_key" "clustername" {
  count       = length(var.clustername) //count will be number of keys
  description = var.clustername[count.index]
}

resource "aws_kms_alias" "clustername-alias" {
  count         = length(var.clustername) //count will be number of key aliases
  name          = "alias/${var.clustername[count.index]}-alias"
  target_key_id = aws_kms_key.clustername[count.index].key_id
}

secrets.tf (note the depends_on field, this ensures the KMS key alias is created before proceeding).

resource "aws_secretsmanager_secret" "app-keystore" {
  depends_on = [aws_kms_alias.clustername-alias]
  count      = length(var.clustername) //count will be number of keys
  name       = "${var.clustername[count.index]}-concat-app-keystore"
  kms_key_id = "alias/${var.clustername[count.index]}-alias"
}

variables.tf:

variable "aws_region" {
  type        = string
  description = "AWS provider to be used to create roles, policies, S3 objects, ..."
}

variable "clustername" {
  type = list(any)
}

./env/eu-west-1.tfvars

# Do not change the order of these default values. it will force the build to destory and rebuild
aws_region          = "eu-west-1"

clustername = [
             "euw1-test-c001",
             "euw1-test-c002",
             "euw1-test-c003",
             "euw1-test-c004",
             ]

output.tf:

output "kms_key_id" {
  value = aws_kms_key.clustername[*].arn
}

output "kms_alias_arn" {
  value = aws_kms_alias.clustername-alias[*].arn
}

output "aws_secretsmanager_secret" {
  value = aws_secretsmanager_secret.app-keystore[*].arn
}

Execution:

Use the terraform commands, init, validate, plan before applying with

terraform apply --var-file=./env/eu-west-1.tfvars

The output of terraform apply below:

Check via AWS console:

Here we see the keys created, along with the aliases:

And the secrets:

Clean Up:

Run terraform destroy to clean up the resources created:

References:

https://paulkamau.medium.com/terraform-tips-how-to-create-multiple-aws-s3-buckets-with-a-single-resource-config-c89c460a1aa6

https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html

https://www.terraform.io/language/meta-arguments/count

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias

https://www.terraform.io/language/meta-arguments/depends_on

https://blog.gruntwork.io/a-comprehensive-guide-to-managing-secrets-in-your-terraform-code-1d586955ace1