An IAM policy looks intimidating until you know what each field does. Here is the whole vocabulary.
Top level
- Version — the policy language version. Always
"2012-10-17". This is not a date you edit. - Statement — an array of one or more permission statements. Order does not matter.
Inside a statement
- Sid (optional) — a statement id, purely for humans and tooling.
- Effect —
"Allow"or"Deny". Deny always wins. - Action — one or more API operations, like
s3:GetObjectorlogs:*. Wildcards are allowed. - Resource — the ARNs the actions apply to.
"*"means every resource. - Principal — (resource-based policies only) who the statement applies to.
- Condition (optional) — key/value tests that must be true, e.g. require HTTPS.
A worked example
{
"Sid": "ReadOneBucket",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::my-app-data",
"arn:aws:s3:::my-app-data/*"
]
}
Note the two ARNs: ListBucket acts on the bucket itself, while GetObject acts on objects (the /*). Forgetting one of these is the single most common IAM bug.
Conditions in one line
"Condition": { "Bool": { "aws:SecureTransport": "true" } }
This restricts the statement to HTTPS requests only.
Open a real policy in the workspace and ask "explain each statement" — the AI narrates every field against the values actually present.