๐ AWS IAM Deep Dive
Authentication ยท Authorization ยท Accounting ยท Roles ยท EC2 Basics
This is part of my ongoing AWS learning journey as I transition from Systems Engineer to Cloud/DevOps. I'm documenting everything I learn โ concepts, hands-on steps, and the "why" behind each one.
Why IAM Exists โ The Real Answer
When you first create an AWS account, you get a Root user. It has zero restrictions โ it can delete everything, rack up unlimited bills, create or destroy any resource. That's exactly why you should almost never use it.
Real teams have multiple people โ developers, DevOps engineers, auditors, managers. You don't want everyone logging into the same all-powerful Root account. You need controlled, tracked, individual access. That's what IAM solves.
IAM answers one fundamental question: Who can do what, on which AWS resource โ and is it being recorded?
That question maps perfectly to a security framework called AAA.
The AAA Framework
Every access control system โ not just AWS โ is built on three pillars:
| Pillar | Question it answers | How AWS implements it |
|---|---|---|
| Authentication | Who are you? | Credentials (username + password) + MFA |
| Authorization | What can you do? | IAM Policies and Roles |
| Accounting | What did you do? | AWS CloudTrail (full audit logs) |
When you log into AWS and try to start an EC2 instance, all three happen in sequence โ AWS verifies your identity, checks if you're allowed to start EC2, and logs that you did it. Every single time.
MFA โ The Second Lock
A password alone isn't enough. If someone gets your password, they're in. MFA adds a second factor โ a time-based OTP from your phone โ so even a stolen password is useless without the physical device.
Three MFA types:
| Type | How it works | When to use |
|---|---|---|
| Virtual MFA | Google Authenticator / Authy app | โ Default choice for learning |
| Hardware MFA | Physical YubiKey device | โ โ Best for Root account |
| SMS/Voice | OTP via text message | โ ๏ธ Weakest, avoid if possible |
Always enable MFA on Root first. Then on your IAM user too.
IAM Users
An IAM User is an identity created inside your AWS account for a specific person or application. Unlike Root, it starts with zero permissions โ it can log in but can't do anything until you attach a policy.
Creating an IAM User (what you actually did):
IAM Console โ Users โ Create User
โ Set username
โ Enable Console access + set password
โ (Optional) Add tags
โ Attach policy directly OR add to a group
โ Done โ user can now log in with limited access
One important thing: an IAM user with permission to create users can create more IAM users. Permissions propagate โ so be careful what you give.
IAM Groups โ Managing at Scale
Imagine you have 10 developers. Attaching policies to each one individually is painful and error-prone. Groups solve this.
A Group is a collection of IAM users. Attach a policy to the group once โ every user in it inherits those permissions automatically.
Group: DevOpsTeam โ Policy: PowerUserAccess
โโโ User: tejas โ gets PowerUserAccess โ
โโโ User: ravi โ gets PowerUserAccess โ
โโโ User: priya โ gets PowerUserAccess โ
Add a new team member โ add to group โ done.
Remove someone โ remove from group โ done.
Key rules:
- One user can belong to multiple groups
- Groups cannot contain other groups (no nesting)
- Default quota: 300 groups per account
Creating via Group (the cleaner approach):
Create IAM Group โ Attach policy to group
โ Create IAM User โ Add user to group
โ User inherits group's permissions automatically
IAM Policies โ The Permission Document
A Policy is a JSON document that defines exactly what is allowed or denied. Every time you make a request in AWS โ clicking a button, running a CLI command, an app calling an API โ AWS checks the relevant policies to decide: allow or deny?
Basic structure:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
| Field | What it means |
|---|---|
Effect |
Allow or Deny
|
Action |
Which API operation (e.g. s3:GetObject, ec2:*) |
Resource |
Which specific resource (by ARN) |
Condition |
Optional โ e.g. "only if MFA is active" |
The one rule that matters most:
Explicit Deny > Everything else
No Policy = Denied by default
Explicit Allow = Access granted (unless a Deny exists)
If a Deny exists anywhere in any applicable policy, it always wins โ even if an Allow exists somewhere else.
What about combined permissions?
AWS combines all Allow permissions across all sources:
User has: AmazonEC2FullAccess (direct policy)
Group has: ReadOnlyAccess
Result: EC2 Full Access + ReadOnly on everything else
(the more permissive wins, unless there's an explicit Deny)
SCP โ The Ceiling Above IAM
You now understand IAM policies. But there's something that sits above IAM entirely.
SCP = Service Control Policy โ it's part of AWS Organizations (used when you manage multiple AWS accounts together).
The key distinction:
| IAM Policy | SCP | |
|---|---|---|
| Attached to | Users, Groups, Roles | AWS Accounts / Organizational Units |
| Does it grant permissions? | โ Yes | โ No โ only limits |
| Can it restrict Root? | โ No | โ Yes |
| Who uses it? | Everyone | Enterprises with multiple accounts |
SCP defines the maximum permissions possible in an account. IAM policies still need to grant the actual access โ but they can never exceed what SCP allows.
Example: SCP says "no S3 access allowed in this account." Even if an IAM policy gives a user S3FullAccess, they still can't access S3. SCP wins.
For now, SCP is mostly relevant at enterprise scale. Keep it in mind โ it'll come up in interviews.
ARN โ Every Resource Has a Unique ID
ARN = Amazon Resource Name. Every single thing in AWS โ users, roles, buckets, instances โ has a globally unique ARN.
Format:
arn:aws:SERVICE:REGION:ACCOUNT-ID:RESOURCE
Examples:
arn:aws:iam::123456789012:user/tejas โ IAM User
arn:aws:iam::123456789012:role/S3AccessRole โ IAM Role
arn:aws:s3:::my-bucket โ S3 Bucket
arn:aws:ec2:ap-south-1:123456789:instance/i-abc โ EC2 Instance
ARNs are used everywhere โ in trust policies, resource-based policies, CloudTrail logs. When you're adding a user to a role's trust policy, you paste their ARN.
IAM Roles โ Temporary Identity, No Password
This is where most beginners get confused. Let's clear it up completely.
An IAM Role is a temporary identity with permissions โ no username, no password. It's meant to be assumed โ picked up temporarily by a user or an AWS service, used, and then dropped.
The visitor badge analogy:
Think of a role as a visitor badge at an office. A visitor picks up the badge at reception (assumes the role), gets access to specific floors (permissions), and returns the badge when done (session ends). No permanent access. No long-term credentials.
IAM User vs IAM Role
| IAM User | IAM Role | |
|---|---|---|
| Has password? | โ Yes | โ No |
| Permanent? | โ Yes | โ Temporary (assumed) |
| For? | Human beings | Services or temporary access |
| Credentials | Long-term | Short-term, auto-rotated |
Trust Policy โ Who Can Assume a Role?
Every IAM Role has two things attached:
- Permission Policy โ what the role is allowed to do
- Trust Policy โ who is allowed to assume this role
The Trust Policy is a JSON document that answers: "Who gets to pick up this badge?"
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/tejas"
},
"Action": "sts:AssumeRole"
}]
}
This says: only the IAM user tejas can assume this role.
Role Switching:
Here's the complete flow:
Step 1: Create a Role
IAM โ Roles โ Create Role
โ Attach permission: AmazonS3FullAccess
โ Name it: S3AccessRole
Step 2: By default, nobody can assume it
Your IAM user tries to switch โ fails โ
Step 3: Edit the Trust Policy
Open S3AccessRole โ Trust Relationships โ Edit
โ Add your IAM user's ARN as a trusted principal
โ Save
Step 4: Switch Role (from Console top-right)
Click your username โ Switch Role
โ Enter Account ID + Role name
โ You're now operating AS the role
Step 5: What changes?
โ
You can now access S3
โ Your original EC2 permissions are SUSPENDED
โ Role permissions fully replace your user permissions for this session
Step 6: Switch back
Click role name (top-right) โ Switch Back
โ Back to your original IAM user permissions
โ S3 access gone
That EC2 access disappearing when you switched to S3 role wasn't a bug โ that's exactly how role switching works. The role's permissions replace your current ones for the duration of the session.
Service Principal โ Roles for AWS Services
So far, roles have been assumed by IAM users (humans). But AWS services need to access other services too โ and they use roles for that.
A Service Principal is the identity of an AWS service, used in trust policies:
ec2.amazonaws.com โ EC2 can assume roles
lambda.amazonaws.com โ Lambda can assume roles
s3.amazonaws.com โ S3 can assume roles
Example: EC2 accessing S3 automatically
You want your EC2 instance to read/write S3 without hardcoding any credentials in your code.
Bad approach โ:
aws_access_key_id = 'AKIAIOSFODNN7EXAMPLE' โ hardcoded in code
aws_secret_access_key = 'wJalrXUt...' โ if pushed to GitHub, you're done
Right approach โ
:
Create a Role with S3 permissions
Trust Policy: ec2.amazonaws.com can assume this role
Attach role to EC2 via Instance Profile
EC2 automatically gets temporary, rotating credentials
Your code just calls S3 โ no credentials anywhere
IAM Instance Profile โ The Bridge Between EC2 and IAM
An Instance Profile is a container that wraps an IAM Role and delivers it to an EC2 instance. When you attach a role to EC2 via the Console, an Instance Profile is created automatically behind the scenes.
Complete flow:
IAM Role (S3AccessRole)
โ wrapped in
Instance Profile
โ attached to
EC2 Instance
โ app calls
AWS Metadata Service (169.254.169.254) โ internal AWS endpoint
โ returns
Temporary credentials (auto-rotated every hour)
โ used to
Access S3 โ
โ no hardcoded keys, no manual rotation
Lab steps:
Step 1: Create Role
IAM โ Roles โ Create Role
Trusted entity: AWS Service โ EC2
Attach policy: AmazonS3FullAccess
Name: EC2-S3-Role
Step 2: Attach to EC2
EC2 Console โ Select Instance
Actions โ Security โ Modify IAM Role
Select: EC2-S3-Role โ Update
Step 3: Test
SSH into EC2 โ run: aws s3 ls
โ Lists your S3 buckets โ
(zero credentials configured)
EC2 Basics โ Launching Your First Instance
EC2 = Elastic Compute Cloud โ a virtual machine running on AWS hardware. When you launch one, you're renting a slice of a physical server in an AWS data center.
The Key Components
AMI (Amazon Machine Image)
A pre-built template containing the OS, software, and configuration. It's the blueprint your EC2 instance is built from.
- Amazon Linux 2, Ubuntu 22.04, Windows Server โ these are all AMIs
- AMIs are Region-specific โ if you want the same AMI in another Region, you must manually copy it. AWS does not auto-replicate AMIs.
Instance Type
Defines CPU, RAM, and network capacity.
-
t2.microโ 1 vCPU, 1 GB RAM โ Free Tier eligible โ - Naming:
t3.mediumโ t = family, 3 = generation, medium = size
Key Pair
Used to SSH into your EC2 instance securely โ no password needed.
- AWS puts the public key on your EC2 instance
- You download the private key (
.pemfile) - You use
.pemto prove your identity:ssh -i key.pem ec2-user@<ip> - Download once. If you lose it, you lose SSH access. No recovery.
Security Group
Acts as a virtual firewall. Controls what traffic can reach your instance.
- Port 22 (SSH) โ for terminal access
- Port 80 (HTTP) โ for web traffic
- Port 443 (HTTPS) โ for secure web traffic
User Data
A script that runs once automatically the first time EC2 boots. Used to install software, configure servers, deploy apps โ all without manual steps.
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from EC2!</h1>" > /var/www/html/index.html
This script installs Apache web server and creates a basic webpage โ automatically on first boot.
EC2 Launch Flow (What You Did)
EC2 Console โ Launch Instance
โ
Name/Tags โ give it a meaningful name
โ
AMI โ Amazon Linux 2 (Free Tier)
โ
Instance Type โ t2.micro (Free Tier)
โ
Key Pair โ Create new โ Download .pem file (save it!)
โ
Security Group โ Allow SSH (22) + HTTP (80)
โ
Storage โ Default 8 GB (Free Tier covers this)
โ
Advanced โ User Data โ paste startup script
โ
Launch Instance
โ
Wait ~2 minutes โ Instance state: Running
โ
Copy Public IP โ open in browser โ "Hello from EC2!" โ
Two Policy Types โ Identity vs Resource Based
You've now seen policies attached to users, groups, and roles. But policies can also be attached to resources directly.
Identity-Based Policy
- Attached to: IAM user, group, or role
- Says: "This identity can perform these actions"
- No
Principalfield needed (the identity it's attached to is the principal) - Example: AmazonEC2FullAccess attached to your IAM user
Resource-Based Policy
- Attached to: a resource (S3 bucket, SQS queue, etc.)
- Says: "These identities are allowed to access me"
- Has a
Principalfield โ explicitly names who can access - Example: S3 bucket policy allowing a specific IAM user to read objects
{
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789:user/tejas"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
Quick Revision
AAA FRAMEWORK
Authentication โ Who are you? (credentials + MFA)
Authorization โ What can you do? (IAM policies)
Accounting โ What did you do? (CloudTrail)
PERMISSION HIERARCHY
SCP (Organizations) โ ceiling, limits max permissions
IAM Policies โ actual grants within that ceiling
Explicit Deny โ always wins over everything
IAM BUILDING BLOCKS
User โ permanent identity, has password, for humans
Group โ collection of users, attach policy once
Role โ temporary identity, no password, assumed
Policy โ JSON doc defining Allow/Deny on resources
ARN โ unique ID for every AWS resource
ROLE SWITCHING
Add user ARN to role's Trust Policy
User switches role โ gets role permissions temporarily
Original permissions suspended during session
Switch back โ original permissions restored
INSTANCE PROFILE (EC2 โ S3)
Create Role (trust: ec2.amazonaws.com) + S3 policy
Attach to EC2 via Instance Profile
EC2 auto-gets temp credentials โ accesses S3
Zero hardcoded credentials โ
EC2 BASICS
AMI = OS template (Region-specific, must copy to use elsewhere)
Key Pair = SSH access (.pem โ download once, don't lose)
User Data = startup script (runs once on first boot)
t2.micro = Free Tier instance type
Interview Questions
Q1: What is the difference between an IAM User and an IAM Role?
An IAM User has permanent credentials (username + password) and is meant for human beings. An IAM Role has no password โ it provides temporary credentials and is assumed by users or AWS services when needed. Roles are best practice for service-to-service communication.
Q2: What is a Trust Policy and why is it needed?
A Trust Policy is a JSON document attached to an IAM Role that defines who is allowed to assume that role. Without it, nobody can use the role โ not even admins. You explicitly add trusted principals (IAM user ARNs or service principals like ec2.amazonaws.com).
Q3: What happens when you switch roles in AWS?
Your current IAM user permissions are temporarily suspended and replaced by the role's permissions for that session. When you switch back, your original permissions are restored. This is why EC2 access disappeared when you switched to the S3 role.
Q4: What is an Instance Profile and why use it instead of access keys?
An Instance Profile is a container that delivers an IAM Role to an EC2 instance. It gives EC2 automatic, temporary, rotating credentials via the metadata service โ no hardcoded keys needed. This is far more secure than embedding access keys in code, which can be accidentally exposed.
Q5: What is the difference between SCP and IAM policies?
IAM policies grant permissions to users, groups, or roles within an account. SCPs (Service Control Policies) sit above IAM at the Organizations level and define the maximum permissions allowed in an account โ they restrict, not grant. Even the Root user is subject to SCP.
Q6: An IAM user has EC2FullAccess via direct policy and ReadOnlyAccess via their group. What's their effective permission?
They get EC2 Full Access plus ReadOnly on everything else. AWS combines all Allow permissions. However, if an Explicit Deny exists anywhere, that overrides all Allows.
Practice Tasks
- Create an IAM Group called
DevOpsTeam, attachPowerUserAccess, create a user and add them to the group. Log in as that user and verify you can access EC2 but not billing. - Create an IAM Role with
AmazonS3ReadOnlyAccess. Edit its Trust Policy to add your IAM user's ARN. Switch to that role and verify S3 access. Notice EC2 access is gone. - Launch an EC2 instance with a User Data script that installs Apache. Access the public IP in your browser and confirm the webpage loads.
- Create an IAM Role for EC2 with S3 access. Attach it to a running EC2 instance via Modify IAM Role. SSH in and run
aws s3 lsโ confirm it works without any credentials configured. - Open
AmazonEC2FullAccesspolicy JSON in the IAM Console. Find whatec2:*means and identify 3 specific actions it includes.
Part of my AWS Cloud + DevOps learning journey โ documenting everything as I transition from Systems Engineer to Cloud/DevOps Engineer.
Top comments (0)