
AWS IAM Security Best Practices: The Enterprise Zero Trust Guide
Master AWS IAM security with enterprise Zero Trust practices for ABAC, OIDC, IMDSv2, SCPs, RCPs, detection, CI/CD guardrails, vendors, and IAM automation.
AWS IAM gets dangerous at scale because permissions outlive the context that justified them. A role is added, a vendor is connected, a microservice ships, and six months later nobody remembers why a policy still has broad access. Enterprise Zero Trust is not one policy. It is a system that makes access narrow, temporary, contextual, observable, and removable.
Table of Contents
- Multi-account foundation and continuous reduction
- Eliminate permanent human credentials
- Protect workload credentials with roles, IMDSv2, and Roles Anywhere
- Make authentication context part of authorization
- Scale least privilege with ABAC
- Defend resources, not just identities
- Prevent service-to-service confused deputy attacks
- Lock down third-party vendors with ExternalId
- Federate CI/CD with OIDC
- Enforce permissions boundaries
- Model privilege escalation beyond
iam:PassRole - Build a network-aware data perimeter
- Shift IAM security left into CI/CD
- Detect and respond to IAM abuse
- Handle leaked credentials like an incident
- Harden and centralize root access
- Continuously Reduce Permissions
The One-Page IAM Cheat Sheet
| Security problem | Enterprise control |
|---|---|
| Human long-term credentials | Federation + temporary STS sessions |
| Workload credentials | IAM roles + IMDSv2 |
| External/on-prem workloads | IAM Roles Anywhere |
| Role explosion | ABAC + governed tags |
| Sensitive data exposure | Resource policies + RCPs |
| Third-party SaaS access | sts:ExternalId |
| AWS service confused deputy | aws:SourceArn, aws:SourceAccount, aws:SourceOrgID |
| CI/CD credentials | OIDC federation |
| Delegated IAM administration | Enforced permissions boundaries |
| Privilege escalation | Graph/path analysis + dangerous-action controls |
| Network escape | VPC endpoint policies + aws:SourceVpce |
| Bad IaC | Checkov/tfsec/CloudFormation Guard + Access Analyzer |
| Credential misuse | CloudTrail + GuardDuty + EventBridge/CloudWatch |
| Posture drift | Config + Security Hub CSPM |
| Root risk | Centralized root access + phishing-resistant MFA |
| Permission entropy | Access Analyzer + regular removal |
1. Start With a Multi-Account Foundation—and Keep Permissions Shrinking
Accounts are stronger isolation boundaries than IAM policies inside one giant account. A mature AWS Organization normally separates management, security/audit, log archive, infrastructure, production, non-production, and sandbox workloads into purpose-built accounts and OUs.
SCPs define permission ceilings for principals in member accounts; they do not grant access, do not restrict the Organizations management account, and do not restrict service-linked roles. RCPs provide the resource-side complement, but only for supported services. Design the Organizations/OU structure before relying on either.
The same architecture needs a lifecycle. IAM Access Analyzer should validate policies before deployment and later help identify external, internal, and unused access. The operating loop is simple: Design → Test → Deploy → Observe → Reduce → Revalidate.

Enterprise AWS Organizations hierarchy showing how SCPs govern principals and RCPs govern protected resources across Security, Infrastructure, Workload, and Sandbox organizational units.
2. Eliminate Permanent Human Credentials
Human access should begin with your identity provider.
Not with:
1
2
3
CreateUser
CreateAccessKey
Send credentialsFor workforce access, prefer federation into temporary sessions.
AWS explicitly recommends federation and temporary credentials for human access.
The desirable lifecycle is:
Corporate identity → authentication → authorization → temporary role session → expiration
That last word matters.
Expiration is a security control.
A permanent access key remains useful until somebody notices and revokes it.
A temporary session dies on schedule.
This also enables cleaner privilege tiers.
An engineer might normally receive read-only access, temporarily elevate into a production-operator role during an incident, and use tightly controlled emergency access only under exceptional circumstances.
Do not turn today's requirement into next year's permanent entitlement.
3. Protect Workload Credentials With Roles, IMDSv2, and Roles Anywhere
Roles remove the need to store AWS secrets in
.env files, containers, build systems, repositories, or deployment scripts. They do not make role credentials impossible to steal.The Capital One breach is the classic lesson: an application-layer weakness and SSRF path were used to reach the EC2 metadata service, obtain temporary role credentials, and use permissions available to that role. The lesson is not that IMDSv2 alone would have prevented the entire incident; it is that temporary credentials still need delivery-path hardening and least privilege.
Require IMDSv2 for EC2:
1
2
3
4
5
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type c6i.large \
--metadata-options \
"HttpEndpoint=enabled,HttpTokens=required,HttpPutResponseHopLimit=2"For container hosts, the hop limit often needs to be
2; validate against your runtime. Enforce IMDSv2 through account defaults, IaC policy checks, Config/Control Tower controls where appropriate, and deployment standards.A role can still be dangerous if it contains:
1
2
3
4
5
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}Temporary credentials limit persistence. Least privilege limits blast radius.
For workloads outside AWS, do not jump straight to long-term keys. Prefer native workload identity, OIDC/SAML federation, or IAM Roles Anywhere with X.509 certificates and temporary role credentials.
4. Make Authentication Context Part of Authorization
"MFA enabled" is not the same as "MFA affects privilege." For IAM-user flows, sensitive actions can be denied when MFA context is absent:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenySensitiveActionsWithoutMFA",
"Effect": "Deny",
"Action": [
"ec2:TerminateInstances",
"iam:CreateAccessKey",
"iam:DeleteRole"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}aws:MultiFactorAuthPresent and aws:MultiFactorAuthAge do not behave the same way for federated or IAM Identity Center sessions. If MFA happens at the IdP, carry trusted authentication context into AWS through attributes or session tags instead of blindly copying an IAM-user condition.For Region restrictions, avoid hard-coding an incomplete
NotAction list of global services. Prefer a maintained Control Tower/Organizations control or a centrally managed baseline using aws:RequestedRegion.5. Scale Least Privilege With ABAC
RBAC becomes expensive when every team, service, and environment needs another role. ABAC lets one policy authorize resources dynamically from trusted attributes.
A principal tagged
Team=Payments can manage only resources with the same tag:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ManageInstancesOwnedBySameTeam",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:RebootInstances"
],
"Resource": "arn:aws:ec2:*:111122223333:instance/*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Team": "${aws:PrincipalTag/Team}"
}
}
}
]
}Now new
Team=Payments resources inherit the same authorization without editing ARN lists.Tag-on-create must also be enforced. For EC2, allow
CreateTags only during RunInstances and require the requested team to match the principal:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireTeamTagWhenLaunching",
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/Team": "${aws:PrincipalTag/Team}"
}
}
},
{
"Sid": "AllowTeamTagDuringLaunch",
"Effect": "Allow",
"Action": "ec2:CreateTags",
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:CreateAction": "RunInstances",
"aws:RequestTag/Team": "${aws:PrincipalTag/Team}"
}
}
}
]
}Protect authorization tags after creation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDirectModificationOfTeamTag",
"Effect": "Deny",
"Action": [
"ec2:CreateTags",
"ec2:DeleteTags"
],
"Resource": "arn:aws:ec2:*:111122223333:instance/*",
"Condition": {
"ForAnyValue:StringEquals": {
"aws:TagKeys": ["Team"]
},
"Null": {
"ec2:CreateAction": "true"
}
}
}
]
}Session tags can carry
Team, Department, or Environment from the IdP into STS sessions. If attributes need to survive role chaining, mark selected tags as transitive and authorize sts:TagSession.
AWS ABAC uses federated identity attributes and STS principal tags to automatically grant access only to resources with matching authorization tags.
6. Defend Resources, Not Just Identities
Identity policies answer what a principal may request. Resource policies answer who a resource will accept.
Within one account, applicable identity- and resource-based allows are generally evaluated as a union, subject to explicit denies and other controls. Cross-account access is different: the trusted account and the resource-owning account generally both need to authorize the interaction.
KMS is a notable special case because key policies are a mandatory part of authorization.
A sensitive S3 bucket can enforce an organization boundary directly:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyPrincipalsOutsideOrganization",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::company-sensitive-data",
"arn:aws:s3:::company-sensitive-data/*"
],
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalOrgID": "o-a1b2c3d4e5"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
}
]
}Resource-side denies give you a second boundary even when an identity is over-permissioned.
7. Prevent Service-to-Service Confused Deputy Attacks
Trusting an AWS service principal is not always enough. Where supported, constrain the source resource or account that caused the service to call you:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowServiceOnlyForMyResources",
"Effect": "Allow",
"Principal": {
"Service": "example-service.amazonaws.com"
},
"Action": "service:RequiredAction",
"Resource": "arn:aws:service:us-east-1:111122223333:resource/example",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "111122223333"
},
"ArnLike": {
"aws:SourceArn": "arn:aws:source-service:us-east-1:111122223333:*"
}
}
}
]
}At larger scale,
aws:SourceOrgID and aws:SourceOrgPaths can provide organization context. Support is service-specific, so verify the target service documentation.8. Lock Down Third-Party Vendors With ExternalId
A multi-tenant SaaS vendor that assumes roles in customer accounts should provide a unique
sts:ExternalId. A vendor trust policy can require both the vendor principal and the tenant-specific value:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowApprovedVendorTenant",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::444455556666:role/CustomerAccessBroker"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "7f8d2677-7d7c-45ab-a97d-cf95f3028ad1"
}
}
}
]
}ExternalId is tenancy context, not a password. Also restrict the vendor's actions, resources, session duration, logging path, and offboarding process.9. Federate CI/CD With OIDC Instead of Access Keys
GitHub Actions and other CI/CD systems should obtain short-lived AWS sessions instead of storing long-term keys. For GitHub, the trust policy must tightly restrict token claims, especially
sub:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::111122223333:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:<ORG>/<REPO>:ref:refs/heads/main"
}
}
}
]
}Validate the actual
sub your repository emits; GitHub Environments and newer subject formats can differ.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
name: deploy
on:
push:
branches: [main]
permissions:
contents: read
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: aws-actions/configure-aws-credentials@v6.3.0
with:
role-to-assume: arn:aws:iam::111122223333:role/github-production-deploy
aws-region: us-east-1
- run: aws sts get-caller-identityOIDC removes the stored AWS secret; it does not make an over-privileged deployment role safe.
10. Enforce Permissions Boundaries, Don't Just Attach Them
A permissions boundary is useful only if delegated administrators cannot create roles without it or remove it later.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowRoleCreationWithApprovedBoundary",
"Effect": "Allow",
"Action": "iam:CreateRole",
"Resource": "arn:aws:iam::111122223333:role/application/*",
"Condition": {
"ArnEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::111122223333:policy/ApplicationRoleBoundary"
}
}
},
{
"Sid": "DenyRemovingBoundary",
"Effect": "Deny",
"Action": "iam:DeleteRolePermissionsBoundary",
"Resource": "arn:aws:iam::111122223333:role/application/*"
}
]
}Also restrict who can modify the boundary policy itself and who may call
PutRolePermissionsBoundary.11. Model Privilege Escalation Beyond iam:PassRole
Privilege escalation is usually about combinations, not one permission. High-risk paths include:
iam:CreatePolicyVersioniam:AttachRolePolicyiam:PutRolePolicyiam:UpdateAssumeRolePolicylambda:UpdateFunctionCodessm:SendCommandiam:PassRolecombined with permissions to create or update a service that uses the passed role
Graph-oriented tools such as PMapper can reveal paths between principals and privileged actions; Cloudsplaining can flag least-privilege risks such as privilege escalation, data exfiltration, credential exposure, and resource exposure.
The better question is not only, "What can this principal do now?" It is "What could this principal become?"
12. Build a Network-Aware Data Perimeter
Identity is only one signal. Resource access can also be constrained using
aws:SourceVpc, aws:SourceVpce, aws:VpceAccount, aws:VpceOrgID, aws:ViaAWSService, and related conditions.A sensitive S3 bucket might deny direct access outside an approved VPC endpoint:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnexpectedNetworkPath",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::company-sensitive-data",
"arn:aws:s3:::company-sensitive-data/*"
],
"Condition": {
"StringNotEqualsIfExists": {
"aws:SourceVpce": "vpce-0123456789abcdef0"
},
"BoolIfExists": {
"aws:ViaAWSService": "false",
"aws:PrincipalIsAWSService": "false"
}
}
}
]
}AWS services can make downstream calls through Forward Access Sessions, where the original VPC context may not propagate. Account for
aws:ViaAWSService or aws:CalledVia when legitimate service-to-service workflows require it. VPC endpoint policies can add another gate by restricting which principals and resources may be reached through the endpoint.13. Shift IAM Security Left Into CI/CD
A pull request should fail before an unsafe IAM policy reaches AWS. Use IaC scanners such as Checkov or tfsec for infrastructure patterns, then use IAM Access Analyzer for policy-specific checks.
Validation:
1
2
3
aws accessanalyzer validate-policy \
--policy-document file://policy.json \
--policy-type IDENTITY_POLICYDetect permission expansion:
1
2
3
4
aws accessanalyzer check-no-new-access \
--existing-policy-document file://policy-before.json \
--new-policy-document file://policy-after.json \
--policy-type IDENTITY_POLICYAssert forbidden permissions are absent:
1
2
3
4
aws accessanalyzer check-access-not-granted \
--policy-document file://policy.json \
--policy-type IDENTITY_POLICY \
--access 'actions="iam:CreateUser","iam:AttachRolePolicy","organizations:LeaveOrganization"'A compact GitHub Actions gate can combine Checkov, OIDC, and Access Analyzer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
name: iam-security
on:
pull_request:
permissions:
contents: read
id-token: write
jobs:
iam-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Checkov
run: pip install checkov
- name: Scan Terraform
run: checkov -d . --framework terraform
- uses: aws-actions/configure-aws-credentials@v6.3.0
with:
role-to-assume: arn:aws:iam::111122223333:role/github-iam-validator
aws-region: us-east-1
- name: Validate policy
shell: bash
run: |
RESULT=$(aws accessanalyzer validate-policy \
--policy-document file://iam/policy.json \
--policy-type IDENTITY_POLICY)
echo "$RESULT"
echo "$RESULT" | jq -e '
[.findings[] |
select(.findingType == "ERROR" or
.findingType == "SECURITY_WARNING")] |
length == 0'
- name: Reject forbidden access
shell: bash
run: |
RESULT=$(aws accessanalyzer check-access-not-granted \
--policy-document file://iam/policy.json \
--policy-type IDENTITY_POLICY \
--access 'actions="iam:CreateAccessKey","iam:AttachRolePolicy","iam:CreatePolicyVersion"')
echo "$RESULT"
echo "$RESULT" | jq -e '.result == "PASS"'Not every
"Resource": "*" is automatically wrong; some AWS actions do not support resource-level authorization. Build exceptions from the Service Authorization Reference instead of using string matching as security policy.14. Detect IAM Abuse After Prevention Fails
This is the layer most IAM articles forget.
Prevention asks:
Should this happen?
Detection asks:
What if it did?
Your IAM architecture needs both.
CloudTrail is your identity flight recorder
CloudTrail records IAM and STS API activity, including assumed-role context.
For temporary credentials, CloudTrail's
userIdentity data can identify the role session and session issuer. STS sourceIdentity, when configured and propagated, can make role-chaining investigations substantially easier because it preserves information about the original identity.That means your investigation should be able to answer:
Who assumed the role?
From where?
When?
Using which source identity?
Which role session?
What APIs were called afterward?
Alert on root activity
Root should be so rare that use itself is a security event.
AWS Security Hub's CIS-aligned control uses a CloudTrail metric-filter pattern for root activity:
1
2
3
{$.userIdentity.type="Root" &&
$.userIdentity.invokedBy NOT EXISTS &&
$.eventType !="AwsServiceEvent"}Connect that metric to a CloudWatch alarm, SNS, incident-management platform, or SIEM.
Alert on IAM mutation
CloudTrail documents monitoring policy changes such as:
1
2
3
4
5
6
7
CreatePolicy
CreatePolicyVersion
PutRolePolicy
AttachRolePolicy
AttachUserPolicy
DeletePolicy
DetachRolePolicythrough CloudWatch Logs metric filters and alarms.
I would extend the enterprise detection set to include high-signal events such as:
1
2
3
4
5
6
7
CreateAccessKey
UpdateAssumeRolePolicy
PutRolePermissionsBoundary
DeleteRolePermissionsBoundary
CreateLoginProfile
DeactivateMFADevice
DeleteVirtualMFADeviceWhether each generates a page, ticket, or informational event depends on your environment.
EventBridge makes IAM changes routable
IAM API activity delivered through CloudTrail can be matched by EventBridge.
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"source": [
"aws.iam"
],
"detail-type": [
"AWS API Call via CloudTrail"
],
"detail": {
"eventSource": [
"iam.amazonaws.com"
],
"eventName": [
"CreateAccessKey",
"CreatePolicyVersion",
"AttachRolePolicy",
"UpdateAssumeRolePolicy",
"DeleteRolePermissionsBoundary"
]
}
}AWS documents the EventBridge pattern for routing specific IAM API calls from CloudTrail.
Do not alert on every AssumeRole
In a healthy AWS estate,
AssumeRole may happen thousands or millions of times.An alarm on every event becomes wallpaper.
Instead, detect unusual role usage.
Examples include:
a role used from a new ASN or geography, unusual API sequences, unusual role sessions, first-time access patterns, high-risk roles being assumed outside expected workflows, or role use inconsistent with the normal principal.
Amazon GuardDuty profiles API activity and can create anomalous-behavior findings based on user identity, API, location, user agent, and related behavior.
CloudTrail tells you what happened.
GuardDuty helps tell you what looks strange.
Config and Security Hub cover posture
Detection is also about configuration drift.
Security Hub CSPM currently includes IAM controls covering issues such as full administrative wildcard policies, root access keys, MFA, unused credentials, role tagging, and Access Analyzer.
AWS Config can continuously evaluate configuration rules, including root MFA controls.
These tools should feed a central security account or SIEM.
Do not leave security findings trapped inside twenty-seven individual AWS consoles.

AWS detection and response architecture combining CloudTrail, GuardDuty, Security Hub, Config, EventBridge, CloudWatch, and a central SIEM to identify, alert on, investigate, and respond to suspicious IAM activity.
15. Handle Leaked Credentials Like an Incident
Long-term credentials should be rare.
Rare does not mean impossible.
If you still maintain access keys, assume one will eventually appear somewhere it should not.
Use secret scanning in source control.
Monitor public exposure notifications.
And document the response before the incident.
When a key is suspected of compromise:
Deactivate it.
Identify the owning principal.
Review CloudTrail activity associated with it.
Determine what the principal could access.
Look for persistence mechanisms or privilege changes.
Replace the credential only if it is still legitimately required.
Then remove unnecessary access.
GuardDuty publishes guidance for investigating potentially compromised IAM credentials.
AWS also maintains
AWSCompromisedKeyQuarantineV3, a managed quarantine policy that AWS may apply when it determines an IAM user's credentials were exposed or compromised. AWS explicitly says not to simply remove that policy; follow the associated support instructions.Treat a leaked key as:
possible account compromise
not:
password rotation ticket.
16. Harden and Centralize Root Access
The root user should not be your super-admin account.
It should be a break-glass identity.
For accounts where root credentials remain, protect them with phishing-resistant MFA. AWS also provides Security Hub and Config controls specifically for root MFA and hardware MFA posture.
Do not create root access keys.
AWS explicitly recommends against root access keys because root has unrestricted account authority.
And alert whenever root is used.
But modern multi-account AWS environments can go further.
Centralize root access for member accounts
AWS Organizations now supports centralized root access management for member accounts.
Organizations can remove member-account root passwords, access keys, signing certificates, and MFA credentials and prevent member accounts from recovering normal root credentials. New organization member accounts can also be created without root credentials by default.
For the exceptional operations that really require root authority, authorized administrators can use centrally controlled privileged root sessions for supported tasks rather than maintaining everyday root credentials in every account.
That changes the model from:
protect 500 permanent root identities
to:
remove the permanent credentials and centrally broker exceptional root operations.
That is a much more scalable enterprise control.
17. Continuously Reduce Permissions
IAM is not finished when Terraform applies.
A perfectly justified permission today can become unnecessary in six months.
A role gets replaced.
A microservice changes.
A vendor contract ends.
A team migrates platforms.
The permission stays.
That is permission entropy.
IAM Access Analyzer should therefore exist at both ends of the lifecycle.
Before deployment:
validate policies.
check forbidden access.
detect permission expansion.
After deployment:
analyze external access.
review internal access.
identify unused roles and permissions.
generate tighter policies from observed activity where appropriate.
AWS explicitly recommends Access Analyzer for validation, least-privilege policy generation, public/cross-account access analysis, and unused-access review.
The mature IAM lifecycle is:
Design → Test → Deploy → Observe → Detect → Reduce → Revalidate
Not:
Create → Forget
What About Region Restrictions?
Region controls are useful.
But do not copy a five-line blog policy with an incomplete
NotAction list and assume the job is finished.aws:RequestedRegion policies need exceptions for global services, and the correct exception set changes as AWS services evolve.AWS's IAM documentation explicitly warns that global services require special handling. AWS Control Tower also provides maintained Region-deny controls for landing zones and individual OUs.
For enterprise environments, prefer a maintained organizational control or generate the policy from a controlled baseline rather than freezing an old list of global services inside a forgotten SCP.
The Enterprise Zero Trust Model for AWS
You can reduce this entire article to nine questions.
Identity: Who are you?
Authentication: How did you prove it?
Attributes: What context does your session carry?
Authorization: What may you request?
Resource: Will the resource accept this interaction?
Organization: Does this violate a global guardrail?
Network: Did the request arrive through an expected path?
Detection: Does the behavior look normal?
Lifecycle: Should this permission still exist?
Most IAM failures happen because organizations answer the first four and forget the rest.
Final AWS IAM Security Checklist
Before describing your AWS environment as Zero Trust, verify the entire system rather than one policy.
For humans, use federation, temporary sessions, phishing-resistant authentication, and short-lived privileged access. For AWS workloads, use roles, enforce IMDSv2, minimize the role's authority, and use IAM Roles Anywhere or federation instead of static keys for external workloads.
At scale, combine RBAC with ABAC, source authorization attributes from trusted systems, require tags at creation, and protect the tags that drive authorization. Use resource policies alongside identity policies, understand the difference between same-account and cross-account evaluation, and remember that KMS has special policy semantics.
For third parties, require narrowly scoped role trust and unique
sts:ExternalId values. For AWS services, constrain service principals with aws:SourceArn, aws:SourceAccount, or organization-level source conditions where supported. For GitHub Actions and other CI/CD systems, use OIDC instead of stored AWS keys and tightly scope token claims.Use permissions boundaries as enforceable ceilings for delegated IAM administration, not optional attachments. Model privilege-escalation paths beyond
iam:PassRole, including IAM policy mutation, trust-policy modification, code deployment into privileged workloads, and remote command capabilities.At the organization level, build the correct multi-account and OU structure before relying on SCPs or RCPs. Remember that SCPs do not constrain the management account or service-linked roles, and RCP service coverage is not universal.
At the network layer, use VPC endpoint policies and network-aware condition keys, but account for AWS service calls and Forward Access Sessions.
Before deployment, scan IaC and run Access Analyzer validation, no-new-access checks, and forbidden-access assertions. After deployment, collect CloudTrail centrally, use GuardDuty for anomalous activity, use Security Hub and Config for posture, and alert on high-risk IAM mutations and root activity.
And finally, practice credential response before credentials leak.
Because "verify continuously" is meaningless if nobody is watching.
The Principle That Matters
AWS IAM becomes difficult when organizations try to solve every security problem with another policy.
That is not the answer.
The answer is architecture.
Temporary credentials reduce persistence.
Least privilege reduces blast radius.
ABAC reduces policy sprawl.
Resource policies defend data.
SCPs and RCPs create ceilings.
OIDC removes CI/CD secrets.
External IDs isolate vendor tenants.
IMDSv2 hardens workload credentials.
VPC conditions constrain paths.
CI/CD checks prevent mistakes.
CloudTrail records reality.
GuardDuty looks for abnormal behavior.
Access Analyzer removes yesterday's privileges.
None of these controls is Zero Trust by itself.
Together, they create something much more useful:
Trust that is narrow.
Trust that has context.
Trust that expires.
Trust that is observable.
And most importantly:
Trust that can be revoked before a small mistake becomes a large breach.


AWS detection architecture combining CloudTrail, GuardDuty, Security Hub, Config, EventBridge, centralized SIEM monitoring, and incident response to identify and investigate suspicious IAM activity.

Simplified Capital One incident-learning flow illustrating how an application-layer compromise can escalate into cloud data access when metadata credentials and overly broad IAM permissions are involved.

GitHub Actions can securely access AWS through OIDC and short-lived STS credentials, with tightly scoped token claims and IAM validation before deployment.

AWS ABAC scales authorization by matching trusted principal attributes with resource tags, allowing access automatically when tags match and denying access when they do not.

AWS IAM evaluates same-account and cross-account requests differently: same-account permissions can come from applicable identity or resource policies, while cross-account access generally requires both sides to authorize the request.
AWS IAM security best practices: AWS IAM Security Best Practices
AWS IAM policy evaluation: AWS Policy Evaluation Logic
AWS data perimeters: AWS Data Perimeter Guidance
IAM Access Analyzer custom policy checks: Access Analyzer Policy Checks
AWS multi-account strategy: AWS Control Tower Multi-Account Strategy
IAM Roles Anywhere: IAM Roles Anywhere Guide
Centralized root management: Centralize Root Access
GitHub OIDC for AWS: GitHub OIDC AWS Guide

AWS human access should rely on federated identity and temporary roles rather than permanent IAM user credentials.

IAM privilege escalation often results from combinations of permissions that create a path to more privileged roles.

AWS authorization can depend on both identity and resource policies, with an explicit deny taking precedence.

Confused deputy protections constrain trusted AWS services so they can access only the intended account, resource, or organization.

A data perimeter combines identity, organizational boundaries, trusted network paths, and resource policies to control access to sensitive AWS data.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article