IAM: users, groups & policies
Every single AWS request is checked by IAM (Identity and Access Management) before anything happens: who is asking, and does a policy say they may do this, to this thing? Get IAM right and a leaked key or a clumsy command can only do a little damage. Get it wrong and one mistake can delete everything.
You will learn
- Users, groups, roles and policies, and how they fit together
- Reading a policy:
Effect,Action,Resource - How AWS decides: default deny, allow, and explicit deny wins
- Access keys, named profiles and
--profile - Least privilege: writing your own policy and testing it
The four building blocks
| Thing | What it is | Linux cousin |
|---|---|---|
| User | A person (or a program) with long-lived credentials: a console password and/or access keys | an account in /etc/passwd |
| Group | A bag of users. Attach policies to the group, and every member gets them | wheel / sudo |
| Role | An identity with no password or keys. Someone or something "puts it on" and gets temporary credentials. EC2 servers, Lambda functions and people from other accounts use roles | a bit like sudo -u |
| Policy | A JSON document listing what is allowed or denied. Attached to a user, group or role | /etc/sudoers rules |
Reading a policy
{
"Version": "2012-10-17", # always this date: it's the policy language version
"Statement": [
{
"Effect": "Allow", # or "Deny"
"Action": ["s3:GetObject", "s3:PutObject"], # service:Operation, wildcards allowed: "s3:*"
"Resource": "arn:aws:s3:::cht-notes-123456789012/*" # which things (ARNs)
}
]
}
AWS evaluates every request the same way:
- Start at deny. Nothing is allowed unless something says so (the "implicit deny").
- If any attached policy has a matching Allow, it's allowed…
- …unless any policy has a matching Deny. An explicit deny always wins.
AWS ships hundreds of ready-made AWS managed policies (ReadOnlyAccess, AmazonS3ReadOnlyAccess, AdministratorAccess…). They're handy, but broad. For real work you write customer managed policies that allow exactly what's needed. That's least privilege.
Users, groups and keys from the CLI
aws iam create-group --group-name readers
aws iam attach-group-policy --group-name readers \
--policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
aws iam create-user --user-name alex
aws iam add-user-to-group --user-name alex --group-name readers
aws iam create-access-key --user-name alex # the secret is shown ONCE: save it now
Put permissions on groups, not on each user. When Alex changes jobs, you move Alex to another group instead of hunting through a pile of policies.
Profiles: more than one identity on one computer
aws configure wrote a [default] profile. Add others with --profile:
aws configure --profile alex # the same four questions aws configure set region us-east-1 --profile alex # or set one value at a time aws s3 ls --profile alex # this one command as alex export AWS_PROFILE=alex # the whole shell as alex unset AWS_PROFILE # back to default
[default] aws_access_key_id = AKIAIOSFODNN7EXAMPLE aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY [alex] aws_access_key_id = AKIAI22QSPKMUTFG3PVC aws_secret_access_key = PsOzGjF25qJawoXRdf4XwGo2JAaCg09mfDA8NzOr
Profiles are how you test permissions honestly: run the command as the user you're giving access to, not as your all-powerful admin.
Roles: no keys on servers
A web server that reads from S3 needs permissions. Never copy access keys onto it. Give the server a role instead (through an instance profile). The server picks up short-lived credentials automatically, and AWS rotates them for you. A role has a trust policy saying who may use it:
{ "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" }
aws iam create-role --role-name web-server --assume-role-policy-document file://policies/ec2-trust.json aws iam attach-role-policy --role-name web-server --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess aws iam create-instance-profile --instance-profile-name web-server aws iam add-role-to-instance-profile --instance-profile-name web-server --role-name web-server
Then launch servers with --iam-instance-profile Name=web-server. People can use roles too: AWS IAM Identity Center signs you in through your browser with temporary credentials, which is what most companies use instead of access keys.
Give each person their own user (never share one), turn on MFA, prefer roles and temporary credentials over access keys, and delete keys nobody uses: aws iam list-access-keys, aws iam delete-access-key. A user can have at most two keys, so you can make a new one, switch to it, then delete the old one.
Practice: a read-only helper, then a custom policy 🔐
You're signed in as sandbox-admin. There's a bucket called cht-notes-123456789012 with some notes in it. Create a user who can read things but not change them, prove it, then grant exactly one extra permission.
Quick check
1. A user's group allows s3:*, but another attached policy has "Effect": "Deny", "Action": "s3:DeleteObject". Can the user delete objects?
✓ Default deny → an Allow opens it → any explicit Deny closes it again.
2. A web server needs to read files from S3. What's the right way to give it permission?
✓ Roles give short-lived credentials that rotate on their own, and there's nothing on disk to steal.
3. What is "least privilege"?
✓ Start small and add permissions when a real need shows up.