DevTools Logo
All posts

Writing IAM Policies by Hand (Without Shooting Yourself in the Foot)

August 10, 2026 · DevTools

aws
iam
security
cloud
developer-tools

An IAM policy is a small JSON document, but it carries a lot of power, so it pays to understand its anatomy. Every policy starts with "Version": "2012-10-17" — the modern policy language version — followed by a Statement array. Each statement has an Effect of Allow or Deny, an Action list (what the caller can do, namespaced like s3:GetObject), and a Resource list (which ARNs it applies to).

The cardinal rule is least privilege. Instead of granting s3:* on *, grant s3:GetObject on arn:aws:s3:::my-bucket/*. Scope actions to one service per statement so the intent reads cleanly, and prefer explicit resource ARNs over wildcards — a wildcard resource widens the blast radius if the policy is ever attached more broadly than you intended.

A few details trip people up. A single action or resource can be written as a string, but multiples must be an array. Deny always wins over Allow, which makes explicit deny statements a strong tool for exceptions. And an optional Sid names a statement so a long policy stays readable. Build the policy field by field, validate that every statement says exactly what you mean, and paste it into the console, Terraform, or CloudFormation.