Quick Answer
{
"Sid": "Allow Terraform to use the key",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::123456789012:role/terraform" },
"Action": ["kms:CreateGrant", "kms:Decrypt", "kms:DescribeKey", "kms:GenerateDataKey*"],
"Resource": "*"
}
The Error
Error: creating EC2 Instance: AccessDeniedException:
User: arn:aws:iam::123456789012:role/terraform is not authorized to
perform: kms:CreateGrant on resource: arn:aws:kms:us-east-1:123456789012:key/mrk-abc123
Or:
Error: creating RDS Cluster: AccessDenied:
The cross-account KMS key access is not allowed
What Causes This
KMS access requires both an IAM policy AND a key policy to allow access. Missing either one blocks the operation.
- KMS key policy doesn’t allow the IAM role — the key needs explicit permission
- IAM role lacks kms: permissions — even with key policy, IAM must also allow
- Cross-account KMS — extra grants needed for keys in different accounts
- Service-linked role needs CreateGrant — EBS, RDS, and EFS use
kms:CreateGrantinternally
Solution 1: Update KMS Key Policy
resource "aws_kms_key" "main" {
description = "Encryption key for application"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Root account full access"
Effect = "Allow"
Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }
Action = "kms:*"
Resource = "*"
},
{
Sid = "Terraform role access"
Effect = "Allow"
Principal = { AWS = var.terraform_role_arn }
Action = [
"kms:CreateGrant",
"kms:Decrypt",
"kms:DescribeKey",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:ReEncrypt*"
]
Resource = "*"
}
]
})
}
Solution 2: Add IAM Permissions
resource "aws_iam_role_policy" "kms_access" {
name = "kms-access"
role = aws_iam_role.terraform.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"kms:CreateGrant",
"kms:Decrypt",
"kms:DescribeKey",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:ReEncrypt*",
"kms:ListGrants",
"kms:RevokeGrant"
]
Resource = [
aws_kms_key.main.arn,
# Or specific key ARN:
# "arn:aws:kms:us-east-1:123456789012:key/mrk-abc123"
]
}
]
})
}
Which Services Need Which KMS Permissions
| Service | Required KMS Actions |
|---|---|
| EBS volumes | CreateGrant, Decrypt, DescribeKey, GenerateDataKey* |
| RDS / Aurora | CreateGrant, Decrypt, DescribeKey, GenerateDataKey* |
| S3 SSE-KMS | Decrypt, GenerateDataKey*, DescribeKey |
| Secrets Manager | Decrypt, DescribeKey, GenerateDataKey* |
| EFS | CreateGrant, Decrypt, DescribeKey, GenerateDataKey* |
| Lambda env vars | Decrypt, DescribeKey |
Solution 3: Cross-Account KMS Access
# Account A (key owner) — key policy
{
Sid = "Allow Account B"
Effect = "Allow"
Principal = { AWS = "arn:aws:iam::222222222222:root" }
Action = [
"kms:CreateGrant",
"kms:Decrypt",
"kms:DescribeKey",
"kms:GenerateDataKey*"
]
Resource = "*"
}
# Account B (consumer) — IAM policy must ALSO allow
resource "aws_iam_role_policy" "cross_account_kms" {
policy = jsonencode({
Statement = [{
Effect = "Allow"
Action = ["kms:CreateGrant", "kms:Decrypt", "kms:DescribeKey", "kms:GenerateDataKey*"]
Resource = "arn:aws:kms:us-east-1:111111111111:key/mrk-abc123"
}]
})
}
Debugging
# Check who you're running as
aws sts get-caller-identity
# Simulate the KMS permission
aws kms describe-key --key-id arn:aws:kms:us-east-1:123456789012:key/mrk-abc123
# Check key policy
aws kms get-key-policy --key-id mrk-abc123 --policy-name default
# List grants
aws kms list-grants --key-id mrk-abc123
Hands-On Courses
- Terraform for Beginners on CopyPasteLearn
- Terraform By Example — practical code examples
Conclusion
KMS access requires both a KMS key policy AND IAM policy. Add kms:CreateGrant, kms:Decrypt, kms:GenerateDataKey*, and kms:DescribeKey to both. For cross-account access, both the key policy and the consuming account’s IAM policy must explicitly grant access.
