Undefined KMS Key Policy in Terraform

High Risk infrastructure-security
awsterraformkmsencryptionkey-managementaccess-control

What it is

AWS KMS keys created without explicit key policies rely on IAM-based access controls that may grant unintended broad access. Without explicit policies, any principal with appropriate IAM permissions can use the key for encryption, decryption, and management operations, potentially allowing unauthorized data access and privilege escalation.

# VULNERABLE: KMS keys without explicit policies

# VULNERABLE: Database encryption key without policy
resource "aws_kms_key" "database_key" {
  description             = "Database encryption key"
  deletion_window_in_days = 7
  enable_key_rotation     = true
  
  # VULNERABLE: No explicit key policy
  # Relies on IAM-based access controls
  # Any principal with kms:* can access this key
  
  tags = {
    Environment = "production"
    Purpose     = "database"
  }
}

# VULNERABLE: S3 encryption key without restrictions
resource "aws_kms_key" "s3_key" {
  description = "S3 bucket encryption key"
  
  # VULNERABLE: No policy restrictions
  # Any service or principal with IAM permissions can use
}

# VULNERABLE: IAM policy that exploits undefined key policies
resource "aws_iam_role_policy" "overprivileged_access" {
  name = "kms-access"
  role = aws_iam_role.application_role.id
  
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "kms:*"  # VULNERABLE: Wildcard permissions
        ]
        Resource = "*"  # VULNERABLE: All KMS keys accessible
        # Without key policies, can access ALL keys including:
        # - Database encryption keys
        # - S3 bucket encryption keys
        # - Other applications' secrets keys
      }
    ]
  })
}
# SECURE: KMS key with explicit policy

resource "aws_kms_key" "database_key_secure" {
  description             = "Database encryption key with explicit access controls"
  deletion_window_in_days = 30
  enable_key_rotation     = true
  
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid      = "EnableRootKeyManagement"
        Effect   = "Allow"
        Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }
        Action   = "kms:*"
        Resource = "*"
      },
      {
        Sid      = "AllowDatabaseServiceAccess"
        Effect   = "Allow"
        Principal = { Service = "rds.amazonaws.com" }
        Action   = ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey", "kms:DescribeKey"]
        Resource = "*"
        Condition = {
          StringEquals = { "kms:ViaService" = "rds.${data.aws_region.current.name}.amazonaws.com" }
        }
      },
      {
        Sid      = "DenyUnauthorizedAccess"
        Effect   = "Deny"
        Principal = "*"
        Action   = ["kms:Decrypt", "kms:Encrypt"]
        Resource = "*"
        Condition = {
          StringNotEquals = { "aws:PrincipalServiceName" = "rds.amazonaws.com" }
        }
      }
    ]
  })
  
  tags = {
    Environment = "production"
    Purpose     = "database-encryption"
    DataClass   = "sensitive"
  }
}

data "aws_caller_identity" "current" {}
data "aws_region" "current" {}

💡 Why This Fix Works

The vulnerable configuration creates KMS keys without explicit policies, relying on IAM permissions that can grant overly broad access. The secure version implements explicit resource-based key policies with least-privilege access, service restrictions via kms:ViaService conditions, and deny statements to prevent unauthorized access.

Why it happens

AWS KMS keys created in Terraform without the policy parameter explicitly defined. Without this argument, keys use default AWS-managed policies that defer to IAM, potentially granting broader access than intended.

Root causes

Missing Policy Argument in Key Creation

AWS KMS keys created in Terraform without the policy parameter explicitly defined. Without this argument, keys use default AWS-managed policies that defer to IAM, potentially granting broader access than intended.

IAM-Only Access Control

Organizations rely solely on IAM policies for KMS key access control instead of implementing explicit key-based policies. This single-layer approach misses the defense-in-depth benefits of resource-based key policies.

Wildcard IAM Permissions Without Key Restrictions

IAM policies grant kms:* or broad kms:Decrypt/kms:Encrypt permissions without resource-level restrictions. When keys lack explicit policies, these overly permissive IAM policies become the sole access control.

Missing Principal and Service Restrictions

Key configurations don't specify which AWS principals (users, roles, services) or accounts should have access. Without explicit restrictions, any entity with IAM permissions can use the key.

Unconstrained Cross-Account Access

Keys allow cross-account access through IAM policies alone without explicit key policy controls. This enables unintended access from external accounts that have been granted IAM permissions.

Fixes

1

Define Explicit Least-Privilege Policies

Add the policy parameter to all aws_kms_key resources with explicit JSON policy documents implementing least-privilege access. Define exactly which principals can perform key management versus cryptographic operations.

2

Restrict to Specific Principals

Configure key policies with specific AWS account IDs, role ARNs, user ARNs, and service principals rather than allowing account root or using wildcards. Grant access only to identities that legitimately need the key.

3

Apply ViaService Conditions

Use kms:ViaService condition keys in key policies to restrict usage to specific AWS services (e.g., kms:ViaService: rds.us-east-1.amazonaws.com). This prevents direct key access outside of intended service contexts.

4

Implement Explicit Deny Statements

Add deny statements to key policies that explicitly prevent unauthorized access patterns, such as denying all principals except specific services or preventing usage outside designated AWS regions.

5

Require Encryption Context

Add encryption context requirements (kms:EncryptionContext condition) to key policies for additional security. Encryption context provides additional authenticated data that must match for decryption operations to succeed.

6

Use Dedicated Keys Per Purpose

Create separate KMS keys for different use cases (database encryption, S3, secrets management) rather than sharing keys. Separate keys with specific policies limit blast radius and simplify access control management.

Detect This Vulnerability in Your Code

Sourcery automatically identifies undefined kms key policy in terraform and many other security issues in your codebase.