Skip to main content

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 AdministratorAccess to 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 KeysIAM Role
Use caseCLI on local machine, CI/CDEC2, Lambda, ECS tasks
CredentialsLong-lived (until rotated)Temporary (15 min – 12 hours)
Risk if leakedHigh — valid until manually rotatedLow — expires automatically
ManagementManual rotation requiredAutomatic

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:

PolicyGrants
AmazonS3ReadOnlyAccessRead any S3 bucket
AmazonS3FullAccessFull S3 access
AmazonRDSReadOnlyAccessRead RDS metadata
CloudWatchLogsFullAccessWrite and read CloudWatch logs
AWSLambda_FullAccessManage Lambda functions
AdministratorAccessFull account access — use sparingly