Identity & SecurityIntermediate18 min read

    AWS IAM Security Best Practices

    Tarek Cheikh

    Founder & AWS Security Expert

    View Security Card

    AWS Identity and Access Management (IAM) is the gatekeeper of your entire cloud environment. Every API call, every console login, every service interaction flows through IAM. If IAM is misconfigured, nothing else you do matters -- an attacker with the right credentials and overly broad permissions can access, modify, or delete any resource in your account in minutes.

    According to the 2025 Verizon DBIR, compromised credentials remain among the leading causes of data breaches. In November 2025, attackers used compromised admin-like IAM credentials to deploy crypto miners across an AWS environment in under 10 minutes, leveraging Lambda functions and new IAM users for persistence. Getting IAM right is the single highest-impact security investment you can make.

    This guide covers 12 battle-tested IAM best practices, each with real AWS CLI commands, audit procedures, and the latest 2025-2026 updates from AWS.

    1. Eliminate Root Account Usage

    The root account has unrestricted access to all AWS resources, billing, and account closure. It bypasses all IAM policies and SCPs. A compromised root account is a total account takeover.

    Implementation

    • Delete all root access keys. Root should never have programmatic access.
    • Enable hardware MFA (FIDO2/passkey). AWS now recommends phishing-resistant passkeys over TOTP for root. Store a backup key in a physical safe.
    • Lock root away. Use it only for the handful of tasks that require it (account closure, certain billing actions).
    # Check for root access keys (should return empty)
    aws iam generate-credential-report
    aws iam get-credential-report --query "Content" --output text | base64 -d | head -2
    
    # Verify root MFA status from the credential report
    # Look for: mfa_active = true, access_key_1_active = false

    CIS Benchmark: Control 1.4 (no root access keys), Control 1.5 (root MFA enabled), Control 1.6 (hardware MFA for root).

    2. Enforce Multi-Factor Authentication Universally

    Credentials alone are insufficient. The November 2025 crypto mining campaign demonstrated that compromised IAM credentials without MFA enabled allowed attackers to deploy miners within 10 minutes of initial access.

    MFA Enforcement Policy

    Attach this policy to all IAM users. It denies every action except MFA self-management until the user configures MFA:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "DenyAllExceptSelfManageWithoutMFA",
          "Effect": "Deny",
          "NotAction": [
            "iam:CreateVirtualMFADevice",
            "iam:EnableMFADevice",
            "iam:GetUser",
            "iam:ListMFADevices",
            "iam:ListVirtualMFADevices",
            "iam:ResyncMFADevice",
            "sts:GetSessionToken"
          ],
          "Resource": "*",
          "Condition": {
            "BoolIfExists": {
              "aws:MultiFactorAuthPresent": "false"
            }
          }
        }
      ]
    }

    Require MFA for Role Assumption

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::123456789012:root"},
        "Action": "sts:AssumeRole",
        "Condition": {
          "Bool": {"aws:MultiFactorAuthPresent": "true"}
        }
      }]
    }

    Audit

    # Generate credential report and check for users without MFA
    aws iam generate-credential-report
    aws iam get-credential-report --query "Content" --output text | base64 -d > report.csv
    # Parse CSV: look for rows where mfa_active = false and password_enabled = true

    2025-2026 Update: AWS now supports passkeys (FIDO2 WebAuthn) as a phishing-resistant MFA option. CIS Benchmark v5.0 explicitly recommends passkeys or hardware security keys over TOTP authenticator apps.

    3. Adopt IAM Identity Center (Replace IAM Users)

    IAM users use long-lived credentials (passwords and access keys) that never automatically expire and are easily leaked. Multiple industry articles in late 2025 and early 2026 declare "IAM users are dead" for human access.

    IAM Identity Center provides:

    • Temporary credentials that rotate with each sign-in session
    • Centralized management across multiple AWS accounts
    • Single sign-on with external identity providers (Okta, Azure AD, etc.)
    • Permission sets that map to IAM roles automatically
    # Create a permission set
    aws sso-admin create-permission-set   --instance-arn arn:aws:sso:::instance/ssoins-EXAMPLE   --name "ReadOnlyAccess"   --session-duration "PT8H"
    
    # Attach an AWS managed policy to the permission set
    aws sso-admin attach-managed-policy-to-permission-set   --instance-arn arn:aws:sso:::instance/ssoins-EXAMPLE   --permission-set-arn arn:aws:sso:::permissionSet/ssoins-EXAMPLE/ps-EXAMPLE   --managed-policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

    Migration strategy: Enable Identity Center alongside existing IAM users. Create equivalent permission sets for your IAM groups. Migrate users in phases, then decommission IAM users.

    4. Implement Least Privilege with IAM Access Analyzer

    Overly permissive policies increase the blast radius of any credential compromise. IAM Access Analyzer combines external access detection and unused access analysis into a single tool.

    Three Types of Findings

    • External access: Resources shared with principals outside your account or organization
    • Unused roles: Roles with no access activity in the specified window
    • Unused permissions: Service-level and action-level permissions not exercised
    # Create an external access analyzer
    aws accessanalyzer create-analyzer   --analyzer-name my-external-analyzer   --type ACCOUNT
    
    # Create an unused access analyzer (organization level)
    aws accessanalyzer create-analyzer   --analyzer-name my-unused-access-analyzer   --type ORGANIZATION_UNUSED_ACCESS   --configuration '{"unusedAccess": {"unusedAccessAge": 90}}'
    
    # Generate a policy based on actual CloudTrail usage
    aws accessanalyzer start-policy-generation   --policy-generation-details '{"principalArn":"arn:aws:iam::123456789012:role/MyRole"}'   --cloud-trail-details '{"trails":[{"cloudTrailArn":"arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail","allRegions":true}],"accessRole":"arn:aws:iam::123456789012:role/AccessAnalyzerRole","startTime":"2025-01-01T00:00:00Z","endTime":"2025-03-01T00:00:00Z"}'
    
    # Validate a policy against best practices
    aws accessanalyzer validate-policy   --policy-document file://policy.json   --policy-type IDENTITY_POLICY

    2025 Update: Access Analyzer now provides actionable policy recommendations with specific steps to refine permissions. Custom tracking periods (1-365 days) were introduced.

    5. Use Permission Boundaries for Delegated Administration

    Permission boundaries let centralized security teams safely delegate IAM role creation to developers. The boundary sets the maximum permissions ceiling -- even if a developer attaches AdministratorAccess, the effective permissions are the intersection of the identity policy and the boundary.

    # Create a permission boundary policy
    aws iam create-policy   --policy-name DeveloperBoundary   --policy-document file://boundary-policy.json
    
    # Create a role with the boundary applied at creation time
    aws iam create-role   --role-name app-lambda-role   --assume-role-policy-document file://trust-policy.json   --permissions-boundary arn:aws:iam::123456789012:policy/DeveloperBoundary

    Best practice: Always set the boundary at role creation time so the role is never without a boundary, even momentarily. Maximum one boundary per role/user.

    6. Deploy Service Control Policies (SCPs)

    SCPs set hard permission boundaries at the AWS Organizations level. Deny statements in SCPs cannot be overridden by any IAM policy in member accounts.

    Major 2025 Enhancement: As of September 2025, SCPs now support the full IAM policy language, including NotResource, conditions in Allow statements, and individual resource ARNs.

    Restrict to Approved Regions

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Sid": "DenyUnapprovedRegions",
        "Effect": "Deny",
        "Action": "*",
        "Resource": "*",
        "Condition": {
          "StringNotEquals": {
            "aws:RequestedRegion": ["us-east-1", "eu-west-1", "eu-central-1"]
          },
          "ArnNotLike": {
            "aws:PrincipalARN": "arn:aws:iam::*:role/OrganizationAdmin"
          }
        }
      }]
    }

    Prevent Disabling Security Services

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Sid": "DenyDisablingSecurityTools",
        "Effect": "Deny",
        "Action": [
          "guardduty:DeleteDetector",
          "securityhub:DisableSecurityHub",
          "config:StopConfigurationRecorder",
          "cloudtrail:StopLogging",
          "access-analyzer:DeleteAnalyzer"
        ],
        "Resource": "*"
      }]
    }

    Best practice: Use a deny-list approach. Start with the default FullAWSAccess SCP, then add targeted Deny statements. Always test in a dedicated test OU before production.

    7. Rotate and Eliminate Long-Lived Access Keys

    Access keys are the single most common attack vector. In November 2025, attackers found credentials in public S3 buckets and used LLMs to automate reconnaissance and lateral movement across 19 AWS principals in under 10 minutes.

    # List all access keys for a user
    aws iam list-access-keys --user-name example-user
    
    # Create a new key (rotate)
    aws iam create-access-key --user-name example-user
    
    # Deactivate the old key after updating applications
    aws iam update-access-key --user-name example-user   --access-key-id AKIAIOSFODNN7EXAMPLE --status Inactive
    
    # Delete the old key after confirming
    aws iam delete-access-key --user-name example-user   --access-key-id AKIAIOSFODNN7EXAMPLE

    Automated Detection with AWS Config

    # Detect keys older than 90 days
    aws configservice put-config-rule --config-rule '{
      "ConfigRuleName": "access-keys-rotated",
      "Source": {
        "Owner": "AWS",
        "SourceIdentifier": "ACCESS_KEYS_ROTATED"
      },
      "InputParameters": "{"maxAccessKeyAge":"90"}"
    }'

    Best practice: Prefer IAM roles with temporary credentials over access keys entirely. For CI/CD, use OIDC federation (e.g., GitHub Actions OIDC provider) to eliminate keys completely.

    8. Use IAM Condition Keys for Context-Aware Security

    Condition keys add contextual controls beyond identity -- restricting by IP, MFA status, encryption requirements, and organization membership.

    Key Condition Examples

    Require MFA for sensitive operations:

    {
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }

    Restrict by organization (data perimeter):

    {
      "Condition": {
        "StringNotEquals": {
          "aws:PrincipalOrgID": "o-EXAMPLE"
        }
      }
    }

    Require KMS encryption on S3 uploads:

    {
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "aws:kms"
        }
      }
    }

    Caveat: aws:SourceIp provides limited security because attackers can pivot through VPNs. It should be one layer in a defense-in-depth strategy, not the sole control.

    9. Use Roles for Applications (Never Embed Keys)

    IAM roles provide temporary credentials via STS that automatically rotate, eliminating the risk of key leakage.

    # Create an EC2 instance profile with a role
    aws iam create-role   --role-name MyEC2AppRole   --assume-role-policy-document '{
        "Version": "2012-10-17",
        "Statement": [{
          "Effect": "Allow",
          "Principal": {"Service": "ec2.amazonaws.com"},
          "Action": "sts:AssumeRole"
        }]
      }'
    
    aws iam create-instance-profile --instance-profile-name MyEC2AppProfile
    aws iam add-role-to-instance-profile   --instance-profile-name MyEC2AppProfile   --role-name MyEC2AppRole
    
    # For CI/CD: use OIDC federation (GitHub Actions example)
    aws iam create-open-id-connect-provider   --url https://token.actions.githubusercontent.com   --client-id-list sts.amazonaws.com   --thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1

    Use instance profiles for EC2, execution roles for Lambda, task roles for ECS, and IRSA/Pod Identity for EKS.

    10. Generate and Review Credential Reports

    Credential reports provide a snapshot of all IAM users and their credential status -- passwords, access keys, MFA, last usage dates.

    # Generate and download the report
    aws iam generate-credential-report
    aws iam get-credential-report --query "Content" --output text | base64 -d > iam-report.csv

    Key Columns to Audit

    • mfa_active -- must be true for all password-enabled users
    • access_key_1_active / access_key_2_active -- identify active keys
    • access_key_1_last_used_date -- identify unused keys for removal
    • password_last_used -- identify dormant accounts (>90 days)
    • access_key_1_last_rotated -- identify keys needing rotation

    CIS Benchmark: Control 1.12 (disable credentials unused for 45+ days), Control 1.13 (only one active access key per user), Control 1.14 (rotate keys every 90 days).

    11. Monitor with CIS Benchmark v5.0 in Security Hub

    AWS Security Hub CSPM added support for CIS AWS Foundations Benchmark v5.0 in October 2025, providing automated, continuous evaluation of your IAM posture.

    # Enable CIS Benchmark v5.0 in Security Hub
    aws securityhub batch-enable-standards   --standards-subscription-requests '[{
        "StandardsArn": "arn:aws:securityhub:::standards/cis-aws-foundations-benchmark/v/5.0.0"
      }]'

    Key IAM Controls

    • 1.4: No root access keys
    • 1.5/1.6: Root MFA (hardware)
    • 1.10: MFA for all console users
    • 1.12: Disable credentials unused for 45+ days
    • 1.14: Rotate access keys every 90 days
    • 1.16: No full *:* admin policies attached

    12. Leverage New IAM Features (2025-2026)

    IAM Policy Autopilot (November 2025)

    An open-source MCP server and CLI tool that analyzes application code locally to generate baseline IAM policies. Integrates with AI coding assistants (Claude Code, Kiro, Cursor). Supports Python, TypeScript, and Go.

    Outbound Identity Federation (November 2025)

    Enables AWS workloads to securely authenticate with third-party cloud providers and SaaS platforms using short-lived JWTs, eliminating long-term credentials for cross-cloud access.

    SCPs with Full IAM Language (September 2025)

    SCPs now support NotResource, conditions in Allow statements, and individual resource ARNs -- enabling far more granular organizational guardrails than before.


    Common Misconfigurations

    Misconfiguration Risk Detection
    Root account with access keys Total account takeover Credential report: access_key_1_active = true on root
    IAM users without MFA Credential compromise leads to full access Credential report: mfa_active = false
    *:* admin policies on IAM users No blast radius containment Access Analyzer findings
    Stale access keys (>90 days) Long-lived credentials increase exposure window AWS Config: access-keys-rotated
    Overly permissive role trust policies Cross-account privilege escalation Access Analyzer external access findings

    Quick Reference Checklist

    # Practice Priority
    1Eliminate root account usageCritical
    2Enforce MFA universallyCritical
    3Adopt IAM Identity CenterHigh
    4Implement least privilege with Access AnalyzerHigh
    5Use permission boundariesHigh
    6Deploy SCPs as guardrailsHigh
    7Rotate/eliminate access keysCritical
    8Use IAM condition keysMedium
    9Use roles for applicationsCritical
    10Review credential reports regularlyMedium
    11Enable CIS Benchmark in Security HubHigh
    12Leverage new IAM featuresMedium

    Related Resources

    Go Deeper: The State of AWS Security 2026

    This article is just the start. Get the full picture with our free whitepaper - 8 chapters covering IAM, S3, VPC, monitoring, agentic AI security, compliance, and a prioritized action plan with 50+ CLI commands.

    IAMMFALeast PrivilegeSCPsIdentity CenterAccess AnalyzerCredential Management