AWS IAM Best Practices
Essential IAM security practices including least privilege, MFA, and role-based access patterns.
Prerequisites
- AWS account with IAM access
- Basic understanding of JSON policy syntax
- Familiarity with AWS Organizations
Why IAM Security Matters
AWS Identity and Access Management (IAM) is the backbone of your cloud security posture. Every single API call in AWS, whether from the console, CLI, SDK, or an automated service, is authenticated and authorized through IAM. This makes IAM the single most important service to configure correctly. A misconfigured IAM policy can expose your entire AWS environment to unauthorized access, data exfiltration, or complete account takeover.
According to multiple industry reports, IAM misconfigurations consistently rank among the top causes of cloud security breaches. The challenge is that IAM is both incredibly powerful and deeply complex. AWS has over 300 services, each with dozens of API actions, creating a permission surface area of thousands of possible action-resource combinations. Without a disciplined approach to IAM, teams inevitably drift toward overly permissive policies that violate the principle of least privilege.
This guide covers battle-tested IAM best practices that every team should implement, from individual developer accounts to large enterprise deployments. Whether you are securing a single-account startup or a multi-account enterprise with hundreds of workloads, these principles will help you build a robust security foundation.
Root Account Alert
Never use the AWS root account for day-to-day operations. The root account has unrestricted access to every resource in the account and cannot be limited by IAM policies, SCPs, or permission boundaries. Enable MFA on the root account immediately after creating it, then lock away the credentials in a secure location like a hardware security module or a physical safe. Only use the root account for the handful of tasks that require it, such as changing your account support plan or closing the account.
Principle of Least Privilege
The principle of least privilege means granting only the permissions required to perform a task and nothing more. This is the single most impactful IAM practice you can adopt. The reason is simple: every additional permission granted to a principal is a potential attack vector. If a Lambda function only needs to read from a specific S3 bucket, it should not have s3:* on *. If an EC2 instance only writes logs to CloudWatch, it should not have the CloudWatchFullAccess managed policy.
The practical challenge is that starting with zero permissions and adding them incrementally requires more effort upfront. Many teams default to broad policies likeAdministratorAccess or PowerUserAccess during development and never revisit them. This creates significant security risk in production. The correct approach is to start with zero permissions and add them as needed, using the tools AWS provides to right-size policies over time.
Tools for Right-Sizing Permissions
AWS provides several tools to help you implement and maintain least privilege:
- IAM Access Analyzer Policy Generation: Analyzes CloudTrail logs to generate a fine-grained policy based on the actual API calls made by a principal over a specified period. This is the most effective way to create least-privilege policies for existing workloads.
- IAM Access Advisor: Shows the last time each AWS service was accessed by a principal. If a role has S3 permissions but has not accessed S3 in 90 days, those permissions are candidates for removal.
- IAM Policy Simulator: Lets you test policies against specific API actions and resources before applying them in production. Use it to verify that a new policy grants exactly the permissions you intend.
- CloudTrail Lake: Query your CloudTrail events using SQL to identify which API actions a principal actually uses. This provides more granular insights than Access Advisor.
- IAM Access Analyzer Unused Access: Identifies unused roles, unused access keys, and unused permissions across your accounts. Available with IAM Access Analyzer at no additional cost.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadSpecificBucket",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-data-bucket",
"arn:aws:s3:::my-app-data-bucket/*"
]
}
]
}Common Least-Privilege Anti-Patterns
Avoid these common mistakes that undermine least privilege:
| Anti-Pattern | Risk | Correct Approach |
|---|---|---|
"Action": "*" | Grants all actions on all services | Specify exact actions needed |
"Resource": "*" | Applies to every resource in the account | Scope to specific ARNs or patterns |
Using AWS managed FullAccess policies | Grants far more permissions than needed | Create custom policies or use Access Analyzer |
| Sharing credentials between services | No blast radius isolation | One IAM role per service or function |
| Not reviewing permissions after initial setup | Permission drift over time | Quarterly reviews using Access Advisor |
Use Conditions for Extra Security
Add condition keys to further restrict when a policy applies. For example, restrict access to specific IP ranges with aws:SourceIp, require MFA withaws:MultiFactorAuthPresent, limit actions to specific regions withaws:RequestedRegion, or restrict to specific VPCs withaws:SourceVpc. Condition keys are one of the most powerful and underused features of IAM policies.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowEC2WithMFAAndRegion",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:TerminateInstances"
],
"Resource": "arn:aws:ec2:us-east-1:123456789012:instance/*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
},
"StringEquals": {
"aws:RequestedRegion": "us-east-1",
"ec2:ResourceTag/Environment": "development"
}
}
}
]
}IAM Roles Over Long-Lived Credentials
IAM roles provide temporary security credentials that automatically rotate, eliminating the risk of leaked long-lived access keys. Wherever possible, use roles instead of IAM users with access keys. This is not just a best practice; it is a fundamental security principle. Long-lived credentials are the most common vector for cloud security breaches because they can be accidentally committed to source code, stored in insecure locations, or exfiltrated from compromised systems.
Every AWS compute service supports IAM roles natively. EC2 instances use instance profiles, Lambda functions have execution roles, ECS tasks have task roles, and EKS pods can use IAM Roles for Service Accounts (IRSA) or EKS Pod Identity. There is almost no legitimate reason to use long-lived access keys for workloads running in AWS.
| Credential Type | Rotation | Risk Level | Use Case |
|---|---|---|---|
| IAM Role (STS) | Automatic (1-12 hours) | Low | EC2, Lambda, ECS, cross-account |
| IAM User Access Key | Manual | High | Legacy systems, third-party tools |
| SSO / Identity Center | Session-based | Low | Human user access to AWS Console/CLI |
| OIDC Federation | Token-based (minutes) | Low | CI/CD (GitHub Actions, GitLab CI) |
EC2 Instance Profiles
An instance profile is a container for an IAM role that allows EC2 instances to assume that role. When you associate an instance profile with an EC2 instance, any application running on that instance can retrieve temporary credentials from the instance metadata service (IMDS). The AWS SDKs automatically discover and use these credentials, so your application code does not need to handle credential management at all.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}Enforce IMDSv2
The EC2 Instance Metadata Service v1 (IMDSv1) is vulnerable to Server-Side Request Forgery (SSRF) attacks. An attacker who can make HTTP requests from your instance can steal the IAM role credentials. Always enforce IMDSv2, which requires a session token and is not vulnerable to SSRF. Set HttpTokens: required in your launch template or use an SCP to deny ec2:RunInstances without IMDSv2.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceIMDSv2",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotEquals": {
"ec2:MetadataHttpTokens": "required"
}
}
}
]
}Cross-Account Access with Roles
For cross-account access, use role chaining with an external ID to prevent the confused deputy problem. The confused deputy is a security issue where a trusted service (such as a third-party SaaS tool) could be tricked into assuming a role in your account on behalf of an unauthorized actor. The external ID serves as a shared secret between you and the trusted third party, ensuring that only the intended principal can assume the role.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::987654321098:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "unique-external-id-from-partner"
}
}
}
]
}CI/CD with OIDC Federation
Modern CI/CD platforms like GitHub Actions, GitLab CI, and CircleCI support OIDC federation, which allows your pipelines to assume IAM roles without storing any AWS credentials. This is the most secure approach for CI/CD because there are no secrets to manage, rotate, or accidentally expose.
# CloudFormation for GitHub Actions OIDC
GitHubOIDCProvider:
Type: AWS::IAM::OIDCProvider
Properties:
Url: https://token.actions.githubusercontent.com
ClientIdList:
- sts.amazonaws.com
ThumbprintList:
- 6938fd4d98bab03faadb97b34396831e3780aea1
GitHubActionsRole:
Type: AWS::IAM::Role
Properties:
RoleName: github-actions-deploy
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Federated: !Ref GitHubOIDCProvider
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
token.actions.githubusercontent.com:aud: sts.amazonaws.com
StringLike:
token.actions.githubusercontent.com:sub: repo:my-org/my-repo:ref:refs/heads/mainPermission Boundaries
Permission boundaries set the maximum permissions that an IAM entity can have. They are essential in environments where you delegate IAM administration to developers or teams. Even if a developer creates a role with AdministratorAccess, the permission boundary ensures the effective permissions never exceed the boundary. This is the key mechanism for safely delegating IAM capabilities without risking privilege escalation.
Think of permission boundaries as guardrails on a highway. The identity-based policy determines where you want to go (what permissions you request), and the permission boundary determines where you are allowed to go (the maximum possible permissions). The effective permissions are the intersection of both policies. A request is only allowed if it is permitted by both the identity-based policy and the permission boundary.
How Permission Boundaries Work
When you attach a permission boundary to an IAM user or role, it acts as a ceiling on the permissions that entity can have. The permission boundary does not grant any permissions by itself. It only limits the maximum permissions that can be granted by identity-based policies.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowedServices",
"Effect": "Allow",
"Action": [
"s3:*",
"dynamodb:*",
"lambda:*",
"logs:*",
"sqs:*",
"sns:*",
"cloudwatch:*",
"xray:*",
"apigateway:*"
],
"Resource": "*"
},
{
"Sid": "AllowIAMWithBoundary",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:AttachRolePolicy",
"iam:PutRolePolicy",
"iam:DeleteRole",
"iam:DetachRolePolicy",
"iam:DeleteRolePolicy",
"iam:PutRolePermissionsBoundary"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::123456789012:policy/DevBoundary"
}
}
},
{
"Sid": "DenyBoundaryRemoval",
"Effect": "Deny",
"Action": [
"iam:DeleteRolePermissionsBoundary",
"iam:DeleteUserPermissionsBoundary"
],
"Resource": "*"
},
{
"Sid": "DenyEscalation",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"organizations:*",
"account:*"
],
"Resource": "*"
}
]
}Understanding Effective Permissions
The effective permissions for a principal are the intersection of identity-based policies, resource-based policies, permission boundaries, SCPs, and session policies. A permission must be allowed by all applicable policy types and not explicitly denied by any. An explicit Deny in any policy always wins, regardless of any Allow statements in other policies. This evaluation logic is the foundation of AWS IAM security, and understanding it is critical for troubleshooting access issues.
Permission Boundary Use Cases
| Use Case | Description | Boundary Strategy |
|---|---|---|
| Developer self-service | Developers create their own Lambda roles | Allow serverless services, deny IAM escalation |
| Team autonomy | Each team manages their own resources | Allow team-specific services, enforce tagging |
| Contractor access | Temporary workers need limited AWS access | Allow only specific services and regions |
| Sandbox accounts | Experimentation without risk | Allow broad services, deny networking and IAM changes |
Multi-Account Strategy with SCPs
AWS Organizations Service Control Policies (SCPs) provide guardrails across your entire organization. SCPs do not grant permissions; they restrict what is allowed. They act as the outermost boundary on what any principal in an account can do, regardless of what IAM policies are attached. This makes SCPs the most powerful governance tool in AWS.
In a well-architected multi-account environment, you separate workloads into dedicated accounts for blast radius isolation, billing separation, and simplified governance. SCPs applied to organizational units (OUs) ensure that security guardrails are consistently enforced across all accounts in that OU, even if individual account administrators try to circumvent them.
Common SCP Patterns
The following SCP patterns are recommended for most organizations:
- Prevent disabling CloudTrail: Ensures a complete audit trail is always maintained in every account
- Prevent disabling GuardDuty: Maintains continuous threat detection coverage
- Restrict AWS regions: Prevents resource creation in unapproved regions, reducing attack surface
- Prevent creation of IAM users: Forces use of IAM Identity Center for human access
- Require encryption: Denies creation of unencrypted S3 buckets, EBS volumes, and RDS instances
- Protect security services: Prevents disabling Security Hub, Config, or Access Analyzer
- Deny root account actions: Prevents the root user from performing API actions in member accounts
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNonApprovedRegions",
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"sts:*",
"support:*",
"budgets:*",
"cloudfront:*",
"route53:*",
"waf:*",
"wafv2:*",
"cloudwatch:GetMetricData",
"cloudwatch:ListMetrics"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"us-east-1",
"us-west-2",
"eu-west-1"
]
}
}
}
]
}{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PreventCloudTrailDisable",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"cloudtrail:UpdateTrail"
],
"Resource": "arn:aws:cloudtrail:*:*:trail/organization-trail"
},
{
"Sid": "PreventGuardDutyDisable",
"Effect": "Deny",
"Action": [
"guardduty:DeleteDetector",
"guardduty:DisassociateFromMasterAccount",
"guardduty:UpdateDetector"
],
"Resource": "*"
},
{
"Sid": "PreventSecurityHubDisable",
"Effect": "Deny",
"Action": [
"securityhub:DisableSecurityHub",
"securityhub:DisassociateFromMasterAccount"
],
"Resource": "*"
}
]
}SCP Testing Is Critical
SCPs can break workloads if applied too broadly. Always test SCPs in a sandbox OU before applying them to production. Use the NotAction element carefully, as it allows all actions except those listed. Monitor AWS CloudTrail forAccessDenied events after applying SCPs to catch unintended blocks. Remember that SCPs do not affect the management account, only member accounts.
IAM Identity Center (AWS SSO)
IAM Identity Center (formerly AWS SSO) is the recommended way for human users to access AWS accounts and applications. It provides centralized identity management, temporary credentials, and a single sign-on experience across all accounts in your organization. This eliminates the need for IAM users with long-lived passwords and access keys.
Key Benefits of Identity Center
- Centralized user management: Manage users in one place, either in the built-in directory or federated from an external IdP like Okta, Azure AD, or Google Workspace
- Temporary credentials: Users receive short-lived credentials for each session, eliminating the risk of credential leakage
- Permission sets: Define reusable sets of permissions that can be assigned to users and groups across multiple accounts
- MFA enforcement: Require MFA for all users accessing the SSO portal, providing a single enforcement point
- CLI integration: The AWS CLI v2 natively supports SSO, allowing developers to authenticate with
aws sso login
# Configure AWS CLI for SSO
aws configure sso
# Follow the prompts to set up SSO profile
# Login with SSO
aws sso login --profile my-sso-profile
# Use the SSO profile for commands
aws s3 ls --profile my-sso-profile
# Example ~/.aws/config entry
# [profile dev-account]
# sso_session = my-org
# sso_account_id = 123456789012
# sso_role_name = DeveloperAccess
# region = us-east-1
#
# [sso-session my-org]
# sso_start_url = https://my-org.awsapps.com/start
# sso_region = us-east-1
# sso_registration_scopes = sso:account:accessPermission Sets Strategy
Permission sets define what users can do in each account. Create a hierarchy of permission sets that align with your organization's roles:
| Permission Set | Purpose | Attached Policies |
|---|---|---|
| AdministratorAccess | Account owners, break-glass | AWS managed AdministratorAccess |
| DeveloperAccess | Day-to-day development work | Custom policy with service restrictions |
| ReadOnlyAccess | Auditing, troubleshooting | AWS managed ReadOnlyAccess |
| DatabaseAdmin | Database operations team | Custom policy for RDS, DynamoDB, ElastiCache |
| SecurityAudit | Security team review | AWS managed SecurityAudit + custom policies |
MFA and Password Policies
Multi-Factor Authentication (MFA) adds a critical second layer of authentication beyond passwords. In AWS, MFA should be required for all human user access, especially for high-privilege operations. Even if credentials are compromised, MFA prevents unauthorized access unless the attacker also possesses the MFA device.
MFA Device Types
| Device Type | Security Level | Use Case |
|---|---|---|
| FIDO2 security key (YubiKey) | Highest, phishing-resistant | Root account, admin users |
| Hardware TOTP token | High, no software dependency | Root account (recommended backup) |
| Virtual MFA (authenticator app) | Medium, software-based | Standard user accounts |
Enforcing MFA with IAM Policies
You can create an IAM policy that denies all actions except IAM self-service until the user has authenticated with MFA. This is commonly called the “force MFA” policy pattern.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSelfManagementWithoutMFA",
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ListVirtualMFADevices",
"iam:ResyncMFADevice",
"iam:ChangePassword",
"sts:GetSessionToken"
],
"Resource": "*"
},
{
"Sid": "DenyAllExceptSelfManagementWithoutMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ListVirtualMFADevices",
"iam:ResyncMFADevice",
"iam:ChangePassword",
"sts:GetSessionToken"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}Resource-Based Policies
Resource-based policies are JSON policies attached directly to AWS resources such as S3 buckets, SQS queues, KMS keys, Lambda functions, and SNS topics. Unlike identity-based policies which are attached to users, groups, or roles, resource-based policies define who can access the resource, including principals from other AWS accounts.
Resource-based policies are unique because they can grant cross-account access without requiring the caller to assume a role. When a principal in Account A accesses a resource with a resource-based policy in Account B, the principal uses its own permissions combined with the resource policy, and there is no need to assume a role in Account B.
Resource Policy Best Practices
- Avoid wildcards in Principal: Never use
"Principal": "*"without conditions. This grants access to anyone, including anonymous users. - Use conditions for cross-account access: Add
aws:PrincipalOrgIDto restrict access to principals within your AWS organization. - Audit with Access Analyzer: IAM Access Analyzer automatically identifies resource-based policies that grant access to external entities.
- Encrypt with KMS: Use KMS key policies to control who can encrypt and decrypt data, providing an additional layer of access control beyond the resource policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOrgAccess",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::shared-data-bucket",
"arn:aws:s3:::shared-data-bucket/*"
],
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-abc123def456"
}
}
},
{
"Sid": "DenyUnencryptedTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::shared-data-bucket",
"arn:aws:s3:::shared-data-bucket/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}Auditing and Monitoring
IAM security is not a set-and-forget exercise. Continuous monitoring and regular audits are essential to maintain a strong security posture over time. Threats evolve, team members change, and permissions accumulate unless actively managed. Implement the following monitoring and audit practices to detect issues early and respond quickly.
CloudTrail for Complete Audit Trail
Enable CloudTrail in all regions and all accounts. Every IAM API call is logged, providing a complete audit trail of who did what, when, and from where. Use a centralized CloudTrail configuration through AWS Organizations to ensure consistent logging across your entire environment.
- Organization trail: Creates a trail in every account automatically, logged to a central S3 bucket in the log archive account
- CloudTrail Lake: Enables SQL-based querying of CloudTrail events for forensic investigation and trend analysis
- Data events: Enable data event logging for S3 and Lambda to track object-level and invocation-level activity
- Insights events: CloudTrail Insights automatically detects unusual API activity patterns
IAM Access Analyzer
Use IAM Access Analyzer to detect resources shared with external entities, such as S3 buckets with public access, KMS keys with cross-account grants, or IAM roles with overly broad trust policies. Access Analyzer continuously monitors your environment and generates findings when it detects external access.
Credential Reports and Security Alerts
Generate credential reports regularly to identify users with old access keys, users without MFA, and inactive accounts. Set up CloudWatch alarms for sensitive IAM events to detect potential security incidents in real time.
{
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName": "RootAccountUsage",
"MetricName": "RootAccountUsageCount",
"Namespace": "CloudTrailMetrics",
"Statistic": "Sum",
"Period": 300,
"EvaluationPeriods": 1,
"Threshold": 1,
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"AlarmActions": [
"arn:aws:sns:us-east-1:123456789012:SecurityAlerts"
]
}
}# Generate and download IAM credential report
aws iam generate-credential-report
sleep 10
aws iam get-credential-report \
--query 'Content' \
--output text | base64 --decode > credential-report.csv
# Find users without MFA enabled
awk -F',' 'NR>1 && $4=="true" && $8=="false" {print $1, "- Password enabled but no MFA"}' \
credential-report.csv
# Find access keys older than 90 days
awk -F',' 'NR>1 && $9=="true" {
cmd="date -d \"" $10 "\" +%s 2>/dev/null || date -j -f \"%Y-%m-%dT%H:%M:%S+00:00\" \"" $10 "\" +%s"
cmd | getline created
close(cmd)
now=systime()
age=(now-created)/86400
if (age > 90) print $1, "- Access key 1 is", int(age), "days old"
}' credential-report.csvAutomated Compliance with AWS Config
Use AWS Config rules to continuously monitor IAM compliance. Key rules includeiam-root-access-key-check (no root access keys),iam-user-mfa-enabled (MFA on all users),iam-user-unused-credentials-check (no stale credentials), andiam-policy-no-statements-with-admin-access (no admin policies on users). Config rules trigger automatically when resources change, providing continuous compliance monitoring.
IAM Policy Structure and Evaluation Logic
Understanding how AWS evaluates IAM policies is essential for writing effective policies and troubleshooting access issues. AWS follows a specific evaluation order when a principal makes a request:
- Explicit Deny: If any applicable policy contains an explicit Deny, the request is denied immediately. This takes precedence over everything.
- SCPs: If the account is part of an AWS Organization, SCPs must allow the action. SCPs do not apply to the management account.
- Resource-based policies: If a resource-based policy grants access, the request may be allowed even without an identity-based policy (for same-account access).
- Permission boundaries: If a permission boundary is attached, it must allow the action.
- Session policies: For assumed roles with session policies, the session policy must allow the action.
- Identity-based policies: Finally, the identity-based policies attached to the principal must allow the action.
The default is Deny. Unless an explicit Allow exists in the appropriate policies (and no Deny blocks it), the request is denied.
Policy Elements Reference
| Element | Purpose | Example |
|---|---|---|
Effect | Allow or Deny | "Effect": "Allow" |
Action | API actions to allow/deny | "Action": "s3:GetObject" |
NotAction | All actions except those listed | "NotAction": "iam:*" |
Resource | ARNs the statement applies to | "Resource": "arn:aws:s3:::my-bucket/*" |
Condition | When the statement applies | IP ranges, MFA, tags, regions |
Principal | Who the policy applies to (resource policies) | Account IDs, service principals |
IAM for Specific AWS Services
Different AWS services have unique IAM integration patterns. Understanding these patterns helps you implement least privilege correctly for each service.
Lambda Execution Roles
Every Lambda function needs an execution role that grants permission to write logs to CloudWatch and access any other AWS services the function uses. Use theAWSLambdaBasicExecutionRole managed policy as a starting point for CloudWatch Logs access, then add only the specific permissions your function needs.
ECS Task Roles vs Execution Roles
ECS distinguishes between task execution roles (used by the ECS agent to pull images and write logs) and task roles (used by your application code to access AWS services). Keep these separate and scope each to its specific purpose.
EKS Pod Identity
EKS Pod Identity (the successor to IRSA) provides fine-grained IAM roles for individual Kubernetes pods. Each pod can assume a different IAM role, enabling least-privilege access at the pod level rather than the node level.
AWS Lambda Performance Tuning: Execution Roles and SecurityECS vs EKS Decision Guide: IAM Integration PatternsIAM Security Automation
Manual IAM management does not scale. As your organization grows, automate IAM governance using Infrastructure as Code, automated remediation, and continuous compliance monitoring.
Infrastructure as Code for IAM
Define all IAM resources (roles, policies, groups, permission boundaries) in CloudFormation, CDK, or Terraform. Never create IAM resources manually through the console. Code-defined IAM enables version control, peer review, and automated testing of permission changes before they reach production.
import * as iam from 'aws-cdk-lib/aws-iam';
import * as cdk from 'aws-cdk-lib';
// Create a role with a permission boundary
const devRole = new iam.Role(this, 'DeveloperRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
permissionsBoundary: iam.ManagedPolicy.fromManagedPolicyName(
this, 'Boundary', 'DevBoundary'
),
});
// Grant least-privilege access
const bucket = s3.Bucket.fromBucketName(this, 'DataBucket', 'my-data');
bucket.grantRead(devRole);
// Use CDK Nag to enforce IAM best practices
import { AwsSolutionsChecks } from 'cdk-nag';
cdk.Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true }));Automated Remediation
Use EventBridge rules to detect and automatically remediate IAM security issues:
- Automatically deactivate access keys older than 90 days
- Remove inline policies from IAM users (force use of managed policies)
- Detach overly permissive policies (like AdministratorAccess) from non-admin roles
- Alert on any IAM policy change in production accounts
IAM Troubleshooting Checklist
When a principal receives an AccessDenied error, work through this checklist systematically:
- Check identity-based policies: Does the principal have a policy that allows the action on the resource?
- Check resource-based policies: Does the resource have a policy that allows or denies the principal?
- Check permission boundaries: Is there a permission boundary that restricts the principal?
- Check SCPs: Is there an SCP on the account or OU that denies the action?
- Check session policies: If the principal assumed a role, was a session policy applied that restricts the action?
- Check the region: Some services (like S3 bucket creation) are region-specific. Ensure the policy applies to the correct region.
- Check conditions: Are there condition keys that are not being met (MFA, source IP, tags)?
- Use CloudTrail: Find the specific API call in CloudTrail. The error message often includes which policy denied access.
- Use Policy Simulator: Test the specific action with the IAM Policy Simulator to identify which policy is causing the denial.
Key Takeaways
Start with least privilege and use Access Analyzer to right-size permissions over time. Prefer IAM roles with temporary credentials over long-lived access keys in all cases. Use permission boundaries to safely delegate IAM administration to teams. Enforce organization-wide guardrails with SCPs. Centralize human access through IAM Identity Center with MFA required. Define all IAM resources in Infrastructure as Code for auditability and peer review. Monitor continuously with CloudTrail, Access Analyzer, and Config rules. IAM security is a continuous process, not a one-time setup. Invest in automation to maintain your security posture as your organization scales.
Key Takeaways
- 1Never use the root account for day-to-day operations; enable MFA immediately.
- 2Apply the principle of least privilege using IAM Access Analyzer and policy generation.
- 3Use IAM roles with temporary credentials instead of long-lived access keys.
- 4Permission boundaries enable safe delegation of IAM administration.
- 5Service Control Policies enforce guardrails across your entire organization.
- 6Continuously audit with CloudTrail, Access Analyzer, and credential reports.
Frequently Asked Questions
What is the principle of least privilege in AWS IAM?
Should I use IAM users or IAM roles?
What are AWS permission boundaries?
How do I audit IAM permissions in AWS?
What is the difference between SCPs and IAM policies?
How often should I rotate AWS access keys?
Written by CloudToolStack Team
Cloud engineers and architects with hands-on experience across AWS, Azure, and GCP. We write guides based on real-world production patterns, not just documentation rewrites.
Disclaimer: This guide is for educational purposes. Cloud services change frequently; always refer to official documentation for the latest information. AWS, Azure, and GCP are trademarks of their respective owners.