What Is AWS IAM?
The Root Account Problem
When you create an AWS account, you get a root user — an account with unlimited power over every AWS resource. Using root for day-to-day work is dangerous:
- If root credentials are compromised, everything is compromised
- You can't limit what root can do
- Root actions can't be restricted by any policy
The first thing to do with a new AWS account: enable MFA on root, then never use root again. Create an IAM user or role for everything else.
Core Components
IAM User
A user is an identity for a human or application that needs long-term credentials (username + password for the console, or access key + secret for the CLI/SDK).
Create users for team members. Each gets their own credentials and only the permissions they need.
IAM Group
A group is a collection of users. Attach policies to groups rather than individual users — when someone joins the team, add them to the group; when they leave, remove them.
Group: Developers
→ Policy: AmazonS3ReadOnlyAccess
→ Policy: AmazonRDSReadOnlyAccess
Users in group: alice, bob, carol
IAM Role
A role is an identity without long-term credentials. It's assumed temporarily by:
- AWS services — an EC2 instance assuming a role to read from S3
- Lambda functions — a function assuming a role to write to DynamoDB
- Other AWS accounts — cross-account access
- Identity providers — federated access from GitHub Actions, Google, etc.
Roles are the preferred way to give AWS services permissions — no credentials to manage, rotate, or accidentally expose.
IAM Policy
A policy is a JSON document defining what's allowed or denied. It's attached to users, groups, or roles.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-app-uploads/*"
}
]
}
This policy allows reading and writing objects in a specific S3 bucket — nothing else.
Principle of Least Privilege
Every user and role should have only the permissions they actually need — nothing more. This limits the blast radius if credentials are compromised.
In practice:
- Never attach
AdministratorAccessto application roles - Use resource-specific ARNs (
arn:aws:s3:::my-bucket/*) rather than*where possible - Review and remove unused permissions regularly
- Use IAM Access Analyzer to detect overly broad policies
Access Keys vs. IAM Roles
| Access Keys | IAM Role | |
|---|---|---|
| Use case | CLI on local machine, CI/CD | EC2, Lambda, ECS tasks |
| Credentials | Long-lived (until rotated) | Temporary (15 min – 12 hours) |
| Risk if leaked | High — valid until manually rotated | Low — expires automatically |
| Management | Manual rotation required | Automatic |
Rule: Never put access keys on a server. Assign an IAM role to the EC2 instance instead.
Assigning a Role to EC2
In the EC2 console → Instance → Actions → Security → Modify IAM role. Select or create an instance profile with the permissions your app needs.
Your app running on that instance can then call AWS APIs without any credentials in the code:
// The SDK automatically uses the instance's IAM role — no keys needed
import { S3Client } from "@aws-sdk/client-s3";
const s3 = new S3Client({ region: "us-east-1" });
Common Managed Policies
AWS provides hundreds of pre-built policies. Commonly used ones:
| Policy | Grants |
|---|---|
AmazonS3ReadOnlyAccess | Read any S3 bucket |
AmazonS3FullAccess | Full S3 access |
AmazonRDSReadOnlyAccess | Read RDS metadata |
CloudWatchLogsFullAccess | Write and read CloudWatch logs |
AWSLambda_FullAccess | Manage Lambda functions |
AdministratorAccess | Full account access — use sparingly |