Skip to main content
Every KMS endpoint checks one IAM action before it does anything. This is the whole list — there are no others, and no endpoint skips the check.
The API reference shows the action on each endpoint’s own page, so you do not have to come back here to look one up. Both come from the same place: the authorization call in the service, read at build time.

The actions

Every operation on a specific key is authorized against that key’s CRN, with the key’s tags available as condition context. Only the two collection-level operations are not.

Sealing and opening are different grants

kms:Decrypt and kms:GenerateDataKey are separate actions from kms:GetKey precisely so the operations that return usable key material can be granted narrowly. A component that only needs to seal data should hold kms:Encrypt and kms:GenerateDataKey and nothing else — it can then write, and never read back. The same split appears on certificates, where certificate:GetCertificateMaterial is separate from reading a certificate.
kms:GenerateDataKey returns the new data key in plaintext as well as wrapped, because the caller has to use it before throwing it away. Treat it as equivalent to kms:Decrypt in blast radius when you decide who holds it, even though the two guard different directions.

Listing cannot be narrowed

kms:ListKeys is authorized against the collection, not against individual keys, so restricting it by CRN or tag has no effect. Scope the operations that use a key; listing tells a caller that a key exists and nothing more.

Resources

KMS actions are checked against one resource shape:
The region slot is populated, unlike DNS or certificates. A key exists in one region and can only be used from there, so a policy written for one region does not reach another region’s keys even when the names match.

Conditions

Create carries the tags from the request; every key-scoped action carries the tags already on the key. So a policy can fence both what a caller may label a key as, and which existing keys it may touch:
  • basalt:RequestTag/<key> — at kms:CreateKey.
  • basalt:ResourceTag/<key> — on every action scoped to a key CRN.

Writing a policy

A write path that can seal but never open:
Fencing a fleet by label rather than by name:
kms:* includes decryption and deletion. A wildcard grants kms:Decrypt, kms:GenerateDataKey and kms:ScheduleKeyDeletion along with everything else. List the actions when the credential belongs to a workload; a service that seals data has no reason to be able to schedule the key’s destruction.
See writing policies for the full document format and every condition operator.

What a denial looks like

A failed check answers 403:
It does not tell you which action was missing, deliberately — the message is the same for every denial, so it cannot be used to map out what a credential can and cannot reach. Look up the call you made in the table above, and the action it needs is the one to add.
A 404 is not a disguised 403. Ownership is resolved before authorization: a key belonging to another account answers KMS_KEY_NOT_FOUND because it is not yours to see, and one you own but lack the action for answers 403. If you are getting 404 on a key you believe you own, check the region and the account the credential belongs to before checking the policy.