Terraform just (November 2021) released the resource to create replica KMS keys! As the name says, a Multi-Region Key is a single key that’s available in two different AWS regions. There are few use cases, such as reducing cost of keys. Even a better case is the ability to share encrypted objects like AMI’s with other regions or accounts. Before I start showing the Terraform AWS KMS Multi-Region Keys Module, you have to know what AWS KMS is. Checkout my previous posts, AWS Key management service (KMS) – Part 1 and AWS KMS Customer Managed CMK with Terraform.
Terraform AWS KMS Multi-Region Keys Module code
We’ll need another “aws” provider. The second provider will be for your replicated key. This region will be different than the first provider.
provider "aws" {
alias = "replica"
region = var.replica_region
}
The primary key will still use the original “aws_kms_key” Terraform resource. I just added additional tags. Don’t forget the key alias!
resource "aws_kms_key" "primary" {
multi_region = true
description = var.description
customer_master_key_spec = var.key_spec
is_enabled = var.is_enabled
enable_key_rotation = var.rotation_enabled
policy = var.primary_key_policy
deletion_window_in_days = var.deletion_window_in_days
tags = merge(
var.tags,
{
"Multi-Region" = "true",
"Primary" = "true"
}
)
}
# Add an alias to the primary key
resource "aws_kms_alias" "primary" {
name = "alias/${var.alias}"
target_key_id = aws_kms_key.primary.key_id
}
Here comes the boom! The “aws_kms_replica_key” terraform resource is required to replicate the key that was just created with the above resource. That’s done with the “primary_key_arn” parameter. The key ARN of the replica key is the key ARN of the primary key.
Notice the “provider” is required in order to ensure this is created in another region. Now, you can reverse this design. You can have the provider on your primary key instead but this is my preference.
You can have a different or the same key policy. The alias, tags, description, deleteion_window_in_days can be the same or different, it doesn’t matter. It is “enabled” and there’s no option to rotate a replica key because the rotation is managed by the primary key.
# Create the replica key using the primary's arn.
resource "aws_kms_replica_key" "replica" {
provider = aws.replica
description = var.description
deletion_window_in_days = var.deletion_window_in_days
primary_key_arn = aws_kms_key.primary.arn
policy = var.replica_key_policy
tags = merge(
var.tags,
{
"Multi-Region" = "true",
"Primary" = "false"
}
)
}
# Add an alias to the replica key
resource "aws_kms_alias" "replica" {
provider = aws.replica
name = "alias/${var.alias}"
target_key_id = aws_kms_replica_key.replica.key_id
}
Module usage
Here’s an example on how to use this module.
data "aws_iam_policy_document" "ebs_key" {
statement {
sid = "Enable IAM User Permissions"
effect = "Allow"
actions = ["kms:*"]
resources = ["*"]
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${local.account_id}:root"]
}
}
statement {
sid = "Allow access for Key Administrators"
effect = "Allow"
actions = [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
]
resources = ["*"]
principals {
type = "AWS"
identifiers = [
"arn:aws:iam::${local.account_id}:user/${local.admin_username}",
"arn:aws:iam::${local.account_id}:role/${local.role_name}"
]
}
}
statement {
sid = "Allow use of the key"
effect = "Allow"
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
resources = ["*"]
principals {
type = "AWS"
identifiers = [
"arn:aws:iam::${local.account_id}:user/${local.admin_username}",
"arn:aws:iam::${local.account_id}:role/${local.role_name}"
]
}
}
statement {
sid = "Allow attachment of persistent resources"
effect = "Allow"
actions = [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
]
resources = ["*"]
principals {
type = "AWS"
identifiers = [
"arn:aws:iam::${local.account_id}:user/${local.admin_username}",
"arn:aws:iam::${local.account_id}:role/${local.role_name}"
]
}
condition {
test = "Bool"
variable = "kms:GrantIsForAWSResource"
values = ["true"]
}
}
}
module "ebs_key" {
source = "git@github.com:masterwali/terraform-kms-multi-region-module.git"
description = "KMS key for EBS volumes."
alias = "multi-region-ebs"
primary_key_policy = data.aws_iam_policy_document.ebs_key.json
replica_key_policy = data.aws_iam_policy_document.ebs_key.json
replica_region = "us-west-2"
tags = {
Name = "multi-region-ebs"
Owner = "Waleed"
}
}
Here’s my applied code. I set the EBS default encryption to use the multi-region-ebs key that I created using the module. Notice Multi-Region key ID’s start with “mrk” for Multi-Region Key.

Regions supported
Multi-Region keys are supported in all AWS Regions where AWS KMS is available.
Cost
Every pair, primary and replica, is priced as a single key! But the KMS quotas are still counted separately.
Complete Code
Here’s what you came for, https://github.com/masterwali/terraform-kms-multi-region-module. Learn more about AWS KMS Multi-Region Keys.
Don’t forget to subscribe for more 🙂
[…] Take a look at Terraform AWS KMS Multi-Region Keys. […]