Files
terraform-foundation/terraform/modules/kms-key/main.tf
Greg Hendrickson 6136cde9bb feat: Terraform Foundation - AWS Landing Zone
Enterprise-grade multi-tenant AWS cloud foundation.

Modules:
- GitHub OIDC for keyless CI/CD authentication
- IAM account settings and security baseline
- AWS Config Rules for compliance
- ABAC (Attribute-Based Access Control)
- SCPs (Service Control Policies)

Features:
- Multi-account architecture
- Cost optimization patterns
- Security best practices
- Comprehensive documentation

Tech: Terraform, AWS Organizations, IAM Identity Center
2026-02-02 02:57:23 +00:00

291 lines
7.3 KiB
HCL

################################################################################
# KMS Key Module
#
# Customer-managed KMS keys for encryption:
# - Automatic key rotation
# - Cross-account access
# - Service-specific grants
# - Alias management
# - Key policies
#
# Usage:
# module "kms" {
# source = "../modules/kms-key"
#
# name = "myapp-encryption"
# description = "Encryption key for myapp"
#
# service_principals = ["logs.amazonaws.com", "s3.amazonaws.com"]
# }
################################################################################
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
variable "name" {
type = string
description = "Key name (used for alias)"
}
variable "description" {
type = string
default = ""
description = "Key description"
}
variable "deletion_window_in_days" {
type = number
default = 30
description = "Waiting period before key deletion (7-30 days)"
validation {
condition = var.deletion_window_in_days >= 7 && var.deletion_window_in_days <= 30
error_message = "Must be between 7 and 30 days"
}
}
variable "enable_key_rotation" {
type = bool
default = true
description = "Enable automatic key rotation (annual)"
}
variable "multi_region" {
type = bool
default = false
description = "Create a multi-region key"
}
variable "key_usage" {
type = string
default = "ENCRYPT_DECRYPT"
description = "Key usage: ENCRYPT_DECRYPT or SIGN_VERIFY"
validation {
condition = contains(["ENCRYPT_DECRYPT", "SIGN_VERIFY", "GENERATE_VERIFY_MAC"], var.key_usage)
error_message = "Must be ENCRYPT_DECRYPT, SIGN_VERIFY, or GENERATE_VERIFY_MAC"
}
}
variable "key_spec" {
type = string
default = "SYMMETRIC_DEFAULT"
description = "Key spec (SYMMETRIC_DEFAULT, RSA_2048, ECC_NIST_P256, etc.)"
}
variable "admin_principals" {
type = list(string)
default = []
description = "IAM ARNs with full admin access to the key"
}
variable "user_principals" {
type = list(string)
default = []
description = "IAM ARNs with encrypt/decrypt access"
}
variable "service_principals" {
type = list(string)
default = []
description = "AWS service principals that can use the key (e.g., logs.amazonaws.com)"
}
variable "grant_accounts" {
type = list(string)
default = []
description = "Account IDs with cross-account access"
}
variable "tags" {
type = map(string)
default = {}
}
################################################################################
# Data Sources
################################################################################
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
################################################################################
# KMS Key
################################################################################
resource "aws_kms_key" "main" {
description = var.description != "" ? var.description : "KMS key for ${var.name}"
deletion_window_in_days = var.deletion_window_in_days
enable_key_rotation = var.key_spec == "SYMMETRIC_DEFAULT" ? var.enable_key_rotation : false
multi_region = var.multi_region
key_usage = var.key_usage
customer_master_key_spec = var.key_spec
policy = jsonencode({
Version = "2012-10-17"
Statement = concat(
# Root account access (required)
[{
Sid = "EnableRootPermissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = "kms:*"
Resource = "*"
}],
# Admin principals
length(var.admin_principals) > 0 ? [{
Sid = "KeyAdministrators"
Effect = "Allow"
Principal = {
AWS = var.admin_principals
}
Action = [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
]
Resource = "*"
}] : [],
# User principals
length(var.user_principals) > 0 ? [{
Sid = "KeyUsers"
Effect = "Allow"
Principal = {
AWS = var.user_principals
}
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
Resource = "*"
}] : [],
# Service principals
length(var.service_principals) > 0 ? [{
Sid = "AllowServices"
Effect = "Allow"
Principal = {
Service = var.service_principals
}
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
Resource = "*"
Condition = {
StringEquals = {
"aws:SourceAccount" = data.aws_caller_identity.current.account_id
}
}
}] : [],
# Cross-account access
length(var.grant_accounts) > 0 ? [{
Sid = "CrossAccountAccess"
Effect = "Allow"
Principal = {
AWS = [for acct in var.grant_accounts : "arn:aws:iam::${acct}:root"]
}
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
Resource = "*"
}] : [],
# Allow grants (needed for some AWS services)
[{
Sid = "AllowGrants"
Effect = "Allow"
Principal = {
AWS = concat(
["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"],
var.user_principals
)
}
Action = [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
]
Resource = "*"
Condition = {
Bool = {
"kms:GrantIsForAWSResource" = "true"
}
}
}]
)
})
tags = merge(var.tags, { Name = var.name })
}
################################################################################
# Alias
################################################################################
resource "aws_kms_alias" "main" {
name = "alias/${var.name}"
target_key_id = aws_kms_key.main.key_id
}
################################################################################
# Outputs
################################################################################
output "key_id" {
value = aws_kms_key.main.key_id
description = "KMS key ID"
}
output "key_arn" {
value = aws_kms_key.main.arn
description = "KMS key ARN"
}
output "alias_arn" {
value = aws_kms_alias.main.arn
description = "KMS alias ARN"
}
output "alias_name" {
value = aws_kms_alias.main.name
description = "KMS alias name"
}
output "key_policy" {
value = aws_kms_key.main.policy
description = "Key policy document"
}