DEV Community

Cover image for AWS IAM Deep Dive โ€” Roles, Policies, Groups, EC2 & Everything in Between
Tejas Shinkar
Tejas Shinkar

Posted on • Edited on

AWS IAM Deep Dive โ€” Roles, Policies, Groups, EC2 & Everything in Between

๐Ÿ” 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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/*"
  }]
}
Enter fullscreen mode Exit fullscreen mode
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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. Permission Policy โ€” what the role is allowed to do
  2. 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"
  }]
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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 (.pem file)
  • You use .pem to 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
Enter fullscreen mode Exit fullscreen mode

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!" โœ…
Enter fullscreen mode Exit fullscreen mode

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 Principal field 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 Principal field โ€” 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/*"
  }]
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

  1. Create an IAM Group called DevOpsTeam, attach PowerUserAccess, create a user and add them to the group. Log in as that user and verify you can access EC2 but not billing.
  2. 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.
  3. Launch an EC2 instance with a User Data script that installs Apache. Access the public IP in your browser and confirm the webpage loads.
  4. 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.
  5. Open AmazonEC2FullAccess policy JSON in the IAM Console. Find what ec2:* 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)