KMS Key with Policy Patterns
Customer-managed KMS keys with sane key policies, aliases, rotation, and multi-region replicas.
Verification
Live-testedReally deployed, verified, idempotent and destroyed in a cloud sandbox.
Conformance
- Static validation (fmt · validate · tflint)
- Security scan clean (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live-tested — applied, verified, destroyed
Last verified 2026-06-11 · how we verify
Documentation
aws-kms
Customer-managed KMS key with a least-privilege, lockout-safe key policy,
automatic rotation on by default, aliases, and optional multi-region
replicas. Works with Terraform and OpenTofu (>= 1.6), AWS provider
>= 6.0, < 7.0. The generated key policy follows the AWS reference pattern —
account root keeps kms:* so the key is never orphaned, while administrators,
users, and AWS service principals get only the actions they need.
Status: static-validated, live-test pending. Ships under live-test quarantine — validated with
tofu fmt,tofu validate, andtflint. Real apply → verify → destroy against an AWS account is pending a cloud sandbox. KMS destroy is non-immediate by design:terraform destroyonly schedules deletion (deletion_window_in_days, 7–30 days), and the key remains billable (~$1/mo) and recoverable until the window elapses. This is an expected exception to the marketplace's instant-destroyConfirmedsemantics, not a teardown failure.
What you get:
aws_kms_key— symmetric or asymmetric/HMAC, with rotation, a deletion window, and an optional multi-region primary.aws_kms_key_policy— a generated least-privilege document (override with a fullpolicyJSON string if you need to).aws_kms_alias— one or morealias/<name>aliases pointed at the key.aws_kms_replica_key— cross-region replicas of a multi-region primary.
Secure defaults
- Rotation on (
enable_key_rotation = true) for symmetric encryption keys; automatically nulled for asymmetric/HMAC specs that do not support it. - Generated least-privilege policy: root keeps
kms:*(the non-lockout safeguard), administration and cryptographic use are split into separate statements, and service principals are pinned to your account viakms:CallerAccount. Key-user grant creation is restricted to AWS resources (kms:GrantIsForAWSResource). - 30-day deletion window by default — the maximum recovery runway.
bypass_policy_lockout_safety_checkdefaults tofalse; the safety check stays on.- Reserved
aws/*alias names and AWS-managed keys are rejected by validation.
Usage
module "kms" {
source = "./aws-kms"
description = "Application data encryption key"
aliases = ["my-app"]
key_administrator_arns = [aws_iam_role.kms_admin.arn]
key_user_arns = [aws_iam_role.app.arn]
key_service_users = ["logs.us-east-1.amazonaws.com"]
tags = { Environment = "prod" }
}
Multi-region replicas
A replica lives in a different region than the primary. Set multi_region = true so the primary is replicable, then create the replica from a root module
that has an aws provider in the target region — either by passing an aliased
provider to this module instance, or (cleaner) by instantiating the module a
second time with replica_primary_key_arn set to the primary's ARN under a
region-specific provider:
provider "aws" { region = "us-east-1" }
provider "aws" {
alias = "eu"
region = "eu-west-1"
}
module "kms_primary" {
source = "./aws-kms"
aliases = ["my-app"]
multi_region = true
}
# Replica via a second instance pinned to the EU provider.
module "kms_replica_eu" {
source = "./aws-kms"
providers = { aws = aws.eu }
aliases = ["my-app"]
replica_primary_key_arn = module.kms_primary.key_arn
replica_regions = { "eu-west-1" = {} }
}
(The inline replica_regions map is also supported on a single instance for
same-account, default-provider plans; cross-region applies require a provider
in the replica's region as shown above.)
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
description | string | (set) | Key description |
aliases | list(string) | [] | Alias names (alias/ prefix added automatically) |
key_usage | string | "ENCRYPT_DECRYPT" | ENCRYPT_DECRYPT, SIGN_VERIFY, GENERATE_VERIFY_MAC, KEY_AGREEMENT |
customer_master_key_spec | string | "SYMMETRIC_DEFAULT" | Key spec (RSA/ECC/HMAC for asymmetric/MAC keys) |
enable_key_rotation | bool | true | Yearly rotation (symmetric ENCRYPT_DECRYPT only) |
rotation_period_in_days | number | null | Custom rotation interval (90–2560); null = 365 |
deletion_window_in_days | number | 30 | Scheduled-deletion waiting period (7–30) |
is_enabled | bool | true | Key enabled for crypto operations |
multi_region | bool | false | Create a multi-region primary (required for replicas) |
policy | string | null | Full JSON policy override (replaces the generated one) |
key_administrator_arns | list(string) | [] | Principals allowed to administer the key |
key_user_arns | list(string) | [] | Principals allowed cryptographic use |
key_service_users | list(string) | [] | AWS service principals allowed use (account-pinned) |
enable_default_root_policy | bool | true | Grant account root kms:* (non-lockout safeguard) |
bypass_policy_lockout_safety_check | bool | false | Skip the lockout safety check |
replica_regions | map(object) | {} | Cross-region replicas {description, deletion_window_in_days, enabled, policy} |
replica_primary_key_arn | string | null | Replicate from an existing primary instead of creating one |
tags | map(string) | {} | Tags for key and replicas |
Outputs
key_id, key_arn, primary_alias, alias_arns, rotation_enabled,
replica_key_arns.
Provider pin
aws = {
source = "hashicorp/aws"
version = ">= 6.0, < 7.0"
}
License
Commercial — LicenseRef-IaCBazaar-Commercial. © IaC Bazaar. Original work
(not derived from a third-party module).