AWS IAM — Identity and Access Management

AWS-IAM

Users, groups, roles, and policies — how AWS controls who can do what to which resources.

awsiamsecurityrolespoliciesidentity

Overview

AWS Identity and Access Management (IAM) is the global service that controls authentication and authorization for every API call made to AWS. When an EC2 instance uploads a file to S3, when a developer runs aws ec2 describe-instances, when a Lambda function reads a secret from Secrets Manager — every one of those actions passes through IAM before it reaches the target service.

IAM is not an optional security layer placed in front of AWS. It is woven into the AWS control plane itself. Understanding IAM means understanding how AWS actually works: every resource interaction is an API call with an identity, and IAM is the engine that decides whether that call is permitted.

IAM is global — it is not region-specific. Users, groups, roles, and policies created in IAM are available across all regions.


The Root Account

When you create an AWS account, the email address and password you used create the root user. The root user has unrestricted access to every service and resource in the account. It bypasses IAM entirely — no policy can deny the root user.

Root user capabilities that cannot be delegated to any other identity include:

The operational rule is absolute: do not use the root account for daily tasks. After creating the account:

  1. Enable MFA on the root user (hardware MFA key if possible)
  2. Create an IAM user or IAM Identity Center user with administrative access
  3. Use that identity for all subsequent work
  4. Store root credentials in a sealed vault and audit access to them

The only time you use root is for the handful of operations that literally require it.


IAM Users

An IAM user is a persistent identity that represents a person or an application. Users have long-term credentials — unlike roles, which provide temporary credentials, users hold credentials that do not expire unless you rotate them.

Credential Types

CredentialUsed ForNotes
Console passwordAWS Management Console (browser)Optionally enforced by a password policy
Access key ID + Secret access keyAWS CLI, SDKs, direct API callsNever embed in code; rotate regularly; prefer roles
MFA deviceAdditional authentication factorVirtual (TOTP app), hardware token, or FIDO2/WebAuthn

When to Use IAM Users

The use case for IAM users has narrowed significantly with the introduction of IAM Identity Center. The current guidance:

One IAM user per person is the minimum. Sharing credentials between people is prohibited because it destroys audit traceability — CloudTrail logs show which IAM user made every API call.


Groups

An IAM group is a collection of IAM users. Policies attached to a group are inherited by all users in that group. Groups cannot contain other groups — they are flat.

Groups exist purely to simplify permission management. Instead of attaching the same policy to 40 individual users, you attach it to one group. When a new user joins the team, you add them to the group and they immediately have the correct permissions.

Common group structures:

A user can belong to multiple groups and inherits the union of all policies attached to each group.


Roles

An IAM role is an identity that does not belong to a person — it is assumed temporarily by an entity that needs it. Roles provide short-lived credentials issued by AWS Security Token Service (STS).

When an entity assumes a role, STS returns:

After expiration, the credentials are worthless. There are no long-term secrets to rotate, leak, or compromise — the credentials self-destruct.

Role Use Cases

ScenarioHow Roles Apply
EC2 instance accessing S3Attach an IAM role as an instance profile. The EC2 metadata service vends credentials automatically; the SDK picks them up without any credential configuration.
Lambda functionEvery Lambda has an execution role. Defines what the function can do — read from DynamoDB, publish to SNS, write to CloudWatch Logs.
Cross-account accessAccount A has a role that Account B can assume. Account B’s principals call sts:AssumeRole with the role ARN from Account A. Useful for shared services or centralized tooling accounts.
Federated identity (SAML)Corporate IdP authenticates the user, then calls sts:AssumeRoleWithSAML. The user gets AWS credentials scoped to a role without an IAM user existing.
OIDC federationGitHub Actions, CircleCI, or any OIDC-compatible provider can exchange a JWT for AWS credentials via sts:AssumeRoleWithWebIdentity. No stored AWS credentials in CI/CD systems.

Trust Policy

Every role has a trust policy — a JSON document that defines who is allowed to call sts:AssumeRole on that role. This is separate from the permissions policies. The trust policy answers “who can use this role?” and the attached permissions policies answer “what can this role do?”.


Policies

IAM policies are JSON documents that define permissions. Every policy contains one or more statements, each with:

Example policy allowing read-only access to a specific S3 bucket:

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

Policy Types

TypeManaged ByReusableBest For
AWS ManagedAWSYesCommon use cases (ReadOnly, PowerUser, AdministratorAccess). AWS updates them when services change.
Customer ManagedYouYesCustom permission sets tailored to your application or team. Attach to multiple users, groups, or roles. Version-controlled.
InlineEmbedded in identityNoAvoid. Tightly coupled to a single user/group/role. Hard to audit and reuse. Use only when strict 1:1 binding is genuinely required.
Resource-basedAttached to resourceN/AS3 bucket policies, KMS key policies, SQS queue policies. Define who can access the resource from outside the account.
Service Control Policies (SCPs)AWS OrganizationsN/AAccount-level guardrails applied to an entire account or OU. Restrict what can be allowed even for administrators.
Permission BoundariesYouYesMax permission cap for a user or role. Used when delegating permission management — a junior admin can only grant permissions up to what their boundary allows.

Policy Evaluation Logic

When an API call is made, IAM evaluates multiple policy types in a specific order. Understanding this order prevents common “access denied” debugging confusion.

API Call
IAM Evaluator
Request arrives
Principal, Action, Resource, Context
Step 1: Explicit Deny in any policy?
Any Deny wins immediately — DENIED
Step 2: SCP allows?
If in an AWS Org: SCP must permit the action — else DENIED
Step 3: Resource-based policy allows?
Cross-account: resource policy must Allow principal
Step 4: Permission boundary allows?
If boundary set: action must be within boundary — else DENIED
Step 5: Session policy allows?
If assumed role with session policy: must Allow
Step 6: Identity policy allows?
User/group/role policy must have Allow — else DENIED
All checks passed
ALLOWED — request proceeds to service

The hierarchy in plain terms:

  1. Explicit Deny always wins. A single Deny statement anywhere in any applicable policy blocks the action, regardless of Allows elsewhere.
  2. SCPs act as a ceiling. Even an administrator cannot perform an action that the SCP prohibits for their account.
  3. Implicit Deny is the default. If no policy explicitly Allows an action, it is denied. There is no “allow by default” in IAM — everything starts as denied.

Common Gotcha: Cross-Account Access

Within the same account, an identity policy Allow is sufficient. Across accounts, both the identity policy in the calling account AND a resource-based policy (or role trust policy) in the target account must Allow the access. One side alone is not enough.


Permission Boundaries

A permission boundary is an advanced IAM feature that sets the maximum permissions an identity can have, regardless of what policies are attached to it.

Suppose you want to let a team manage their own IAM roles (for their application’s Lambda functions) without being able to grant themselves or others administrator access. You:

  1. Create a permission boundary policy defining the maximum allowed actions (e.g., only EC2, S3, Lambda, DynamoDB for specific resource prefixes)
  2. Require that any role they create must have this permission boundary attached
  3. Use an SCP or IAM condition to enforce this requirement

Now the team can create roles, but any role they create is capped at the boundary’s permissions — even if they accidentally (or intentionally) attach the AdministratorAccess managed policy to it.


IAM Identity Center (SSO)

IAM Identity Center (formerly AWS Single Sign-On) is the recommended way to manage human access to multiple AWS accounts and applications. Instead of creating IAM users in every account, you create users once in Identity Center and assign them access across the organization.

How It Works

  1. Identity source: Identity Center maintains a user directory, or you connect an external IdP — Azure AD, Okta, Ping, Google Workspace — via SCIM (for automatic user provisioning) and SAML 2.0 (for authentication).
  2. Permission sets: Define what access a user gets in an account. A permission set bundles IAM policies (AWS managed or customer managed) and maps to a role in the target account.
  3. Account assignments: Assign a user or group to an account + permission set combination. Identity Center creates an IAM role in that account automatically.
  4. SSO login: Users go to the Identity Center portal, authenticate via their IdP, see all their assigned accounts, and click to generate temporary credentials — either for console access or downloaded as CLI credentials.
FeatureIAM UsersIAM Identity Center
Credential lifetimeLong-term (keys don’t expire)Short-term (hours, auto-renewed)
Multi-account managementManual per accountCentralized
MFAPer-user configurationCentralized policy
External IdP integrationManual federation per accountNative SCIM + SAML
Audit trailPer-account CloudTrailCentralized CloudTrail + Identity Center events
ScalabilityPoor (N users × M accounts)Excellent

IAM Best Practices

PracticeRationale
Enable MFA on the root account and all privileged usersCredential theft is the most common initial access vector. MFA neutralizes stolen passwords.
Use roles for services, not access keysInstance profiles, execution roles, and OIDC federation eliminate long-term credentials from services. No credential to rotate or leak.
Grant least privilegeStart with no permissions. Add only what is needed. Use IAM Access Analyzer to identify unused permissions and tighten policies over time.
Rotate access keysAny access key that exists should be rotated every 90 days at maximum. Use IAM credentials reports to audit key age.
Never use the root accountRoot has no policy guardrails. One compromised root session means total account compromise.
Audit with CloudTrail and IAM Access AnalyzerCloudTrail logs every API call. Access Analyzer identifies roles and policies with external access. Run both continuously.
Use SCPs for organization-wide guardrailsSCPs prevent even account administrators from performing actions you want to prohibit globally — creating IAM users, disabling CloudTrail, leaving the organization.
Apply permission boundaries when delegating IAM managementPrevent privilege escalation when junior roles need to create IAM identities.
Prefer customer managed policies over inlineCustomer managed policies are auditable, reusable, and version-controlled. Inline policies are invisible in policy listings and easy to forget.

Conditions in Policies

Conditions make policies context-aware. They allow or deny based on request attributes beyond just identity, action, and resource.

Common condition keys:

Condition KeyExample Use
aws:SourceIpRestrict API calls to your corporate IP ranges
aws:MultiFactorAuthPresentRequire MFA before sensitive actions (deleting S3 buckets, modifying IAM)
aws:RequestedRegionPrevent resource creation outside approved regions
aws:CurrentTimeAllow access only during business hours
s3:prefixRestrict S3 access to a specific path prefix
ec2:ResourceTag/EnvironmentAllow actions only on resources tagged with Environment: dev
iam:PassedToServiceControl which services a role can be passed to

Tag-based conditions are particularly powerful: if you enforce resource tagging through SCPs and use tag conditions in policies, you can automatically scope access to resources owned by a team without maintaining per-resource ARN lists.


IAM Access Analyzer

IAM Access Analyzer continuously analyzes IAM resource policies, S3 bucket policies, KMS key policies, SQS queue policies, and Lambda function policies to identify resources that are accessible from outside your account or organization.

It generates findings for any resource that grants external access — intended or not. For each finding you either:

Access Analyzer also includes a policy validation feature that checks your policy JSON against IAM best practices before you apply it, and a policy generation feature that builds a least-privilege policy from CloudTrail events showing what an identity actually did over a time window.