1. Separate material, authorization, and path
A team receives AccessDenied during close for a fictional positions application. Before changing the key, identify caller, operation, Region, KeyId, and expected authorization source. A usable key can coexist with a grant that has not propagated or incorrect context. Record the immediately preceding change and whether the error occurs in the integrated service or a direct call. kms:ViaService can limit use to a supported service path acting on the principal’s behalf; running a CLI on an instance does not necessarily reproduce that path. A useful rehearsal preserves application conditions and changes one hypothesis at a time. Avoid adding broad permissions without understanding which condition rejected the request.
2. Create, retry, and end a grant
A newly created grant may not yet be visible throughout KMS. The grant token supports immediate use in compatible operations without replacing credentials or removing constraints. Retain the request-response relationship to avoid confusing token and GrantId. For equivalent CreateGrant retries, a stable Name prevents duplication when other parameters match. For service-principal grants, confirm SourceArn and retirement-authority requirements in the selected integration. At lifecycle end, revoking or retiring a grant does not delete the key or other grants. Removal also propagates: an incident ticket should distinguish the accepted command from the observed effect, with an owner to confirm containment.
3. Two sources of delegation authority
Evaluate CreateGrant as a capability to delegate access. When permission comes from policy, the creator can grant operations they do not directly hold; use conditions to bound delegation. When creation is authorized by another grant, the child grant is bounded by that source’s operations and constraints. In a review exercise, write the permission source beside each proposal: administrative policy, an integration grant, or a combination requiring investigation. If the only source permits Decrypt and requires Project=Ledger, do not approve a child with Encrypt and no context. The review should explain the boundary being retained. Finding the name CreateGrant somewhere in an account document is insufficient.
4. Context as a condition and as AAD
EncryptionContextEquals compares the exact set of pairs; EncryptionContextSubset requires the specified pairs and allows others. Both are case-sensitive. That authorization check does not replace the cryptographic requirement: to decrypt symmetric ciphertext created with context, supply the same context used during encryption. An additional Allow does not correct a changed value. Because context can appear in plaintext in logs, use non-sensitive identifiers and protect their relationship to personal data outside that field. In the model below, first compare Equals and Subset when Stage is added. Then observe that satisfying Subset does not make different context match the original AAD. The code teaches these two comparisons; it neither encrypts data nor simulates all KMS policies.
5. Regional recovery and key migration
Related multi-Region keys share cryptographic properties but remain regional resources. Key policies and grants need local management. The application also needs to select the correct endpoint and identifier on the recovery path. Replicating material does not demonstrate that the contingency role can read the dataset within the RTO. An existing single-Region key cannot be converted in place; plan the strategy and treatment of history. Similarly, changing an alias target directs future use without re-encrypting old ciphertext. Before retiring a key, inspect backups, archives, protected data keys, and infrequent consumers, including monthly processes that a daily check does not cover.
6. Acceptance criteria for security and production
Prepare a matrix containing identity, key, operation, context, Region, and expected outcome. Include an allowed path, incorrect context, an unauthorized identity, and a repeat after revocation. In local exercises use only the fictional data below; real AWS checks require their own environment and authorization. For the committee, present observed results, recovery time, gaps, and control impact on shared consumers. If replication is green but the application cannot decrypt, the recovery objective remains open. Partial acceptance can be a valid management decision when explicit, with risk, authority, timing, and ownership; it must not be rewritten as proven recovery. Handover also delivers contacts, a runbook, and a review procedure for grants that remain active.
# Local context comparison; not a KMS authorization engine or encryption.
# No credentials, network calls, or changes to keys.
def constraint_matches(mode, required, supplied):
if mode == "Equals":
return required == supplied
if mode == "Subset":
return all(k in supplied and supplied[k] == v for k, v in required.items)
raise ValueError("unknown constraint mode")
required = {"Project": "Ledger"}
expanded = {"Project": "Ledger", "Stage": "prod"}
assert not constraint_matches("Equals", required, expanded)
assert constraint_matches("Subset", required, expanded)
assert not constraint_matches("Subset", required, {"Project": "ledger"})
original_aad = dict(required)
assert expanded!= original_aad # Constraint success is not original AAD equality.
assert dict(reversed(list(expanded.items))) == expanded
print("equals=False subset=True aad_match=False")
The rehearsal finds replicated data but the contingency role cannot decrypt. Correct authorization and endpoint and repeat recovery before acceptance.
Common pitfalls
Token as credential; instantaneous propagation; CreateGrant always limited to own actions; alias as re-encryption; replica as recovered service.
Related topics: Keys, masking, and retention · Response, containment, and preservation
Confirm authorization, context, and regional path using observed results; document who maintains and ends each grant.
Reference: Grants in AWS KMS · SCS-C03