Apr 09, 2026 Cloud · 5 min read

AWS IAM Best Practices: A Practical Guide

IAM misconfigurations are the most common finding in AWS security audits. Here's the practical checklist — root account, least privilege, roles vs users, and how to audit what you have.

IAM misconfigurations show up in almost every AWS security audit I run. Not because teams are careless — because IAM accumulates debt over time. Roles added for a one-off task, policies copied from Stack Overflow, users with access keys that haven’t rotated in two years. The permission surface grows incrementally, and nobody does a full review until something goes wrong.

This guide covers the practical fundamentals: what to lock down first, what patterns to avoid, and how to audit what you already have.


Root account: lock it down first

The root account is the one AWS identity that can do anything — close the account, change billing, override IAM. It cannot be restricted by SCPs or permission boundaries.

Root account hygiene is non-negotiable:

  1. Enable MFA. Go to the IAM console, select “My Security Credentials,” and set up a hardware MFA token or authenticator app. This is the single most important IAM action you can take. A root account without MFA is an account that can be taken over with credentials alone.

  2. Remove access keys. Root account should have no programmatic access keys. If they exist, delete them. There is no legitimate use case for root access keys.

  3. Don’t use root for daily operations. Create an IAM identity (or use AWS SSO) for all day-to-day work. Root is for account-level emergencies only. Lock the credentials somewhere secure and don’t touch them.


Users vs roles: prefer roles

IAM users have static credentials — access keys and passwords that don’t expire unless you rotate them. They accumulate over time and often outlast their original purpose.

IAM roles use temporary credentials issued by STS, with a configurable expiry (15 minutes to 12 hours). When the session expires, the credentials are useless.

Principle: Use roles wherever possible. Use users only when you have no alternative.

Where roles replace users:

  • EC2 instances: Attach an instance profile (a role). No access keys on the instance.
  • Lambda functions: Assign an execution role. No access keys in environment variables.
  • CI/CD pipelines: Use OIDC federation (GitHub Actions → AWS) or assume a role. No long-lived keys in CI secrets.
  • Cross-account access: One account assumes a role in another. No credential sharing.

Where you might still need IAM users:

  • Programmatic access for legacy tools that don’t support role assumption
  • Break-glass accounts for emergency access

If you have IAM users with access keys, enforce key rotation (90-day policy via IAM password policy) and audit last-used dates regularly. Delete keys that haven’t been used in 90 days.


Least privilege: the practical approach

“Least privilege” means giving an identity only the permissions it needs to do its job — nothing more. In practice, it’s easy to state and hard to implement, because AWS has thousands of individual actions across hundreds of services.

The pragmatic approach:

Start with AWS managed policies for broad roles. ReadOnlyAccess, AmazonS3ReadOnlyAccess, CloudWatchReadOnlyAccess are reasonable starting points. They’re not perfectly scoped, but they’re better than starting with AdministratorAccess and never narrowing.

Audit with IAM Access Analyzer. Access Analyzer reviews your policies and flags permissions that are overly broad or allow unintended external access. It’s a built-in AWS service — enable it in each region.

Use CloudTrail to scope permissions based on actual use. If a role has s3:* but Access Advisor shows it has only ever called s3:GetObject and s3:PutObject, scope the policy to those two actions. IAM Access Advisor (in the IAM console under each role) shows last-accessed service data.

Never use * on sensitive services without review. Wildcards on iam:*, s3:*, ec2:*, and kms:* are the most common broad-access patterns I see. Flag these for review. They may be intentional (admin roles) or accidental (copied from a tutorial).


Permission boundaries and SCPs

Permission boundaries cap the maximum permissions a role or user can have. They’re useful when you need to allow team members to create IAM roles themselves (for CI/CD or service accounts) without letting them create roles with more permissions than they have.

A typical pattern: developers can create service roles for Lambda and ECS, but only within the permission boundary that limits those roles to specific services and doesn’t allow IAM privilege escalation.

Service Control Policies (SCPs) apply at the AWS Organizations account level. They’re not permissions — they’re guardrails. An SCP can prevent any identity in an account from enabling a service, creating resources in unauthorized regions, or disabling CloudTrail.

SCPs are the foundation of multi-account governance. Common ones:

  • Deny disabling CloudTrail and Config
  • Deny EC2 instance launches outside approved regions
  • Deny root account access except from specific IP ranges
  • Deny creating IAM users (force SSO-only access)

Practical audit checklist

If you haven’t done an IAM review recently, work through this list:

Root account:

  • MFA enabled
  • No access keys

IAM users:

  • All users have MFA enabled
  • Access keys rotated within 90 days (or deleted)
  • Unused users (no console/API activity in 90+ days) reviewed and removed

Roles:

  • No roles with AdministratorAccess unless explicitly required
  • No roles with * on sensitive services without justification
  • IAM Access Advisor reviewed for last-accessed data on high-privilege roles
  • EC2 instance profiles in use (no access keys on instances)
  • Lambda execution roles scoped to minimum required services
  • CI/CD using OIDC or role assumption (no long-lived keys in CI)

Policies:

  • Inline policies reviewed (prefer managed policies for auditability)
  • Wildcard resource (Resource: "*") on write actions reviewed
  • IAM Access Analyzer enabled and findings reviewed

Organization-level:

  • SCPs in place for CloudTrail/Config protection
  • Region restriction SCP if you operate in a limited set of regions

The compounding problem

IAM debt compounds. Each role added without a review is a permission that persists indefinitely. Each user who leaves without having their access removed is a credential that may still work. Each policy copied from the internet without understanding is a risk that may not surface until an incident.

The best time to do an IAM audit is when you’re setting up the account. The second best time is now.

If your account has been running for more than 6 months without a formal IAM review, assume there are findings. The audit is the first step to understanding your actual exposure.

Contact me or email nick@coldsmokeconsulting.com to discuss a security review.


Nick Allevato is an AWS Certified Solutions Architect Professional with 20 years of infrastructure experience. He runs Cold Smoke Consulting, an independent AWS consulting practice.