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

  1. Key Management

    • Use meaningful key descriptions
    • Enable key rotation
    • Set appropriate deletion windows
    • Use key aliases
  2. Security

    • Implement least privilege access
    • Use detailed key policies
    • Monitor key usage
    • Regular key rotation
  3. Cost Optimization

    • Monitor key usage
    • Clean up unused keys
    • Use appropriate key types
    • Consider key sharing
  4. 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

  1. Initialize Terraform:
terraform init
  1. Plan the deployment:
terraform plan
  1. Apply the configuration:
terraform apply

Clean Up

Remove all resources when done:

terraform destroy

Common Use Cases

  1. 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"
    }
  }
}
  1. 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.