KMS Key Rotation in Terraform: enable_key_rotation and Key Policies
Last reviewed: 2026-05-27 · 8 min read
5+ years AWS engineering · Open-source contributor
Last reviewed: 2026-05-27
KMS key rotation in Terraform requires two things: creating a customer-managed key with enable_key_rotation = true, and writing a key policy that restricts which principals can use, manage, and grant access to the key. A KMS key without rotation enabled is a finding in the AWS Well-Architected Security pillar (SEC08-BP03). A KMS key without a restrictive policy is a finding in SEC03.
Step 1 — Create a KMS key with rotation enabled
The AWS KMS automatic key rotation documentation notes that rotation creates new key material annually while retaining the ability to decrypt data encrypted with any previous version. The key ARN does not change after rotation.
resource "aws_kms_key" "bad" { description = "App encryption key" # enable_key_rotation not set — defaults to false}resource "aws_kms_key" "main" { description = "${var.env} application encryption key" deletion_window_in_days = 30 enable_key_rotation = true tags = { Environment = var.env ManagedBy = "terraform" }}resource "aws_kms_alias" "main" { name = "alias/${var.env}-app" target_key_id = aws_kms_key.main.key_id}Step 2 — Write a restrictive key policy
The default KMS key policy grants the AWS account root principal full access to the key. This means any IAM principal in the account can be granted KMS access through IAM policies alone. A restrictive key policy requires that KMS access is both allowed by the key policy and by IAM — defence in depth at the key level.
data "aws_iam_policy_document" "kms_key_policy" { # Required: allow root to manage key (prevents lockout) statement { sid = "EnableRootAccess" effect = "Allow" principals { type = "AWS" identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"] } actions = ["kms:*"] resources = ["*"] } # Key administrators: can manage the key but not encrypt/decrypt statement { sid = "AllowKeyAdministration" effect = "Allow" principals { type = "AWS" identifiers = var.key_admin_role_arns } actions = [ "kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*", "kms:Put*", "kms:Update*", "kms:Revoke*", "kms:Disable*", "kms:Get*", "kms:Delete*", "kms:ScheduleKeyDeletion", "kms:CancelKeyDeletion", ] resources = ["*"] } # Key users: can encrypt and decrypt statement { sid = "AllowKeyUse" effect = "Allow" principals { type = "AWS" identifiers = var.key_user_role_arns } actions = [ "kms:Decrypt", "kms:DescribeKey", "kms:Encrypt", "kms:GenerateDataKey*", "kms:ReEncrypt*", ] resources = ["*"] }}resource "aws_kms_key_policy" "main" { key_id = aws_kms_key.main.id policy = data.aws_iam_policy_document.kms_key_policy.json}Separate administrator and user statements follow the principle of least privilege at the key level
Step 3 — Attach the key to services that encrypt data
Reference the KMS alias ARN (not the raw key ID) in service configurations. The alias ARN is stable and human-readable in the AWS console. The services below each require an additional IAM grant in the key policy allowing the service principal to use the key.
# RDS encrypted with customer-managed KMS keyresource "aws_db_instance" "main" { identifier = "${var.env}-db" engine = "postgres" instance_class = "db.t4g.medium" storage_encrypted = true kms_key_id = aws_kms_key.main.arn # ... other settings}# Secrets Manager secret encrypted with customer-managed KMS keyresource "aws_secretsmanager_secret" "db_password" { name = "${var.env}/db/password" kms_key_id = aws_kms_alias.main.arn}# EBS volume encrypted with customer-managed KMS keyresource "aws_ebs_volume" "data" { availability_zone = "${var.region}a" size = 100 encrypted = true kms_key_id = aws_kms_key.main.arn}Multi-region KMS keys: when to use them
Multi-region keys replicate the same key material across AWS regions. They are required when your workload replicates encrypted data: S3 cross-region replication, DynamoDB Global Tables, or disaster recovery scenarios where a secondary region must decrypt data encrypted in the primary. For single-region workloads, multi-region keys add cost and complexity without benefit.
# Primary key in us-east-1resource "aws_kms_key" "primary" { provider = aws.us_east_1 description = "Multi-region primary key" multi_region = true enable_key_rotation = true}# Replica in eu-west-1resource "aws_kms_replica_key" "eu" { provider = aws.eu_west_1 description = "Multi-region replica" primary_key_arn = aws_kms_key.primary.arn deletion_window_in_days = 30 enabled = true}Cost tradeoffs
KMS pricing at a glance (as of 2026)
- Customer-managed key (CMK)$1.00/month per key
- Multi-region key replica$1.00/month per replica
- API requests (Encrypt, Decrypt, GenerateDataKey)$0.03 per 10,000 requests
- S3 Bucket Key (bucket_key_enabled = true)Reduces KMS API calls by up to 99%
Source: AWS KMS pricing
Related Security pillar articles
S3 Encryption Best Practices in Terraform →
IAM Least Privilege in Terraform →
CloudTrail Multi-Region Setup in Terraform →
AWS Security pillar overview →
Frequently asked questions
What does enable_key_rotation = true do in Terraform?↓
It enables automatic annual key rotation for the KMS customer-managed key. AWS generates new key material every year. Data encrypted with the old key material remains decryptable — KMS retains previous versions. Only customer-managed keys (CMKs) support automatic rotation; AWS-managed keys rotate automatically on a 3-year schedule.
Does KMS key rotation change the key ARN?↓
No. The key ARN and key ID remain the same after rotation. AWS creates new underlying key material but the key identifier is unchanged. Applications and Terraform resources that reference the key ARN do not need to be updated.
What is a KMS key policy and why does it matter?↓
A KMS key policy is a resource-based policy attached to the key itself. Unlike IAM policies, KMS key policies are the primary access control mechanism — if the key policy does not explicitly allow an IAM principal, IAM policies alone cannot grant access. The default key policy grants full access to the account root; production key policies should restrict this.
When should I use multi-region KMS keys in Terraform?↓
Use multi-region keys when your workload replicates data across AWS regions — for example, S3 cross-region replication or DynamoDB Global Tables. A multi-region key allows the same key material to decrypt data in multiple regions. For single-region workloads, single-region keys are simpler and sufficient.
Get an automated KMS configuration review
ArchGuard reviews your Terraform for KMS and encryption-at-rest gaps across the AWS Well-Architected Security pillar and delivers a branded PDF in 24 hours.
See how it works