Skip to main content

IAM - Users, Roles, Policies, and Least Privilege in Production

Implement AWS IAM with users, groups, roles, and JSON policies following least privilege principles — and audit with Credentials Report and Access Advisor.

What you will learn

  • What IAM is and why every AWS action passes through it first
  • The Root User — what it is, when to use it, and why you should almost never touch it
  • IAM Users, Groups, and how permissions flow from group to individual
  • How to read and write IAM Policy JSON — every field explained
  • Why explicit Deny always wins no matter what
  • IAM Roles — why they exist and how AWS services use them safely
  • MFA, password policy, and the rules around access keys
  • The two audit tools that keep your account clean as it grows

Why this matters

Every single action in AWS — launching an EC2, reading an S3 file, deleting a database — goes through IAM first. Get IAM wrong and you either lock your team out of what they need or hand an attacker the keys to everything.

This is not a one-time setup. IAM is something you audit, tighten, and maintain as your team grows. The most common AWS security incidents — credentials leaked on GitHub, over-permissive roles, inactive users with full admin access — are all IAM failures. Engineers who treat IAM as a formality are the ones who wake up to compromised accounts and unexpected bills.

What is IAM and the Root User Problem

IAM (Identity and Access Management) is a global AWS service that controls two things for every single request made in your account:

◈ DIAGRAM
Who are you? → Authentication (proving your identity)
What can you do? → Authorization (what actions are allowed)

IAM is not region-specific. A user you create today works in Mumbai, Singapore, and Virginia equally.

When you first open an AWS account, you get a Root User — created with your account email and password. Root has complete, unrestricted access to everything: billing, IAM, every service, every region. No IAM policy in the world can limit it.

◈ DIAGRAM
Root User reality:
Full access to billing, support, all 200+ AWS services
Cannot be restricted by any IAM policy — ever
If credentials are stolen → entire account is compromised
When to actually use Root (only these 4 cases):
Initial account setup — creating your first IAM admin user
Managing billing and payment methods
Account recovery
Closing the AWS account
Security

Enable MFA on Root immediately after account creation. Never create Access Keys for Root. Never use it for daily work. Think of Root like a master key to your entire office building — kept locked in a safe and taken out only in genuine emergencies.

Users, Groups, and How Permissions Flow

IAM Users represent one real person or one application. One person = one user. Always. Sharing users makes auditing impossible — if something goes wrong you cannot tell who did it.

Each IAM user gets:

  • A username and password → for Console login
  • Access Key ID and Secret Access Key → for CLI and SDK access

IAM Groups are containers for users with the same job role. Attach a policy to the group once — everyone inside inherits it automatically.

◈ DIAGRAM
Example team at a Bangalore fintech startup:
Group: Developers → Arjun, Rohan → EC2 Full + S3 Read
Group: Testers → Sneha → EC2 Read-only
Group: Admins → Priya → AdministratorAccess
Rohan is also added to Group: Audit Team → IAM ReadOnly
Result: Rohan gets Developer permissions PLUS Audit permissions combined

Three rules that trip engineers up:

TEXT
Groups contain users only — you cannot put a group inside another group
A user can belong to multiple groups — permissions from all groups combine
A user can exist outside all groups — allowed but not recommended
Remember

Always attach policies to Groups, not directly to individual users. When someone changes roles, just move them between groups. Individual user policies pile up silently and become impossible to audit over time.

IAM Policies — Reading and Writing Permissions

A Policy is a JSON document that defines exactly what actions are allowed or denied on which AWS resources. This is the actual engine behind every permission in AWS.

A real policy — read-only access to one S3 bucket:

JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadPaymentLogs",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::razorpay-payment-logs",
"arn:aws:s3:::razorpay-payment-logs/*"
]
},
{
"Sid": "ExplicitlyDenyDelete",
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "arn:aws:s3:::razorpay-payment-logs/*"
}
]
}

This lets someone read payment logs but blocks any delete — even if another policy tries to allow it.

Every field explained:

Field Required What it does
Version Yes Policy language version — always use "2012-10-17"
Sid No A readable label for the statement — helps you audit later
Effect Yes Allow or Deny — what happens when this rule matches
Action Yes Which AWS API calls — e.g. s3:GetObject, ec2:*
Resource Yes Which resource — * means all, or a specific ARN
Principal Sometimes Who the policy applies to — used in resource-based policies
Condition No Extra conditions — IP range, MFA required, time of day
Remember

Effect: Deny always wins over Effect: Allow. If one policy allows an action and another denies it, Deny wins every time with no exceptions. This is the explicit deny rule. Statement order inside a policy does not matter — AWS evaluates all statements together.

The most common S3 ARN mistake:

Bash
s3:ListBucket applies to the bucket itself:
"Resource": "arn:aws:s3:::my-bucket"
s3:GetObject and s3:PutObject apply to objects inside:
"Resource": "arn:aws:s3:::my-bucket/*"
You need both statements for full S3 read access.
Using only one or the other is why S3 policies silently fail.

Three types of policies:

Type Created by When to use
AWS Managed AWS Standard roles — AmazonS3ReadOnlyAccess, AdministratorAccess
Customer Managed You Custom rules specific to your organisation
Inline You — directly on a user or role Avoid — not reusable, hard to audit

How permissions combine:

◈ DIAGRAM
Developers group → EC2FullAccess → Arjun, Rohan, Priya all get it
Audit Team group → IAMReadOnlyAccess → Rohan also gets this
Inline Policy → special rule → Fred only — attached to his user
Rohan = EC2Full + IAMReadOnly combined
Fred = his inline policy only

IAM Roles — Permissions for AWS Services

IAM Roles solve a different problem from users. AWS services like EC2, Lambda, and ECS need to call other AWS services. How do you give an EC2 instance permission to read S3 without storing credentials on it?

The wrong way — what beginners do:

◈ DIAGRAM
Developer puts AWS credentials directly on EC2:
AWS_ACCESS_KEY_ID = AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
→ Keys in config → config pushed to GitHub → repo public for 10 minutes
→ Automated scanner finds keys within 60 seconds
→ Account compromised. Bills run up. Data exfiltrated.

The right way — IAM Roles:

◈ DIAGRAM
Attach IAM Role to the EC2 instance
↓
Role has policy: Allow s3:GetObject on payment-logs bucket
↓
AWS SDK on EC2 automatically fetches TEMPORARY credentials
↓
Credentials expire in 1-12 hours and auto-rotate
↓
No keys stored anywhere. Nothing to leak. Nothing to rotate manually.

User vs Role — the key difference:

Feature IAM User IAM Role
Designed for Humans and long-running apps AWS services
Credentials Long-term — password and access keys Temporary — auto-rotated
Risk if stolen High — valid until manually rotated Low — expires automatically
Example Arjun logs into Console EC2 reads from S3

Common roles you create in every production project:

◈ DIAGRAM
EC2 Instance Role → app reads S3, writes to DynamoDB, calls Secrets Manager
Lambda Execution Role → Lambda writes logs to CloudWatch, queries RDS
ECS Task Role → container sends messages to SQS, reads from S3
CodeDeploy Role → pipeline pushes deployments to EC2 instances
CloudFormation Role → CloudFormation creates resources on your behalf
Tip

If you are ever tempted to put an access key inside an EC2 instance, Lambda function, or Docker container — stop. Create a Role instead. The SDK fetches temporary credentials automatically. No keys. No risk. No rotation.

Securing Access — MFA, Password Policy, Access Keys

MFA — Multi-Factor Authentication

MFA adds a second layer. Even if someone steals Priya's password, they cannot log in without her physical device.

◈ DIAGRAM
Without MFA:
Password stolen via phishing → attacker logs in → full account access
With MFA:
Password stolen → attacker tries to log in → AWS asks for 6-digit code
→ Attacker does not have Priya's phone → blocked completely

MFA device options:

Type Device How it works
Virtual MFA Google Authenticator, Authy App generates 6-digit code every 30s — free
U2F Security Key YubiKey Plug in and tap — strongest physical option
Hardware Key Fob Gemalto device Physical rotating display — corporate environments
GovCloud Key Fob SurePassID device Same but for AWS GovCloud US only

Password Policy

Set account-wide rules for all IAM users:

  • Minimum length (12+ characters recommended)
  • Require uppercase, lowercase, numbers, special characters
  • Allow users to change their own passwords
  • Force expiration every 90 days
  • Prevent reuse of last N passwords

Location: IAM → Account Settings → Password Policy

Access Keys — for CLI and SDK access

TEXT
Access Key ID ≈ username (an identifier — safe to share)
Secret Access Key ≈ password (a secret — never share this)

Non-negotiable rules:

  • Never commit to Git — scanners watch GitHub, GitLab, Bitbucket 24/7
  • Never hardcode in application source code
  • Never share with teammates — each person generates their own
  • Deactivate immediately if you suspect a leak
  • For EC2, Lambda, and ECS — never use keys at all, use Roles

Setting up AWS CLI:

Bash
## Configure with your IAM user access keys
aws configure
## You will be prompted for:
## AWS Access Key ID → your key ID
## AWS Secret Access Key → your secret key
## Default region name → ap-south-1
## Default output format → json
## Verify it works
aws iam get-user
aws s3 ls
aws ec2 describe-instances --region ap-south-1
Tip

AWS CloudShell is a browser-based terminal inside the Console — pre-configured with your credentials, zero local setup. Perfect for quick commands without configuring your local machine.

Three ways to access AWS:

Method Protected by Use for
AWS Management Console Password + MFA Humans, browser, one-off tasks
AWS CLI Access Keys Automation, scripts, CI/CD
AWS SDK (Python, Node, Java) Access Keys Application code calling AWS APIs

IAM Security Audit Tools

Once teams grow, permissions drift silently. People leave but their users stay active. A service has permissions for 10 actions but only ever calls 2.

IAM Credentials Report — account-level snapshot

Downloads a CSV of every IAM user and their credential status:

  • Password enabled, MFA active, access keys active or inactive
  • Last login date and last key use date
  • Find: users inactive for 90+ days (probably left the company), unused access keys

Location: IAM → Credential Report → Download

IAM Access Advisor — per-user permission usage

Shows which AWS services a specific user or role actually accessed and when. Use this to trim unused permissions.

◈ DIAGRAM
Real example — trimming Arjun's permissions:
Arjun currently has: EC2Full + S3Full + RDSFull + LambdaFull + CloudWatchFull
Access Advisor shows:
S3 → accessed 2 days ago
CloudWatch → accessed 1 week ago
EC2 → accessed 5 months ago
RDS → never accessed
Lambda → never accessed
Action: Remove RDS and Lambda. Review EC2.
Result: Smaller blast radius if Arjun's credentials are ever compromised.

Location: IAM → Users → select user → Access Advisor tab

Remember

Credentials Report = audit the entire account at once. Access Advisor = trim permissions for one specific user or role. Run both every month in any production account.

Hands-on Lab — Set Up IAM the Right Way From Day One

This is the exact setup every AWS account should have before anything else is built.

Step 1 — Enable MFA on Root

◈ DIAGRAM
Log in as Root
Top right → Account name → Security credentials
Multi-factor authentication → Assign MFA device
Choose: Authenticator app → scan QR code with Google Authenticator
Enter two consecutive codes to confirm → MFA enabled

Step 2 — Create your first IAM Admin user

◈ DIAGRAM
IAM → Users → Create user
Username: priya-admin
Console access: Enable → Custom password → set a strong password
Permissions: Attach policies directly → AdministratorAccess
Create user
Log out of Root. Log back in as priya-admin.
Use this account for all daily work from now on.

Step 3 — Create Groups with correct policies

◈ DIAGRAM
IAM → User Groups → Create group
Group name: Developers
Attach policies: AmazonEC2FullAccess + AmazonS3ReadOnlyAccess
Create group
Create another:
Group name: Testers
Attach policies: AmazonEC2ReadOnlyAccess
Create group

Step 4 — Create a developer user and add to group

◈ DIAGRAM
IAM → Users → Create user
Username: arjun-dev
Console access: Enable → set password
Add user to group: Developers
Create user
Verify: IAM → Users → arjun-dev → Permissions
You should see: AmazonEC2FullAccess and AmazonS3ReadOnlyAccess inherited from Developers group

Step 5 — Create access keys for CLI

◈ DIAGRAM
IAM → Users → arjun-dev → Security credentials
Create access key → Use case: CLI → Create
Download the CSV — the Secret Access Key is shown only once

Step 6 — Configure CLI and test

Bash
aws configure --profile arjun-dev
## Enter the access key ID and secret from the CSV
## Region: ap-south-1
## Output format: json
## Test — should work
aws s3 ls --profile arjun-dev
aws ec2 describe-instances --region ap-south-1 --profile arjun-dev
## Test a denied action — should fail
aws iam list-users --profile arjun-dev
## Error: Access Denied (arjun-dev has no IAM permissions)

Step 7 — Create an IAM Role for EC2

◈ DIAGRAM
IAM → Roles → Create role
Trusted entity: AWS service → EC2
Permissions: AmazonS3ReadOnlyAccess
Role name: ec2-s3-read-role → Create
Launch or select an EC2 instance:
Actions → Security → Modify IAM Role → ec2-s3-read-role → Update
SSH into the instance and test:
Bash
## No aws configure needed — role provides credentials automatically
aws s3 ls --region ap-south-1
## Works immediately
aws sts get-caller-identity
## Shows the role ARN — confirms role is active, not a personal key

Step 8 — Download and review Credentials Report

◈ DIAGRAM
IAM → Credential Report → Download report
Open the CSV and look for:
password_last_used = N/A → user never logged in, consider removing
access_key_1_last_used_date = old → key not used, deactivate it
mfa_active = false → no MFA, security risk

Expected result: Root is MFA-protected and unused. You have a working admin user for daily work. A developer user with scoped group permissions is set up. CLI access is configured and tested. You have read your first credentials report.

Common Mistakes to Avoid

Common Mistake

Storing AWS access keys on an EC2 instance by running aws configure on the server. If that instance is ever compromised — through a vulnerability, a leaked SSH key, or a misconfigured Security Group — the attacker gets your AWS credentials. Use IAM Roles. The SDK fetches temporary credentials automatically. No keys stored anywhere.

Common Mistake

Creating one shared IAM user for an entire team. When that credential is leaked (and it eventually will be), you cannot tell which team member made which API call. You cannot revoke one person's access without affecting everyone. One person = one IAM user. Always.

Common Mistake

Attaching policies directly to individual users instead of groups. Three months later you have 20 users each with a different set of directly-attached policies. No one knows what permissions anyone has. Put everyone in groups. Manage permissions on the group. One change affects everyone in the group instantly.

Security

The IAM Credentials Report shows access keys that have never been used or have not been used in 90+ days. Every one of those is a credential that could be leaked without you noticing. If it is not being used, it should not exist. Deactivate first, then delete after a week if nothing breaks.

Resources

AWS Direct Connect vs Site-to-Site VPN Failover

AWS Direct Connect vs Site-to-Site VPN Failover

Direct Connect vs VPN isn't really either/or for production — it's a primary-plus-failover pattern. Here's how to design it, and when either/or is right.

5 min read•Aug 2026
Lambda vs Fargate vs EC2 Spot: The Cost Crossover

Lambda vs Fargate vs EC2 Spot: The Cost Crossover

Lambda vs Fargate vs EC2 Spot, at the crossover where Lambda stops being cheaper — 2026 pricing, invocation thresholds, and interruption math.

5 min read•Aug 2026
Secrets Manager vs Parameter Store vs Vault

Secrets Manager vs Parameter Store vs Vault

AWS Secrets Manager, Parameter Store, and HashiCorp Vault compared for 2026 - cost math, rotation, multi-cloud fit, and the Vault-to-OpenBao fork.

5 min read•Aug 2026
AWS VPC Security: Hardening Every Layer

AWS VPC Security: Hardening Every Layer

Most cloud security incidents start with a misconfigured VPC. Here's how to harden every layer — subnets, Security Groups, NACLs, and IAM — for production.

5 min read•Jul 2026
Event-Driven Architecture on AWS Explained

Event-Driven Architecture on AWS Explained

Event-driven architecture on AWS decouples services and absorbs traffic spikes using SQS, SNS, EventBridge, and Lambda — workflows that scale themselves.

5 min read•Jul 2026
S3 vs RDS vs DynamoDB: Choosing AWS Storage

S3 vs RDS vs DynamoDB: Choosing AWS Storage

Choosing S3, RDS, or DynamoDB wrong costs you in performance, cost, and scalability. Here is a practical decision guide based on your actual access patterns.

5 min read•Jul 2026
AWS Cost Optimisation: Cut Cloud Bills 40-60%

AWS Cost Optimisation: Cut Cloud Bills 40-60%

AWS bills surprise teams every month. Here are the 8 concrete actions that cut cloud spend by 40-60% without touching your application architecture.

5 min read•Jul 2026
EC2 vs Lambda vs Fargate: Choosing AWS Compute

EC2 vs Lambda vs Fargate: Choosing AWS Compute

EC2, Lambda, or Fargate — choosing the wrong AWS compute option costs you money and performance. Here is exactly when to use each one in production.

5 min read•Jul 2026

Explore More in AWS Networking and Security

All 6 Topics

Frequently Asked Questions

Is IAM - Users, Roles, Policies, and Least Privilege in Production free to learn on DevOps Network?

Yes - this topic, like everything on DevOps Network, is 100% free with no paywall or sign-up gate.

What does the IAM - Users, Roles, Policies, and Least Privilege in Production topic cover?

Implement AWS IAM with users, groups, roles, and JSON policies following least privilege principles — and audit with Credentials Report and Access Advisor.

Does IAM - Users, Roles, Policies, and Least Privilege in Production include hands-on modules?

Yes - this topic has 1 attached module for hands-on practice.