Complete guide to AWS IAM — Understanding users, groups, policies, roles, and how they work together to secure your AWS account.


IAM Components Explained

IAM Core Concepts (Users, Groups, Policies, Roles)

flowchart LR
    Root["🔒 Root User<br/>(account owner)"]

    subgraph IAM["IAM Building Blocks"]
        U["👤 Users"]
        G["👥 Groups"]
        R["🎭 Roles"]
        P["📋 Policies"]
    end

    U -->|"member of"| G
    P -->|"attached to"| U
    P -->|"attached to"| G
    P -->|"attached to"| R

    U -->|"assume role (STS)"| R
    F["🌐 Federated Identities<br/>(Identity Center/SAML/OIDC)"] -->|"assume role"| R
    S["⚙️ AWS Services<br/>(EC2/Lambda/etc.)"] -->|"assume service role"| R

    Root -.->|"break-glass only"| IAM

In practice:

  • Users represent individual IAM identities (long-term credentials if needed).
  • Groups organize users so you assign permissions once to many users.
  • Policies are permission documents attached to users, groups, or roles.
  • Roles provide temporary credentials and are the preferred pattern for services, federation, and cross-account access.

1. Root User

What It Is

The root user is the account owner identity created when you first sign up for AWS.

Characteristics

AttributeValue
LoginEmail address used during signup
AccessComplete, unrestricted access to ALL resources and settings
PermissionsNot governed by IAM identity policies (organization guardrails can still apply)
Best PracticeLock away; use only for emergencies

Root User Responsibilities

Only the root user can perform these actions:

  • Change AWS account settings
  • Close the AWS account
  • Change the root password
  • Retrieve root account security credentials
  • Enable MFA Delete for S3

Critical Security Practice: Enable MFA on your root account immediately and never use it for daily operations.


2. IAM Users

What They Are

IAM users represent individuals or applications that need to interact with AWS resources.

User Credentials

Credential TypePurposeWhere It’s Used
Console PasswordSign in to AWS Management ConsoleBrowser-based access
Access Key ID + SecretProgrammatic access to AWS APIsCLI, SDKs, scripts
MFA DeviceAdditional security layerOptional but recommended

Creating a User

# AWS CLI example
aws iam create-user --user-name john-developer
aws iam create-login-profile --user-name john-developer --password TempPassword123!
aws iam create-access-key --user-name john-developer

User States

StateDescription
ActiveUser can sign in and make API calls
InactiveUser exists but cannot access (password/access keys disabled)

Best Practices for Users

  1. One user per person — No shared accounts
  2. Force password reset on first login — For console access
  3. Enable MFA — Required for security best practices
  4. Set password policy — Enforce complexity and rotation
  5. Don’t embed access keys — Use IAM roles for applications

3. IAM Groups

What They Are

Groups are collections of IAM users that share the same permissions.

Key Characteristics

CharacteristicDetail
NestingGroups cannot contain other groups — only users
MembershipA user can belong to multiple groups
PermissionsAttached as policies (managed or inline)
SimplificationManage permissions at group level, not per user

Why Use Groups?

Without Groups (Chaotic):

❌ Each user needs policies assigned individually

flowchart TB
    U1["User 1"] --> PA1["Policy A"]
    U1 --> PB1["Policy B"]
    U2["User 2"] --> PA2["Policy A"]
    U2 --> PB2["Policy B"]
    U3["User 3"] --> PA3["Policy A"]
    U3 --> PB3["Policy B"]

With Groups (Organized):

flowchart TB
    subgraph Organized["✅ Group-Based Management"]
        G["👥 Developers Group<br/>Policies: A + B"]
        G --> U1["User 1"]
        G --> U2["User 2"]
        G --> U3["User 3"]
    end

Common Group Patterns

Group NamePermissionsTypical Members
AdministratorsAdministratorAccessDevOps engineers, Sysadmins
DevelopersPowerUserAccess + customSoftware developers
ReadOnlyReadOnlyAccessBusiness analysts, auditors
SupportLimited specific permissionsSupport staff

4. IAM Policies

What They Are

Policies are JSON documents that define permissions.

Policy Structure

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "OptionalIdentifier",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": ["192.0.2.0/24", "203.0.113.0/24"]
        }
      }
    }
  ]
}

Policy Elements Explained

ElementRequiredDescriptionExamples
VersionYesPolicy syntax versionAlways "2012-10-17"
StatementYesContainer for policy rulesArray of statement objects
SidNoStatement identifier (optional)"AllowS3Read"
EffectYesAllow or Deny"Allow" or "Deny"
ActionYesSpecific AWS API calls"s3:GetObject" or "s3:*"
ResourceYes*Target AWS resources"arn:aws:s3:::bucket/*"
ConditionNoOptional constraintsIP address, time, tags

* Policy statements must include Resource or NotResource.
* For actions that do not support resource-level permissions (such as iam:ChangePassword), use Resource: "*" in the statement.

Action Syntax

PatternMeaningExample
service:actionSpecific actions3:GetObject
service:*All actions in services3:*
*All AWS actions* (admin access)

Resource ARN Format

arn:partition:service:region:account-id:resource
PartExampleDescription
partitionawsStandard AWS partition
services3The AWS service
regionus-east-1Region (optional for some services)
account-id12345678901212-digit AWS account ID
resourcebucket-name/object-keySpecific resource identifier

Common Wildcards and Condition Operators

TypeDescriptionExample
* (wildcard)Matches multiple characters in action/resource patternss3:* or arn:aws:s3:::*
? (wildcard)Matches a single character in patternsuser:? matches user:a
StringEqualsString equality match in ConditionRestrict to a specific VPC endpoint ID
ArnLikePattern match for ARNs in ConditionRestrict assumed roles by ARN pattern
Bool / BoolIfExistsBoolean condition checksRequire MFA with aws:MultiFactorAuthPresent

Managed vs Inline Policies

AspectManaged PoliciesInline Policies
LocationStandalone entityEmbedded in user/group/role
ReusabilityCan attach to multiple entitiesOnly for one entity
VersioningSupportedNot supported
AWS-ManagedAvailable (pre-built by AWS)Not available
Customer-ManagedAvailableAvailable
Best ForReusable permission setsEntity-specific permissions

AWS Managed Policies (Examples)

Policy NameDescriptionUse With
AdministratorAccessFull access to all AWS servicesTrusted administrators
PowerUserAccessAll permissions except IAM managementDevelopers who don’t manage users
ReadOnlyAccessRead-only access to all AWS servicesAuditors, analysts
SecurityAuditRead access commonly used for security reviewSecurity and audit teams

5. IAM Roles

What They Are

Roles are identities with temporary credentials that you assume when needed.

Why Use Roles Instead of Users?

ScenarioUse Role Because…
EC2 accessing S3No need to manage/rotate long-term access keys
Lambda accessing DynamoDBAutomatic credential rotation
Cross-account accessNo need to create users in other accounts
Federated accessExternal users get temporary credentials
Service-to-serviceAWS services need permissions to act on your behalf

Trust Policy (Who Can Assume the Role)

{
  "Effect": "Allow",
  "Principal": {
    "Service": "ec2.amazonaws.com"
  },
  "Action": "sts:AssumeRole"
}

Permission Policy (What the Role Can Do)

{
  "Effect": "Allow",
  "Action": [
    "s3:GetObject",
    "s3:PutObject"
  ],
  "Resource": "arn:aws:s3:::my-app-bucket/*"
}

Common Role Use Cases

1. EC2 Instance Profile

# Create role with trust policy for EC2
aws iam create-role \
  --role-name MyEC2Role \
  --assume-role-policy-document file://trust-policy.json
 
# Attach permissions
aws iam attach-role-policy \
  --role-name MyEC2Role \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
 
# Create instance profile
aws iam create-instance-profile --instance-profile-name MyEC2Profile
 
# Add role to instance profile
aws iam add-role-to-instance-profile \
  --instance-profile-name MyEC2Profile \
  --role-name MyEC2Role
 
# Attach to EC2 instance
aws ec2 associate-iam-instance-profile \
  --instance-id i-1234567890abcdef0 \
  --iam-instance-profile Name=MyEC2Profile

2. Cross-Account Access

Account A (123456789012)Account B (987654321098)

flowchart LR
    Bob["👤 User Bob"] -->|"Assume Role"| Role["🎭 Role"]
    Role --> Resources["📦 Resources"]

Account A (User’s Policy):

{
  "Effect": "Allow",
  "Action": "sts:AssumeRole",
  "Resource": "arn:aws:iam::987654321098:role/CrossAccountRole"
}

Account B (Role’s Trust Policy):

{
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::123456789012:root"
  },
  "Action": "sts:AssumeRole"
}

3. Service-Linked Roles

  • Automatically created by AWS services
  • Pre-defined permissions required by the service
  • No need to manually manage

Examples:

  • AWSServiceRoleForOrganizations — AWS Organizations
  • AWSServiceRoleForTrustedAdvisor — Trusted Advisor
  • AWSServiceRoleForConfig — AWS Config

IAM Policy Evaluation Logic

The Decision Flow

flowchart TD
    Request["📨 Request Arrives"] --> Default["1️⃣ Default DENY<br/>(implicit deny)"]
    Default --> CheckDeny["2️⃣ Check for explicit DENY<br/>in all applicable policies"]
    CheckDeny --> DenyFound{Deny found?}
    DenyFound -->|Yes| Deny1["❌ DENY"]
    DenyFound -->|No| CheckAllow["3️⃣ Check for explicit ALLOW<br/>in all applicable policies"]
    CheckAllow --> AllowFound{Allow found?}
    AllowFound -->|Yes| Allow["✅ ALLOW"]
    AllowFound -->|No| Deny2["❌ DENY<br/>(implicit deny)"]

Policy Sources Checked

SourceTypeScope
Identity-based policiesAttached to user/group/roleWhat this identity can do
Resource-based policiesAttached to AWS resourceWho can access this resource
IAM Permissions BoundariesMaximum permissions for an entityCannot exceed this boundary
SCPAWS OrganizationsOrganization-level restrictions
Session PoliciesPassed when assuming roleTemporary restriction during session

Explicit Deny Always Wins

Policy A: Allow S3 read
Policy B: Allow S3 write
Policy C: Deny S3 delete
Policy D: Allow S3 delete

Result: User can read and write S3, but CANNOT delete
      (Explicit Deny in Policy C overrides Allow in D)

Common IAM Scenarios

Scenario 1: Developer Needs Full EC2, Read-Only RDS

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:*",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "rds:Describe*",
        "rds:List*"
      ],
      "Resource": "*"
    }
  ]
}

Scenario 2: Limit S3 Access to Specific Bucket

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::my-app-bucket"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::my-app-bucket/*"
    }
  ]
}

Scenario 3: Require MFA for Sensitive Operations

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAllUsers",
      "Effect": "Allow",
      "Action": ["iam:ChangePassword", "iam:GetAccountPasswordPolicy"],
      "Resource": "*"
    },
    {
      "Sid": "AllowViewAccountInfo",
      "Effect": "Allow",
      "Action": [
        "iam:GetAccountSummary",
        "iam:ListVirtualMFADevices"
      ],
      "Resource": "*"
    },
    {
      "Sid": "RequireMFAForSensitive",
      "Effect": "Deny",
      "NotAction": [
        "iam:ChangePassword",
        "iam:GetAccountPasswordPolicy"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}

IAM Security Best Practices

PracticeImplementation
Enable MFA on rootConsole → IAM → Security credentials → Activate MFA
Delete root access keysNever use root credentials programmatically
Individual IAM usersCreate user for each person; no shared accounts
Use groups for permissionsAttach policies to groups, not individual users
Least privilegeGrant only minimum required permissions
Rotate credentialsSet password policy; rotate access keys regularly
Use roles for appsNever hardcode access keys; use IAM roles
Enable CloudTrailLog all IAM API calls for auditing
Review access regularlyUse IAM Access Analyzer to find unintended access
Set password policyEnforce complexity, expiration, history

IAM Limits and Quotas

ResourceDefault Limit
IAM users per account5,000
IAM groups per account500
IAM roles per account1,000
Managed policies per account1,500
Inline policies per entityLimited by size (2,048 characters for users, 10,240 for roles)
User groups per user10
Policies per group10
Access keys per user2

TL;DR

  • Root User = Account owner, lock away with MFA, never use daily
  • IAM Users = Individual identities for people/apps with credentials
  • IAM Groups = Collections of users with shared permissions (simplifies management)
  • Policies = JSON documents defining permissions (Effect, Action, Resource, Condition)
  • Roles = Temporary credentials for services, cross-account, federation
  • Managed Policies = Reusable, versioned; Inline Policies = Entity-specific
  • Evaluation Logic: Default Deny → Check Allow → Check Deny (Deny always wins)
  • Best Practices: MFA everywhere, least privilege, groups for permissions, roles for apps

Resources

IAM User Guide Comprehensive IAM documentation.

IAM Policy Elements Reference Detailed policy syntax and options.

IAM Policy Examples Common policy patterns by use case.

IAM Best Practices Official AWS security recommendations.

IAM Access Analyzer Tool to verify that your resources grant only intended access.