AWS IAM Fundamentals
Users, roles, policies and the trust between them
IAM is how AWS decides who can do what. Users, groups, roles, policies, and trust relationships — get these five wrong and everything from security to debugging gets worse.
What you will learn
- Distinguish IAM users, groups and roles
- Read and write an IAM policy document
- Chain trust policies, roles and STS to make cross-account access safe
IAM identities (users/roles) carry policies that grant or deny API actions against resources. Roles are assumed via trust policies and return temporary credentials through STS. Effective access is the intersection of every policy that applies.
What is this?
AWS IAM controls access to every API call. Users represent people, groups bundle users with common permissions, and roles are identities that anything (a person, an EC2 instance, another account) can assume. Policies are JSON documents describing Allow or Deny effects on actions and resources. A role's trust policy names who is allowed to assume it; STS issues short-lived credentials; organizations/federation extend access across accounts and identity providers.
Why do you need it?
- IAM is the blast-radius control — a misconfigured policy makes every other service insecure.
- Serverless and container workloads must act as something; roles give machines identity with credentials that expire.
- Multi-account strategy is built on cross-account roles, not shared keys.
- Auditors read IAM to prove least privilege and the policy review process.
Mental model
Building badge + room access list
IAM users and roles
Your badge (identity) who you are; the access control list per room (policies) what you may enter. A 'room service' badge (role) lets a service act without being a person.
How it works
- A principal (user or role) invokes an API; IAM evaluates all applicable policies and ultimately decides Allow or Deny.
- Policies attach to identities (identity-based) or to resources like S3 buckets (resource-based); both must allow.
- A Role has two documents: the trust policy (who may assume it) and the permissions policy (what they can do once assumed).
- sts:AssumeRole returns temporary credentials (expiring keys) subject to the trust + permission intersection.
- Federation (SAML/OIDC) maps external identities to roles automatically; IAM Identity Center manages this at scale.
How AWS decides whether an API call succeeds.
Examples
A minimal policy and role
// Policy allowing read on one bucket and key prefix{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::acme-data", "arn:aws:s3:::acme-data/reports/*"] }]} # Assume a role with the CLI (temporary, time-boxed)aws sts assume-role --role-arn arn:aws:iam::123456789012:role/DataRead --role-session-name ci-job --duration-seconds 3600Policies scope actions to specific resources; roles add a trust boundary; STS rotates credentials so nothing long-lived is stored in CI config.
In production
- EC2 instances get instance profiles: a role with least-privilege policies, no keys burned into the image.
- CI pipelines assume cross-account roles from an IAM Identity Center (OIDC) to deploy into dev/prod.
- A data team reads only their bucket prefixes via a scoped role; a deny-all-then-allow strategy keeps it tight.
Best practices
- Default deny: start with no permissions and add only what each workload needs.
- Prefer roles and temporary credentials over user keys and hardcoded secrets.
- Name policies and roles meaningfully (app:env:function) and version them as code.
- Review unused roles/policies with IAM Access Analyzer and CI-based policy checks.
Common mistakes
- Giving users AdministratorAccess because debugging permissions is annoying.
- Hardcoding access keys in Lambda env vars or repo config files.
- Putting a full trust policy (everyone) on a role and calling it cross-account.
- Forgetting explicit Deny always wins — a stray deny SCP/policy blocks everything.
Common issues
AccessDenied for an action your IAM policy allowsResource policy, SCP or explicit Deny elsewhere blocks it
Inspect bucket/role trust policies and the OU chain; use Policy Simulator to see effective permissions.
EC2 can't do s3:GetObjectInstance has no IAM role attached (or wrong role)
Attach the intended instance profile; verify with aws sts get-caller-identity on the box.
CI role assumption fails because of MFATrust policy requires MultifactAuthPresent but CI has no MFA
Scope MFA requirement to human users, or add a separate trust path for automated principals.
Debugging tips
- When an access call fails, read the error — AccessDenied often names the lacking action.
- Use IAM policy simulator and CloudTrail (SourceIP, AccessKeyId) to locate the effective deny.
- Check for SCPs and resource policies: IAM may allow while an SCP or bucket policy denies.
- Compare the identity's attached policies to what the resource actually requires.
Interview checkpoint
Hands-on lab
- Create an IAM role with a scoped policy
- Assume the role with STS and confirm limited permissions
- Prove an action outside the policy is denied
Build a Least-Privilege Role and Prove It
30 min · intermediate
Quick quiz
Which component decides WHO can assume a role?
IAM roles issue permanent access keys stored in the account.