Managing encryption keys as code requires a clear understanding of how AWS Key Management Service integrates with Terraform, how key policies are expressed, and how multi-region and state encryption scenarios are handled. This article covers the complete lifecycle from initial key creation to policy updates, alias management, and audit alignment, using patterns that keep security consistent with infrastructure as code principles.
Prerequisites and Project Layout
Working with AWS KMS through Terraform assumes a baseline environment that is ready for secure infrastructure provisioning.
- AWS CLI configured
- Terraform installed
- Basic understanding of encryption concepts
- Resources that need encryption
A typical project structure for a focused KMS workspace is:
aws-kms-terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars
This layout separates provider configuration, key definitions, outputs, and variable values. Keeping the key policy in main.tf with variables for project name and environment enables reuse across teams.
Core KMS Key Resource
AWS Key Management Service is a managed service for creating and controlling encryption keys. Terraform models a key with the awskmskey resource. Common baseline arguments include description, deletionwindowindays, enablekey_rotation, policy, and tags.
A basic configuration defines a key with account root permissions and enables rotation:
```hcl
provider "aws" {
region = var.aws_region
}
resource "awskmskey" "main" {
description = "KMS key for ${var.projectname}"
deletionwindowindays = 7
enablekeyrotation = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.awscalleridentity.current.account_id}:root"
}
Action = "kms:"
Resource = ""
}
]
})
tags = {
Environment = var.environment
}
}
resource "awskmsalias" "main" {
name = "alias/${var.projectname}"
targetkeyid = awskmskey.main.keyid
}
data "awscalleridentity" "current" {}
```
The alias resource provides a stable name for the key and simplifies references in other services. The caller identity data source injects the current account ID into the policy principal.
For tighter access control, the policy can be built with awsiampolicy_document and restrict actions to specific roles:
```hcl
resource "awskmskey" "example" {
description = "Example KMS key"
policy = data.awsiampolicydocument.example.json
deletionwindowindays = 7
}
data "awsiampolicy_document" "example" {
statement = [
{
effect = "Allow"
actions = [
"kms:DescribeKey",
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey",
]
principals = [{
type = "AWS"
identifiers = ["arn:aws:iam::123456789012:role/example-role"]
}]
resources = ["*"]
},
]
}
```
This configuration ensures that only the specified IAM role can perform encryption and decryption operations on the key.
Multi-Region Keys and Replicas
Multi-region keys provide active-active key material across AWS regions. The primary key is created in one region and replica keys are created in others.
Primary region key:
hcl
resource "aws_kms_key" "primary" {
description = "Multi-region primary key for ${var.project_name}"
deletion_window_in_days = 7
enable_key_rotation = true
multi_region = true
tags = {
Environment = var.environment
}
}
Secondary region replica:
hcl
resource "aws_kms_key" "secondary" {
provider = aws.secondary_region
description = "Multi-region replica key for ${var.project_name}"
deletion_window_in_days = 7
multi_region = true
primary_key_arn =
The primary KMS key initially created was created as a multi-region KMS key. You can create a primary KMS key or a replica of a multi-region primary KMS key for use with the Mozilla SOPS tool.
Modules that wrap this functionality often support optional features:
- Create a primary KMS key in either single/multi-region
- Create a replica KMS key in a different region of the primary multi-region KMS key
- Create a corresponding SOPS file containing the primary KMS or replica KMS arn
- Create a KMS Grant including encryption constraints
Amazon Key Management Service makes it easy for you to create and manage cryptographic keys and control their use across a wide range of AWS services and in your applications. AWS KMS is a secure and resilient service that uses hardware security modules that have been validated under FIPS 140-2, or are in the process of being validated, to protect your keys. AWS KMS is integrated with AWS CloudTrail to provide you with logs of all key usage to help meet your regulatory and compliance needs.
Terraform State Encryption with KMS
By enabling KMS encryption for Terraform state files, teams can ensure that even if state files are compromised, the encryption keys remain protected through AWS KMS key rotation policies.
To enable KMS encryption in Terraform Cloud or Enterprise, you can use the following configuration:
hcl
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "my-terraform-state-key"
region = "us-west-2"
encrypt = true
kms_key_id = "arn:aws:kms:us-west-2:123456789012:key/abcd1234-a123-4567-8abc-def123456789"
}
}
This configuration ensures that the Terraform state is encrypted using the specified KMS key, aligning with AWS best practices for securing configuration management data.
Integrating AWS Key Management Service with Terraform enables secure encryption of data at rest across AWS services such as Amazon S3, Amazon EBS, and others, while maintaining centralized control over cryptographic keys. This section provides practical examples of creating KMS keys with Terraform, configuring key policies, enabling key rotation, and auditing key usage.
Auditing and Compliance
AWS Config and CloudTrail play essential roles in continuous auditing and compliance monitoring. These configurations not only protect against unauthorized access but also align with modern DevOps and infrastructure-as-code principles, ensuring that security is baked into the infrastructure from the start.
Key usage is logged through CloudTrail, and key policies can be reviewed via Config rules to detect overly permissive principals or missing rotation settings.
Updating Existing Key Policies
While Terraform doesn't directly support updating an existing KMS key policy through its resources, there are a few approaches you can consider to achieve this.
Data source driven update pattern:
```hcl
data "awskmskey" "existingkey" {
keyid = "your-key-id-or-arn"
}
data "awskmskeypolicy" "existingpolicy" {
keyid = data.awskmskey.existingkey.id
}
locals {
updatedpolicy = jsonencode({
Version = "2012-10-17"
Statement = concat(
jsondecode(data.awskmskeypolicy.existing_policy.policy).Statement,
[
{
Sid = "NewStatement"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::123456789012:user/NewUser"
}
Action = ["kms:Encrypt", "kms:Decrypt"]
Resource = "*"
}
]
)
})
}
resource "awskmskeypolicy" "updatedpolicy" {
keyid = data.awskmskey.existingkey.id
policy = local.updated_policy
}
```
If you need more control or if the above method doesn't work for your use case, you can use the awskmskey resource with the policy argument, but you'll need to import the existing key first:
hcl
resource "aws_kms_key" "existing_key" {
description = "Existing KMS key"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
# Your existing policy statements
]
})
}
Importing an existing key into Terraform state is required before managing its policy as code, otherwise drift will occur on the first apply.
Available Terraform Resources
The AWS provider exposes a set of KMS resources for fine-grained control.
| Resource | Purpose |
|---|---|
| awskmsalias | Manages an Kms Alias resource |
| awskmsciphertext | Manages an Kms Ciphertext resource |
| awskmscustomkeystore | Manages an Kms Custom Key Store resource |
| awskmsexternal_key | Manages an Kms External Key resource |
| awskmsgrant | Manages an Kms Grant resource |
| awskmskey | Manages an Kms Key resource |
| awskmskey_policy | Manages an Kms Key Policy resource |
| awskmsreplicaexternalkey | Manages an Kms Replica External Key resource |
| awskmsreplica_key | Manages an Kms Replica Key resource |
There are 9 Terraform resources and 7 data sources available for KMS operations.
Key attributes commonly used together:
| Attribute | Typical Value |
|---|---|
| deletionwindowin_days | 7 |
| enablekeyrotation | true |
| multi_region | true for primary or replica |
| policy | jsonencode with Version 2012-10-17 |
Operational Practices
The guide shows how to set up KMS using Terraform.
A comprehensive guide to setting up AWS Key Management Service using Terraform Infrastructure as Code.
Managing AWS KMS with Terraform
Prerequisites include AWS CLI configured, Terraform installed, basic understanding of encryption concepts, and resources that need encryption.
Look at complete Terraform examples where you can get a better context of usage for various scenarios. The Terragrunt example can be viewed directly from GitHub.
- Replica KMS Keys
- The primary KMS key you initially created was created as a multi-region KMS key
- You can create a primary KMS key or a replica of a multi-region primary KMS key for use with the Mozilla SOPS tool
For production workloads, combine key rotation, least-privilege policies, alias naming conventions, and CloudTrail logging. Keep policies in version control and test changes in a non-production account before applying to keys that protect live data.
Conclusion
AWS KMS managed through Terraform provides deterministic key creation, policy enforcement, and auditability. The core pattern is defining awskmskey with rotation enabled and a carefully scoped policy, attaching an alias for stable referencing, and using multi-region primary and replica keys where low-latency cross-region encryption is required. State encryption via the S3 backend with a specific kmskeyid protects Terraform state, while CloudTrail and AWS Config provide continuous compliance evidence. Updating existing policies requires data source reads and explicit import steps to avoid destructive recreation. Together these practices embed key governance into infrastructure as code without sacrificing operational flexibility.