Authorization bypass due to undefined KMS key policy in Terraform

High Risk infrastructure-security
awskmskey-policyauthorization-bypassencryption-securitykey-managementleast-privilege

What it is

AWS KMS keys created without explicit key policies rely on default IAM-based access controls that may grant overly broad permissions through existing IAM policies. This creates a security risk where unintended principals could gain access to encryption keys, enabling unauthorized data decryption, key management operations, privilege escalation, and potential data exposure across encrypted resources.

# VULNERABLE: KMS key without explicit policy
resource "aws_kms_key" "vulnerable_key" {
  description             = "Vulnerable KMS key"
  deletion_window_in_days = 10
  enable_key_rotation     = true
  
  # VULNERABLE: No policy defined - relies on IAM
  # Any IAM user/role with kms:* permissions can access
}

resource "aws_kms_alias" "vulnerable_alias" {
  name          = "alias/vulnerable-key"
  target_key_id = aws_kms_key.vulnerable_key.key_id
}

# VULNERABLE: Encryption using undefined policy key
resource "aws_s3_bucket_server_side_encryption_configuration" "vulnerable" {
  bucket = aws_s3_bucket.data.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.vulnerable_key.arn
    }
  }
}
# SECURE: KMS key with explicit policy
resource "aws_kms_key" "secure_key" {
  description             = "Secure KMS key with explicit policy"
  deletion_window_in_days = 10
  enable_key_rotation     = true
  
  # SECURE: Explicit key policy
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "Enable IAM Permissions"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::123456789012:root"
        }
        Action   = "kms:*"
        Resource = "*"
      },
      {
        Sid    = "Allow key administrators"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::123456789012:role/admin-role"
        }
        Action = [
          "kms:Create*",
          "kms:Describe*",
          "kms:ScheduleKeyDeletion"
        ]
        Resource = "*"
      },
      {
        Sid    = "Allow key usage"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::123456789012:role/app-role"
        }
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:GenerateDataKey*"
        ]
        Resource = "*"
      }
    ]
  })
}

resource "aws_kms_alias" "secure_alias" {
  name          = "alias/secure-key"
  target_key_id = aws_kms_key.secure_key.key_id
}

💡 Why This Fix Works

The vulnerable configuration creates a KMS key without an explicit policy, causing it to rely on default IAM-based access controls which may grant overly broad permissions. The secure version defines an explicit key policy with least-privilege access, separating key administrators from key users and specifying exactly which principals can perform which operations on the key.

Why it happens

AWS KMS keys created in Terraform without the policy parameter explicitly defined. Without key policies, KMS falls back to IAM-based permissions which may grant broader access than intended through existing IAM policies.

Root causes

Missing Explicit Key Policies

AWS KMS keys created in Terraform without the policy parameter explicitly defined. Without key policies, KMS falls back to IAM-based permissions which may grant broader access than intended through existing IAM policies.

Default IAM-Based Access Control

Organizations rely on IAM policies alone for KMS key access control instead of implementing explicit key policies. This approach can grant unintended access when IAM policies contain kms:* or overly broad permissions.

Incomplete Terraform Configuration

The aws_kms_key resource in Terraform lacks a policy attribute. Without explicit policy definition, the key's access control is determined entirely by IAM, missing the defense-in-depth benefits of key policies.

Overly Permissive IAM Policies

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

Inadequate Least-Privilege Implementation

Access controls for encryption keys don't follow least-privilege principles with separate key administrators and key users. Without explicit policies, there's no clear separation of duties for key management versus key usage operations.

Fixes

1

Define Explicit Key Policies

Add the policy parameter to all aws_kms_key resources with explicit JSON policy documents. Key policies should define exactly which principals can perform key management and cryptographic operations, providing defense-in-depth beyond IAM policies.

2

Implement Least-Privilege Principal Access

Configure key policies with specific principal ARNs (roles, users, services) rather than allowing account root or using wildcards. Grant only the minimum necessary permissions to each principal based on their actual requirements.

3

Control Management and Usage Separately

Use key policies to differentiate between key management actions (kms:Create*, kms:Delete*, kms:ScheduleKeyDeletion) and key usage actions (kms:Encrypt, kms:Decrypt, kms:GenerateDataKey). Apply appropriate permissions to different principal sets.

4

Separate Administrators from Users

Create distinct policy statements for key administrators who manage the key lifecycle and key users who perform encryption/decryption. This separation of duties prevents privilege escalation and limits blast radius of compromised credentials.

5

Enable Rotation and Monitoring

Set enable_key_rotation = true for automatic annual key rotation. Enable CloudTrail logging and CloudWatch metrics to monitor key usage patterns, detecting anomalous access that may indicate compromise or policy misconfigurations.

Detect This Vulnerability in Your Code

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