AWS KMS Key Policies vs Grants

Knowing these 7 differences could help you tighten your company’s security posture…and score higher on the “AWS Certified Security — Specialty” exam

Yann Stoneman
5 min readNov 10, 2019
Photo by Michael Dziedzic on Unsplash

Amazon Web Services (AWS) Key Management Service (KMS) is a huge part of security in AWS and on the “AWS Certified Security — Specialty” exam. How do you control access to your keys in KMS?

1. A key can have multiple grants, but only one key policy

Grants can be added and removed for a given key, whereas a key’s key policy can only be replaced. You can run CreateGrant (with an API call) to add specific permissions or RevokeGrant to remove those permissions again. If you use PutKeyPolicy, on the other hand, that replaces the entire key policy.

IAM Console help text for the `kms:PutKeyPolicy` action

2. You can lock yourself out with a mistaken key policy

The risk when replacing the key policy is that, if you’re not careful, you could remove all users’ access to a key. Then you’d need to contact AWS Support to recover the key.

If you keep the default KMS key policy, you won’t lock yourself out, because that policy gives complete permissions to the root user:

{
"Id": "key-consolepolicy-3",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<Your AWS Account ID>:root"
},
"Action": "kms:*",
"Resource": "*"
}
]
}

If the key policy is empty, the key becomes effectively useless. You can’t encrypt or decrypt with it anymore until you get AWS Support to help you out. If you haven’t issued any grants, on the other hand, you aren’t locked out, as long as you still have some permissions in the key policy.

3. Grants are better for programmatic permissions management

There are three API calls you can make with grants and only one for key policies. Just take a look at the Identity and Access Management (IAM) console, under KMS permissions management actions:

AWS console for IAM, permissions management options

With CreateGrant, you can get so granular as to set conditions (“constraints”) based on key metadata (“encryption context”) and also specify a specific AWS principal that can “retire” the grant. Whereas with key policies, only the principal that created the key policy can modify the key policy, because there’s only PutKeyPolicy.

Stackoverflow has a longer explanation of the differences between RetireGrant and RevokeGrant.

4. Grants can be given a friendly name, like “foo.” The key policy is just the “key policy.”

In this CLI example, the grant is getting the name “foo”:

aws kms create-grant \
--key-id d69a54b0-0250-467d-b7bd-f3a72f346c62 \
--grantee-principal arn:aws:iam::<Account ID>:user/yann_personal \
--operations Decrypt \
--name foo

5. Key policies allow you to specify the full range of KMS API actions. The range of actions you can specify in grants, however, is more limited.

If you try to run the following command:

aws kms create-grant \
--key-id d69a54b0-0250-467d-b7bd-f3a72f346c62 \
--grantee-principal yann_personal \
--operations "TagResource"

…you’ll get this error:

An error occurred (ValidationException) when calling the CreateGrant operation: 1 validation error detected: Value '[TagResource]' at 'operations' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [CreateGrant, GenerateDataKey, RetireGrant, Encrypt, ReEncryptTo, Decrypt, GenerateDataKeyWithoutPlaintext, DescribeKey, Verify, ReEncryptFrom, Sign]]

That’s because, when you create a grant, the API actions (or “operations”) you can assign must be one of these:

[CreateGrant, GenerateDataKey, RetireGrant, Encrypt, ReEncryptTo, Decrypt, GenerateDataKeyWithoutPlaintext, DescribeKey, Verify, ReEncryptFrom, Sign]

So if you run this instead:

aws kms create-grant \
--key-id d69a54b0-0250-467d-b7bd-f3a72f346c62 \
--grantee-principal yann_personal \
--operations "Encrypt"

…you will get a successful result:

{
"GrantToken": "AQpAM2RhZTk1MGMyNTk2ZmZmMzEyYWVhOWViN2I1MWM4Mzc0MWFiYjc0ZDE1ODkyNGFlNTIzODZhMzgyZjBlNGY3NiKAAgEBAgB4Pa6VDCWW__MSrqnre1HIN0Grt00ViSSuUjhqOC8OT3YAAADXMIHUBgkqhkiG9w0BBwaggcYwgcMCAQAwgb0GCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM8AyPXJIfFCBpmRghAgEQgIGP48IGvk5g2TEKrCjAzcvY6rDOkGSkCHHGP0XDOqFNiubyOOvLa0WPE-sEKHvAKDLzBJPMGxLcKy3xFUM2JKp4-GnCfPGBejOJTGggykmPsRtSw29RilZA7xcG-KUGiYXf38fIpxAZPJPz6A9LJbPrpQtyFQNUpSrqCSzRmQ3zXw_xrcGUKuKVPOneGPV-tDEqIM_Q42hYwk_ALMqGbq4vkrHMk9gkb-EpmQ0cKHJdkAcW",
"GrantId": "cfd0e36858c24fc02cca866eae2f92b1cc93d8246fe129990d1c28725d900716"
}

With a key policy, however, you can specify all KMS actions, including TagResource, in the policy. For example, if you include the following statement in the key policy…

{
"Sid": "Enable IAM User Permissions",
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::<Account ID>:root"
},
"Action": "kms:TagResource",
"Resource": "*"
}

…it successfully blocks the user’s ability to tag KMS keys, as you can see in this screenshot:

AWS KMS console screenshot — tagging permissions denied

6. The key policy is in the console and in the API/CLI (programmatic). Grants are only programmatically accessible.

As it says in the AWS docs, “to retrieve a list of grants attached to a [Customer Master Key (CMK)], use the AWS KMS ListGrants API (or list-grants AWS CLI command).” Notice that the console isn’t mentioned as an option.

The console, however, does let you view and edit the key policy:

The console includes the key policy, not grants.

When a feature doesn’t exist in the console, it’s a good clue that it’s a more advanced feature. As the docs say, “Grants are advanced [emphasis added] mechanisms for specifying permissions…”

7. You can use grants to allow access to other AWS principles, but not deny. With the key policy, you can do both.

You can use [grants] to allow access, but not deny it.
AWS Docs

And what differences have you noticed?

There are more differences, but these were enough to get me a general idea. I’d love to hear about any differences you noticed in your experience!

Follow Yann Stoneman

Last but not least, if you are not a Medium Member yet and plan to become one, I kindly ask you to do so using the following link. I will receive a portion of your membership fee at no additional cost to you.

--

--

Yann Stoneman

Staff Solutions Architect, giving technology language @ Cohere | Ex-AWS. Support blog by becoming member here: https://ystoneman.medium.com/membership