Skip to main content

AWS IAM Basics: Users, Roles, and Policies

Tags:

Secure access management is essential for running AWS safely. AWS IAM (Identity and Access Management) is a service that lets you control exactly who can access what. Let's cover the core IAM concepts and how to use them in practice.

What is AWS IAM?

IAM is a service for securely managing access to AWS resources. With IAM, you can configure precisely "what each user or service is allowed to do" within your AWS account.

For example, you can restrict a user to read-only access to S3, or allow an EC2 instance to write only to a specific S3 bucket. IAM is the foundation of AWS security — setting it up correctly significantly reduces the risk of unauthorized access and data breaches.

Key IAM Components

IAM has four main components. Each one plays a role in determining who can access what and how.

ComponentDescriptionCommon Use
UserAn individual identity for signing in to AWS. Authenticates with a password or access keys.Console logins, CLI access
GroupA collection of IAM users. Attach policies to a group to manage permissions for all members at once.Role-based access for "developers," "ops team," etc.
RoleAn identity without passwords or access keys that issues temporary credentials. Assumed by AWS services or external identities.Granting permissions to EC2, Lambda, and other AWS services
PolicyA JSON document that defines permissions. Attached to users, groups, or roles.Read-only access to a specific service, admin access across all services, etc.

For humans, create IAM users. For applications and AWS services, use IAM roles. Roles don't have access keys, which eliminates the risk of key leakage and makes them more secure.

Security Best Practices

Here are the key practices for running IAM securely. Permission design mistakes can lead to data breaches or unintended resource changes, so it's important to get this right from the start.

PracticeDetailsWhy
Don't use the root userUse IAM users for day-to-day work. Reserve the root user for account-level operations only.The root user has full permissions — a compromise has maximum impact.
Principle of least privilegeAvoid overly broad permissions like "Action": "*". Grant only the actions that are actually needed.Unnecessary permissions expand the attack surface for mistakes and attackers.
Enable MFASet up multi-factor authentication for console logins. Required for users with admin access.Even if a password is leaked, MFA prevents unauthorized login.

Trying IAM with the AWS CLI

Let's create an IAM role and use sts assume-role to assume it from an IAM user, then verify what's allowed and what's denied. Note that calling sts assume-role itself requires authentication via an IAM user's access keys.

Creating an IAM Role and Attaching a Policy

An IAM role requires a file that defines "who can use this role." Specify your own AWS account ID in the Principal.AWS field. In this example, any user in the same AWS account can assume the role.

cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole"
}
]
}
EOF

Create the role using this trust policy file:

❯ aws iam create-role \
--role-name exrecord-s3-readonly-role \
--assume-role-policy-document file://trust-policy.json
{
"Role": {
"Path": "/",
"RoleName": "exrecord-s3-readonly-role",
"RoleId": "AROA0a1b2c3d4e5f67890",
"Arn": "arn:aws:iam::123456789012:role/exrecord-s3-readonly-role",
"CreateDate": "2026-04-15T09:47:12+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole"
}
]
}
}
}

Attach the AWS managed policy AmazonS3ReadOnlyAccess to grant read-only access to S3:

❯ aws iam attach-role-policy \
--role-name exrecord-s3-readonly-role \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

Assuming the Role and Getting Temporary Credentials

Use sts assume-role to assume the role and set the temporary credentials as environment variables. These credentials expire after 1 hour by default.

❯ aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/exrecord-s3-readonly-role \
--role-session-name test-session
{
"Credentials": {
"AccessKeyId": "ASIA0a1b2c3d4e5f67890",
"SecretAccessKey": "0a1b2c3d4e5f67890",
"SessionToken": "AQoDYXdzEJr...",
"Expiration": "2026-04-15T10:48:56+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "AROA0a1b2c3d4e5f67890:test-session",
"Arn": "arn:aws:sts::123456789012:assumed-role/exrecord-s3-readonly-role/test-session"
}
}

Set the Credentials values as environment variables. All subsequent CLI commands will run under the role's permissions.

export AWS_ACCESS_KEY_ID=ASIA0a1b2c3d4e5f67890
export AWS_SECRET_ACCESS_KEY=0a1b2c3d4e5f67890
export AWS_SESSION_TOKEN=AQoDYXdzEJr...

Allowed Operation: Reading from S3

Since AmazonS3ReadOnlyAccess is attached, listing buckets succeeds:

❯ aws s3 ls
2026-04-15 18:57:05 exrecord-test-bucket

Denied Operation: Writing to S3

Read-only access is allowed, so uploading a file results in an AccessDenied error:

❯ aws s3 cp test.txt s3://exrecord-test-bucket
upload failed: ./test.txt to s3://exrecord-test-bucket/test.txt An error occurred (AccessDenied) when calling the PutObject operation: User: arn:aws:sts::123456789012:assumed-role/exrecord-s3-readonly-role/test-session is not authorized to perform: s3:PutObject on resource: "arn:aws:s3:::exrecord-test-bucket/test.txt" because no identity-based policy allows the s3:PutObject action

Denied Operation: Accessing EC2

No EC2 permissions were granted, so listing instances also fails:

❯ aws ec2 describe-instances

aws: [ERROR]: An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation. User: arn:aws:sts::123456789012:assumed-role/exrecord-s3-readonly-role/test-session is not authorized to perform: ec2:DescribeInstances because no identity-based policy allows the ec2:DescribeInstances action

This clearly shows how IAM policies separate what you can do from what you can't. Following the principle of least privilege is an effective way to prevent unintended operations.

Using IAM in Production

The approach above requires you to manually run sts assume-role and set environment variables each time, which is tedious in practice. For production, AWS IAM Identity Center (formerly AWS SSO) is the recommended approach.

With IAM Identity Center, a single command triggers a browser-based login and automatically issues and refreshes temporary credentials:

❯ aws sso login --profile my-profile

After that, just use --profile my-profile — no manual assume-role or environment variable setup needed.

Summary

We covered the core concepts and usage of AWS IAM. IAM is the backbone of AWS security. Keep these points in mind to build a secure AWS environment:

  • Understand the roles of users, groups, roles, and policies — use IAM users for humans, IAM roles for AWS services
  • Follow the principle of least privilege and grant only the permissions actually needed
  • Don't use the root user for day-to-day work, and enable MFA
  • In production, use IAM Identity Center to automate credential management