Managing AWS KMS with Terraform
A comprehensive guide to setting up AWS Key Management Service (KMS) using Terraform Infrastructure as Code
Managing AWS KMS with Terraform
AWS Key Management Service (KMS) is a managed service for creating and controlling encryption keys. This guide shows how to set up KMS using Terraform.
Prerequisites
- AWS CLI configured
- Terraform installed
- Basic understanding of encryption concepts
- Resources that need encryption
Project Structure
aws-kms-terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars
Basic KMS Configuration
# main.tf
provider "aws" {
region = var.aws_region
}
# KMS Key
resource "aws_kms_key" "main" {
description = "KMS key for ${var.project_name}"
deletion_window_in_days = 7
enable_key_rotation = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = "kms:*"
Resource = "*"
}
]
})
tags = {
Environment = var.environment
}
}
# KMS Alias
resource "aws_kms_alias" "main" {
name = "alias/${var.project_name}"
target_key_id = aws_kms_key.main.key_id
}
# Data source for current account
data "aws_caller_identity" "current" {}
Multi-Region Key Configuration
# Primary Region Key
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 Key
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 = aws_kms_key.primary.arn
tags = {
Environment = var.environment
}
}
Key Policy Configuration
# Key with detailed policy
resource "aws_kms_key" "restricted" {
description = "Restricted KMS key for ${var.project_name}"
deletion_window_in_days = 7
enable_key_rotation = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = "kms:*"
Resource = "*"
},
{
Sid = "Allow Service Access"
Effect = "Allow"
Principal = {
Service = [
"s3.amazonaws.com",
"rds.amazonaws.com"
]
}
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
Resource = "*"
},
{
Sid = "Allow Specific IAM Roles"
Effect = "Allow"
Principal = {
AWS = var.allowed_role_arns
}
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
Resource = "*"
}
]
})
tags = {
Environment = var.environment
}
}
Variables Configuration
# variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "us-west-2"
}
variable "project_name" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
variable "allowed_role_arns" {
description = "List of IAM role ARNs allowed to use the key"
type = list(string)
default = []
}
Best Practices
-
Key Management
- Use meaningful key descriptions
- Enable key rotation
- Set appropriate deletion windows
- Use key aliases
-
Security
- Implement least privilege access
- Use detailed key policies
- Monitor key usage
- Regular key rotation
-
Cost Optimization
- Monitor key usage
- Clean up unused keys
- Use appropriate key types
- Consider key sharing
-
Compliance
- Document key usage
- Regular access reviews
- Implement logging
- Monitor compliance
Cross-Account Access
# Key Policy for Cross-Account Access
resource "aws_kms_key" "cross_account" {
description = "Cross-account KMS key for ${var.project_name}"
deletion_window_in_days = 7
enable_key_rotation = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable Cross Account Access"
Effect = "Allow"
Principal = {
AWS = var.trusted_account_arns
}
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
Resource = "*"
}
]
})
}
Monitoring Configuration
# CloudWatch Alarm for Key Usage
resource "aws_cloudwatch_metric_alarm" "key_usage" {
alarm_name = "${var.project_name}-key-usage"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "NumberOfOperations"
namespace = "AWS/KMS"
period = "300"
statistic = "Sum"
threshold = "1000"
alarm_description = "This metric monitors KMS key usage"
alarm_actions = [var.sns_topic_arn]
dimensions = {
KeyId = aws_kms_key.main.id
}
}
Deployment Steps
- Initialize Terraform:
terraform init
- Plan the deployment:
terraform plan
- Apply the configuration:
terraform apply
Clean Up
Remove all resources when done:
terraform destroy
Common Use Cases
- S3 Bucket Encryption
resource "aws_kms_key" "s3" {
description = "KMS key for S3 encryption"
deletion_window_in_days = 7
enable_key_rotation = true
}
resource "aws_s3_bucket" "encrypted" {
bucket = "${var.project_name}-bucket"
}
resource "aws_s3_bucket_server_side_encryption_configuration" "encrypted" {
bucket = aws_s3_bucket.encrypted.id
rule {
apply_server_side_encryption_by_default {
kms_master_key_id = aws_kms_key.s3.arn
sse_algorithm = "aws:kms"
}
}
}
- RDS Database Encryption
resource "aws_kms_key" "rds" {
description = "KMS key for RDS encryption"
deletion_window_in_days = 7
enable_key_rotation = true
}
resource "aws_db_instance" "encrypted" {
identifier = "${var.project_name}-db"
engine = "postgres"
instance_class = "db.t3.micro"
allocated_storage = 20
kms_key_id = aws_kms_key.rds.arn
storage_encrypted = true
}
Grant Configuration
# Key Grant
resource "aws_kms_grant" "example" {
name = "${var.project_name}-grant"
key_id = aws_kms_key.main.id
grantee_principal = aws_iam_role.example.arn
operations = [
"Encrypt",
"Decrypt",
"GenerateDataKey"
]
constraints {
encryption_context_equals = {
Environment = var.environment
}
}
}
Conclusion
This setup provides a comprehensive foundation for deploying KMS using Terraform. Remember to:
- Plan your key management strategy carefully
- Implement proper access controls
- Monitor key usage and rotation
- Keep your configurations versioned
- Test thoroughly before production deployment
The complete code can be customized based on your specific requirements and use cases.