Lion Cipher Lab
Audit AWS KMS key policies for wildcard and cross-account access
- Cloud Security
- Intermediate
- ~50 min
- Free · no account required
Why it matters
Encryption is only as strong as the rule that decides who may use the key. In AWS, that rule is the KMS key policy: a short JSON document attached to every key. If it says the wrong thing, the encryption still runs, the data still looks protected on every dashboard, and a stranger's account can still call Decrypt. These mistakes are rarely dramatic. They are a Principal '*' someone added to unblock a deploy, a partner account ID left over from a migration, a role given kms:* because the exact action list was tedious, or kms:CreateGrant handed out without the condition that limits grants to…
What you'll learn
- reading an AWS KMS key policy statement by statement -- Effect, Principal, Action, Resource, Condition -- and knowing that Resource '*' in a key policy means 'this key', not 'everything'
- recognising the default 'Enable IAM User Permissions' statement for what it is: not a finding, but a delegation that makes IAM policies in the account part of who can use the key
- writing a Python standard-library linter that flags Principal '*' without an account or organization restriction, unapproved cross-account principals (full ARN, bare account ID, or hidden in a principal list), kms:* to non-admin roles, missing separation between key administrators and key users, kms:CreateGrant without kms:GrantIsForAWSResource, and account-wide grants missing kms:ViaService
- measuring a naive grep against a structured linter on the same 20 policies: grep for '*' flags 20 of 20 with 9 false positives; the obvious grep fix flags 8 with 3 false positives and misses 6; the linter flags 10 with 0 false positives and 1 miss
- seeing condition semantics bite: treating 'any condition' as a restriction misses 3 risky policies, and a StringNotEquals on kms:CallerAccount slips past a linter that checks the key but not the operator
- proving the corrected policies pass (0 of 11 flagged) while the naive grep still flags all 11, because the wildcard it hunts is the harmless one
- explaining why a clean key policy is not proof of least privilege (grants and IAM policies also confer access) and when to hand the job to IAM Access Analyzer instead of a hand-written linter
Steps in this lab
- What a KMS key policy is -- every term, defined once
- The default policy, and why the root statement is a note, not a finding
- The six things worth flagging, and why each is risky
- Generate 20 synthetic key policies
- Measure the naive audit: grep for the asterisk
- Build the structured linter
- Run the linter and read the findings
- Condition semantics: where linters (and people) go wrong
- Prove the fixed policies pass
- Optional appendix: lint the real keys in your own account
- The honest limits: a clean key policy is not least privilege
- What you built -- and the reflex to keep