IAM Fundamentals
How AWS controls who can do what to which resources — users, groups, roles, and the policies that grant or deny permissions.
Want a visual for this topic?
Generate a diagram tailored to IAM Fundamentals — the AI picks whichever visual (architecture, flowchart, ER diagram, etc.) best fits this specific AWS concept.
Sign in to generate a visual →🎓 Learning objectives
- •Explain the difference between an IAM user, group, role, and policy
- •Explain why you should never use the root account for daily work
- •Read and write a simple IAM policy JSON document
- •Explain when to use an IAM Role instead of long-lived access keys
What is it?
IAM (Identity and Access Management) is AWS's global service for controlling who (a person, an application, another AWS service) can do what (read, write, delete) to which resources (a specific S3 bucket, a specific EC2 instance) in your account. Every single API call made to AWS — whether from the Console, CLI, or your application's code — is checked against IAM permissions before it's allowed to happen.
Why it exists
An AWS account, by default, has one all-powerful 'root' identity created at signup, with unrestricted access to everything including billing. Giving every developer, script, and application that root-level access would mean any single compromised credential or careless mistake (e.g. an accidentally-committed API key) could destroy or exfiltrate your entire infrastructure. IAM exists to implement the principle of least privilege: every identity gets exactly the permissions it needs to do its job, and nothing more, so a compromise or mistake in one place has a contained blast radius instead of an account-wide one.
Problem it solves
It solves the all-or-nothing access problem (without IAM, every credential would be root-equivalent), the credential-sharing problem (each person/service gets its own identity instead of everyone sharing one login), the auditability problem (every action is logged against a specific IAM identity via CloudTrail, so you know exactly who/what did what), and the temporary-access problem (IAM Roles let you grant short-lived, auto-expiring credentials instead of permanent ones).
Intuition
Think of IAM like a company's building and office key-card system. The 'root account' is the master key that opens every door in every building, including the vault — you lock it away and almost never carry it day-to-day. Each employee (IAM user) gets a key card programmed with access to only the doors they actually need for their job (an IAM policy). Some doors are only opened by badging in temporarily as a specific role for a specific task (an IAM Role) — like a contractor who gets a visitor badge that expires at the end of the day, rather than a permanent key card.
Analogy
A hotel's key-card system: the general manager has a master key (root), each staff department gets cards scoped to the areas they work in (IAM users/groups with policies), and a temporary maintenance contractor gets a card programmed to open exactly the one room they're fixing, valid only for a few hours (an IAM Role with temporary credentials) — never a permanent key that keeps working after the job is done.
Technical explanation
An IAM policy is a JSON document with a list of statements, each specifying an Effect (Allow or Deny), an Action (e.g. s3:GetObject, ec2:StartInstances), a Resource (a specific ARN — Amazon Resource Name — or a wildcard pattern), and optionally a Condition (e.g. only from a specific IP range, or only if MFA was used). When an API call is made, AWS evaluates every policy attached to the calling identity (directly, via group membership, and via any assumed role) — an explicit Deny anywhere always wins over an Allow, and if nothing explicitly allows the action, it's denied by default (default-deny).
Architecture
In a typical setup: individual developers get IAM Users belonging to an 'Admins' or 'Developers' IAM Group with an attached policy granting exactly the permissions that group needs; EC2 instances and Lambda functions are assigned IAM Roles (never long-lived access keys embedded in code) so the application automatically gets short-lived, auto-rotated temporary credentials scoped to only what it needs — e.g. a Lambda function's execution role might allow only s3:GetObject on one specific bucket and nothing else.
Workflow
- Create an IAM Group (e.g. 'Developers') and attach a policy defining what developers are allowed to do. 2) Create IAM Users for each person and add them to the appropriate group(s) — permissions come from the group, not set per-user. 3) Require MFA (multi-factor authentication) on all users, especially anyone with elevated permissions. 4) For any AWS resource that needs to call other AWS services (an EC2 instance calling S3, a Lambda function writing to DynamoDB), create and attach an IAM Role instead of embedding access keys — the resource automatically gets temporary credentials it never has to manage.
Example
A company sets up three IAM groups: 'ReadOnlyAnalysts' (can view but not modify any resource, for the data team), 'Developers' (can create/modify EC2, S3, and Lambda resources in a dev environment only, not production), and 'Admins' (broad access, MFA-required, only 2 people). A new backend service that needs to read from an S3 bucket and write to a DynamoDB table gets an IAM Role (not a developer's personal credentials) attached to its EC2 instance, scoped to exactly s3:GetObject on that one bucket and dynamodb:PutItem on that one table — if the instance is ever compromised, the attacker can't touch anything outside those two narrow permissions.
Real-world usage
AWS's own security best-practice documentation and virtually every security audit/compliance framework (SOC 2, PCI DSS) require least-privilege IAM design as a baseline control; a large fraction of publicly reported cloud security incidents trace back to overly permissive IAM policies (e.g. a wildcard '*' resource on a sensitive action) or long-lived access keys leaked in public code repositories — both problems IAM Roles and scoped policies are specifically designed to prevent.
Trade-offs
Fine-grained least-privilege policies are more secure but take more time to write and maintain correctly, and can slow down development if permissions are too restrictive (developers hit 'access denied' constantly). Broader policies are faster to set up and reduce day-to-day friction but expand the blast radius of any compromise or mistake. Most teams start slightly broad in early development and progressively tighten policies (least-privilege by iteration) as the system stabilizes and its real access patterns become clear.
Visual explanation
Picture four boxes connected by arrows: 'IAM User' (a person or app with permanent long-term credentials) and 'IAM Role' (an identity assumed temporarily, no permanent credentials) both point to → 'IAM Policy' (a JSON document listing Allow/Deny rules for specific actions on specific resources) which is attached directly to a user/role, or attached to an 'IAM Group' (a named collection of users) that many users belong to, so you manage permissions once at the group level instead of per-user.
Advantages
- —
Fine-grained least-privilege control — grant exactly the actions and resources needed, nothing more
- —
IAM Roles provide temporary, auto-rotating credentials, eliminating the risk of a leaked permanent access key
- —
Every action is auditable per-identity via CloudTrail, supporting compliance and incident investigation
- —
Group-based permission management scales to large teams without per-user policy sprawl
Disadvantages
- —
Policy JSON can get complex quickly, especially with conditions and resource ARN patterns — misconfiguration is common
- —
Overly broad policies (wildcard actions/resources) are easy to write quickly and hard to notice are wrong until an incident happens
- —
Managing permissions across many accounts (AWS Organizations) adds another layer of complexity beyond single-account IAM
- —
There's no built-in 'preview what this policy actually allows' in the basic Console flow — understanding real-world effect often requires the IAM Policy Simulator or careful manual review
Common mistakes
- —
Using the root account for everyday work instead of creating an IAM admin user — root should be locked away with MFA and used only for account-level tasks (e.g. changing the support plan)
- —
Embedding long-lived IAM user access keys directly in application code or committing them to a Git repository — a very common source of real breaches; use IAM Roles for anything running on AWS infrastructure instead
- —
Writing policies with wildcard Resource ("*") 'to get it working' and never tightening them afterward
- —
Not enabling MFA on IAM users, especially those with any administrative permissions
In the AWS Console
- 1
AWS Console → search 'IAM' → IAM Dashboard
Under Security recommendations, add MFA to the root account first, then avoid using root for anything else.
This is the single highest-priority IAM console action for any new AWS account.
- 2
IAM → User groups → Create group
Name the group (e.g. 'Developers'), attach an appropriate managed policy (e.g. 'PowerUserAccess' for a dev environment) or a custom policy.
Prefer AWS managed policies for common roles before writing custom JSON policies from scratch.
- 3
IAM → Users → Create user
Create the user, add them to the group created above (do not attach policies directly to the user), and enable console access if needed.
Managing permissions at the group level, not per-user, is what keeps IAM maintainable as a team grows.
- 4
IAM → Roles → Create role → AWS service → EC2
Attach a policy scoped to exactly what the EC2 instance needs (e.g. read access to one S3 bucket), then attach this role to the instance under EC2 → Actions → Security → Modify IAM role.
This is how an application gets AWS permissions without ever having a hardcoded access key.
🎤 Interview questions
What's the difference between an IAM user and an IAM role? (Listen for: user = permanent identity with long-lived credentials for a person/app; role = temporary identity assumed as needed, no permanent credentials, ideal for AWS resources calling other AWS services.)
Why shouldn't you use the AWS root account for daily development work? (Listen for: root has unrestricted access including billing; any compromise is catastrophic; create a scoped IAM admin user instead and lock root away with MFA.)
How does IAM decide whether to allow or deny an API call? (Listen for: evaluates all attached policies; explicit Deny always wins; default is deny if nothing explicitly allows it.)
An EC2 instance needs to read from an S3 bucket. What's the best-practice way to grant that access? (Listen for: attach an IAM Role to the instance scoped to that specific bucket/action — never hardcode long-lived access keys in the application.)
What's the principle of least privilege, and how does IAM implement it? (Listen for: grant only the exact permissions needed for a task, nothing more; implemented via narrowly scoped policies attached to users/groups/roles.)