Key types, key policies, and grants
Lesson 2 of 5 in KMS, Keys, and Certificates.
A KMS key is not one thing. Three ownership models exist, they differ in exactly the dimensions the exam probes — who holds the policy, who rotates it, whether you can audit its use, what it costs — and a question that says “the auditor must see every use of the key” or “the key must be usable from another account” has already eliminated two of the three.
AWS owned keys live in AWS-owned accounts and are shared across many customers. You never see them, you cannot audit them in your own CloudTrail, and they cost nothing. AWS managed keys exist in your account with the alias form aws/s3, aws/ebs, aws/secretsmanager: one per service per Region, created the first time you encrypt with that service’s default. You can see them and see their use in CloudTrail, but you cannot edit their key policy and you cannot choose their rotation — AWS rotates the key material every year. They are free to keep; you pay only per request. Customer managed keys are the ones you create: your key policy, your rotation decision, your aliases and tags, your deletion — and a monthly charge per key plus requests. Every “we must control the key” requirement in Domain 5 lands on a customer managed key.
Then there is the shape of the key itself. Symmetric keys (AES-256, never leaving KMS) cover almost everything: envelope encryption, S3, EBS, RDS, Secrets Manager. Asymmetric keys hold an RSA or elliptic-curve pair, and the public key can be downloaded and used outside AWS — which is the only reason to choose one: encryption by a party who must not have AWS credentials, or signature verification outside AWS. Asymmetric operations are slower and priced higher per request, and they cannot be used by the AWS services that expect symmetric keys.
| Key type | Who writes the policy | Rotation | Visible in your CloudTrail | Cross-account use | Cost |
|---|---|---|---|---|---|
AWS owned | AWS — invisible to you | AWS, on its own schedule | No — the key lives in an AWS-owned account | No | None |
AWS managed ( | AWS — policy not editable | Automatic, every year, not configurable | Yes — key use appears in your trail | No — cannot be shared with another account | No monthly key charge; per-request charges apply |
You — the key policy is mandatory | Yours: optional automatic (annual by default, configurable period) plus on-demand | Yes | Yes — via key policy plus grants | Monthly charge per key, plus requests |
Now authorization, which is the single most tested idea in this module.
Every KMS key carries a key policy, and it is not optional — a key cannot exist without one. The key policy is the root of authority for that key: it is a resource-based policy, and unlike most AWS resource policies it does not merely add to IAM, it gates IAM. An IAM policy granting kms:Decrypt on a key does nothing at all unless that key’s policy delegates authority to IAM. The delegation is the statement every console-created key gets by default — Principal: {"AWS": "arn:aws:iam::111122223333:root"} with Action: "kms:*" — which means “principals in this account may be authorized for this key by their IAM policies.” Remove it and the key becomes governable only by statements written directly in the key policy, which is a deliberate pattern for high-value keys.
That inversion produces the classic troubleshooting scenario: an administrator with AdministratorAccess cannot use a key, and nothing is wrong. The key’s policy was written without the IAM-delegation statement, so only the principals it names explicitly can touch it. The reverse scenario is just as common: the key policy delegates to the account root, so the key appears “open”, and the real control lives in the IAM policies — meaning a review of the key policy alone tells you nothing about who can decrypt.
Delegating to IAM
The statement that makes IAM policies effective for this key. Without it, no IAM policy in the account can authorize key use.
{
"Sid": "EnableIAMUserPermissions",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": "kms:*",
"Resource": "*"
}
Resource: "*" inside a key policy means this key — the policy is already attached to it. The root principal here is the account, not the root user: it means “this account’s IAM may authorize access”, which is why removing it locks out even administrators.
Restricting a key to one service
kms:ViaService allows key use only when the request arrives through a named AWS service on the principal’s behalf — so a leaked role credential cannot call Decrypt directly, only S3 can, acting for that role.
{
"Sid": "AllowOnlyThroughS3AndEBS",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/AppRole" },
"Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey*", "kms:DescribeKey"],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": ["s3.eu-west-1.amazonaws.com", "ec2.eu-west-1.amazonaws.com"]
}
}
}
Cross-account decryption
Cross-account key use always takes two grants of authority: the key policy in the key’s account must allow the external principal, and that principal’s IAM policy in its own account must allow the KMS action. Either one missing is an AccessDenied.
{
"Sid": "AllowPartnerAccountToDecrypt",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::444455556666:root" },
"Action": ["kms:Decrypt", "kms:DescribeKey"],
"Resource": "*",
"Condition": {
"StringEquals": { "kms:EncryptionContext:project": "shared-reports" }
}
}
This is the pattern behind every “share an encrypted snapshot / encrypted S3 object with another account” question.
Pinning to an organization
For keys shared widely inside an organization, condition on the org id rather than enumerating accounts — the same global condition key used across resource policies.
{
"Sid": "AllowOrgDecrypt",
"Effect": "Allow",
"Principal": "*",
"Action": ["kms:Decrypt", "kms:DescribeKey"],
"Resource": "*",
"Condition": {
"StringEquals": { "aws:PrincipalOrgID": "o-exampleorgid" }
}
}
Principal: "*" with an org condition is not “public” — the condition is the boundary. Reviewers who read only the principal line misjudge this policy constantly.
Grants are the third authorization mechanism, and they exist because policies are the wrong tool for temporary, programmatic delegation. A grant is created by an API call, names a grantee principal, a specific list of allowed operations, and optionally an encryption context constraint; it takes effect within seconds and is removed by RetireGrant or RevokeGrant rather than by a policy edit. Nothing in the key policy changes. That is the point: a long-running job, a Lambda, or an AWS service that needs to decrypt on your behalf for a while gets exactly the operations it needs, for as long as it needs, without a human editing a policy document under time pressure.
AWS services create grants on your behalf constantly — this is why an encrypted EBS volume, an Aurora cluster, or a Secrets Manager secret keeps working after the creating principal’s session ends. The condition key kms:GrantIsForAWSResource exists for exactly that traffic: you can allow kms:CreateGrant only when the grant is being created by an AWS service integrated with KMS, which lets you permit the service-created grants your workloads need while refusing arbitrary grant creation by a principal that may be compromised. Grants are additive and auditable: ListGrants enumerates them, and every creation and use appears in CloudTrail. The exam tell for a grant is any of “temporary”, “programmatic”, “for the duration of the job”, or “without modifying the key policy”.
Rotation is the last piece and the most mis-stated. For a customer managed symmetric key with AWS-generated material, you may enable automatic rotation — annual by default, with a configurable period — and you may also trigger on-demand rotation at any time. Rotation generates new key material and makes it current for new encryption, while KMS retains all previous material so existing ciphertexts stay readable: the key id, ARN, aliases and policies never change, and no ciphertext needs re-encrypting. Nothing in your application changes at all, which is both the convenience and the thing people misunderstand — rotation does not make old data unreadable, and it is not a revocation mechanism.
The exceptions matter. AWS managed keys rotate every year and you cannot change that. AWS owned key rotation belongs to the owning service. Automatic rotation is not available for asymmetric keys, HMAC keys, keys in a custom key store, or keys with imported material — those are rotated manually or, for imported material, on demand after you import the replacement. If a requirement says “the key material must change every 90 days”, the answer is a configurable rotation period on a customer managed key; if it says “we must supply the material ourselves and still rotate it”, you are in the next lesson.
Key terms: KMS key policy, KMS grant, kms:ViaService, AWS managed key, AWS owned key, KMS key rotation, Scheduled key deletion
Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.