How to Scope an AWS KMS Key Policy to One IAM Role
An overly broad AWS KMS key policy - one that grants Decrypt to the account root - makes IAM least-privilege meaningless: any role in the account with kms:Decrypt in its policy can decrypt your data. Scoping the key policy to a specific role ARN is the second layer that actually enforces the boundary.
Why KMS key policies override IAM
AWS evaluates KMS access as an AND of two checks: the key policy must say
yes AND the IAM policy must say yes. But a key policy with
"Principal": {"AWS": "arn:aws:iam::123456789012:root"} effectively delegates
that yes/no decision entirely to IAM - any principal in the account that has
kms:Decrypt in its IAM policy gets through.
The result: one careless IAM grant elsewhere blows open access to every key that uses the broad root principal. The fix is a key policy that names the specific role ARN in the Decrypt statement.
Read the current policy
KEY=$(cat /workspace/.key-id)
aws kms get-key-policy \
--key-id "$KEY" \
--policy-name default \
--query Policy \
--output text | python3 -m json.tool
A too-broad policy looks like this - the Decrypt statement lists the account root, not a specific role:
{
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:root"},
"Action": "kms:*",
"Resource": "*"
}
]
}
Write the scoped policy
A correct two-statement policy keeps the required admin statement and adds a tightly scoped Decrypt/Encrypt grant for the consuming role only:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:root"},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "AllowDataPipelineDecrypt",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:role/data-pipeline"},
"Action": ["kms:Decrypt", "kms:Encrypt"],
"Resource": "*"
}
]
}
The root statement (Statement 1) is required - removing it permanently locks admins out of the key. It cannot be recovered without AWS Support.
Apply the policy
aws kms put-key-policy \
--key-id "$KEY" \
--policy-name default \
--policy file:///tmp/scoped.json
Verify with another get-key-policy call to confirm the root-only Decrypt
is gone and only the role ARN remains in the second statement.
Going further with conditions
Production policies add Condition blocks for a tighter scope:
kms:ViaService- restricts use to a specific AWS service (e.g."s3.us-east-1.amazonaws.com") so the key cannot be used directly via the CLI even by the named role.kms:EncryptionContext- requires a matching encryption context key/value (e.g.{"project": "payments"}), providing cryptographic binding between the data and its intended use.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Reading an existing KMS key policy with get-key-policy
- Writing a two-statement key policy that scopes Decrypt to a single role ARN
- Applying the scoped policy with put-key-policy and verifying the change
FAQ
What does granting kms:Decrypt to the account root actually mean?
It delegates the Decrypt decision to IAM - any principal in the account whose IAM policy includes kms:Decrypt can use the key. The key policy itself provides no additional restriction, making it equivalent to no key-level control.
Why must I keep the root allow-all statement in the KMS key policy?
Without a statement granting kms:* to the account root, no IAM principal - not even account admins - can manage the key. AWS cannot recover access to a key whose policy locks out all principals. Always keep the root admin statement.
How do I scope an AWS KMS key policy to one role?
Write a two-statement policy: Statement 1 keeps the required root kms:* admin grant; Statement 2 grants only kms:Decrypt (and kms:Encrypt if needed) with Principal set to the specific role ARN. Apply it with aws kms put-key-policy.
What is an AWS KMS key policy?
A KMS key policy is the resource-based policy attached to a KMS key that says which principals can use or manage it. It is the primary access control for the key - without an allow in the key policy, even an IAM admin cannot use it.
What is the difference between an IAM policy and a KMS key policy?
An IAM policy attaches to a user or role and grants permissions across services; a KMS key policy attaches to the key itself and is authoritative for that key. KMS access requires an allow in the key policy.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →