Join our Newsletter — 33% off our NHI Course
Home› Guides› AWS IAM Policies and Roles Guide: Policy Types…
Guide Cloud Security

AWS IAM Policies and Roles Guide: Policy Types and Trust Policies

← All guides
By Lalit Choda, NHI Mgmt Group Updated 18 October 2026 17 min read
On this page

Most AWS privilege problems are not caused by a missing control but by policies nobody can reason about: nine policy types, a trust policy on every role and an evaluation order that turns small wildcards into account-wide access. This guide goes below the account structure and into the policy language itself: which policy types exist and what each can and cannot do, how AWS evaluates a request, how role trust policies, AssumeRole and role chaining work, how permissions boundaries and iam:PassRole contain delegation, and how to analyse policies with IAM Access Analyzer and the policy simulator. It is for cloud security engineers and reviewers who approve IAM changes. For the wider picture see the AWS Security Guide.

Key takeaways

  • Only two policy types grant access. Identity-based and resource-based policies (including role trust policies) grant permissions; permissions boundaries, session policies, SCPs and RCPs only set ceilings.
  • An explicit deny always wins. AWS checks every policy for a matching Deny first; otherwise the request needs an Allow that survives every ceiling.
  • The trust policy is the front door of every role. Review who can call sts:AssumeRole as carefully as what the role can do.
  • Delegation needs two brakes. Let teams create roles only with a mandatory permissions boundary, and scope iam:PassRole to named roles and services, because passing a role is not logged as its own event.
  • Analyse with reasoning, not string matching. IAM Access Analyzer checks catch broad or deliberately hard-to-read policies that text search misses.

The policy types and what each can do

AWS IAM policies come in nine documented types. For each, ask whether it grants or only limits, and what it is attached to.

Policy typeAttached toGrants access?Notes for reviewers
Identity-based (AWS managed, customer managed, inline)IAM users, groups, rolesYesThe root user cannot have them
Resource-basedResources such as S3 buckets, KMS keys, SQS queues, and IAM roles (the trust policy)Yes, including to other accountsAlways inline; has a Principal element
VPC endpoint policyInterface or gateway endpointsNo, filters traffic through the endpointDefault policy "allows full access" if you do not attach one
Permissions boundaryA single user or role (uses a managed policy)NoCaps identity-based policies only
Session policyAn AssumeRole or federation session, passed as a parameterNoOne inline (Policy) and up to 10 managed (PolicyArns)
Service control policy (SCP)Organisation root, OU or accountNoLimits principals in member accounts, including each root user
Resource control policy (RCP)Organisation root, OU or accountNoLimits access to member account resources whoever the caller is
Access control list (ACL)S3, AWS WAF, VPCYes, cross-account onlyThe only type not written in JSON; cannot control same-account access
AWS RAM resource shareShared resourcesYes, to accounts, OUs or the organisationInclude RAM shares in access reviews

AWS managed, customer managed and inline policies

  • AWS managed policy: written and updated by AWS. "You cannot change the permissions defined in AWS managed policies", and when AWS updates one the change reaches every principal it is attached to. Job function policies such as ReadOnlyAccess grow as services are added: fine for people, wrong for workloads.
  • Customer managed policy: yours to write; it keeps up to five versions with one default, which gives a clean rollback path. The right container for least-privilege workload permissions.
  • IAM inline policy: embedded in one identity and "deleted when you delete the identity". AWS's own rule of thumb: "If a policy could apply to more than one entity, it's better to use a managed policy." Flag inline policies in reviews: they are missed by managed policy inventories.

IAM policy evaluation logic: how AWS evaluates a request

AWS starts from an implicit deny: "By default, all requests are implicitly denied with the exception of the AWS account root user, which has full access." It then works through the applicable policies in a fixed order.

  1. Explicit deny: every applicable policy is checked for a matching Deny; one match ends evaluation with Deny.
  2. RCPs: must allow the action on a member account resource.
  3. SCPs: must allow it for a member account principal.
  4. Resource-based policies: an Allow can end evaluation with Allow for some principal types.
  5. Identity-based policies: otherwise an Allow is needed here.
  6. Permissions boundaries: must also allow it, where set.
  7. Session policies: must also allow it, where passed.
CombinationResultWhat catches people out
Identity-based and resource-based, same accountUnionA bucket or key policy can grant access the identity policy never mentions
Identity-based and permissions boundaryIntersectionA boundary does not limit what a same-account resource policy grants directly to an IAM user ARN
Identity-based, SCP and RCPIntersectionThe management account is outside both SCPs and RCPs
Identity-based and session policyIntersectionA resource policy naming the role session ARN is not limited by an implicit deny in the boundary or session policy
Cross-account requestBoth accounts must allow"The request is allowed only if both evaluations return a decision of Allow."

Explicit deny is the only reliable way to guarantee something cannot happen; an absent Allow can be supplied by another policy. Conditions matter as much as actions: a statement applies only when its Condition is true, so a key that is absent for some callers changes the outcome. AWS warns, for example, that aws:MultiFactorAuthPresent is absent for long-term credentials and recommends BoolIfExists in Deny statements.

Role trust policies, AssumeRole and cross-account roles

Every IAM role has two policies. The IAM role trust policy is "a required resource-based policy" that names the principals allowed to assume the role; the permissions policy is the identity-based policy that defines what the assumed IAM role can do. IAM role assumption happens through STS AssumeRole (sts:AssumeRole), which returns temporary credentials for a role session, identified by an assumed-role ARN such as arn:aws:sts::111122223333:assumed-role/examplerole/session. Workload roles such as an EC2 IAM role (delivered through an instance profile) are covered in the Cloud Workload Identity Guide.

  • Who the principal is: a specific role ARN trusts only that principal. An account (arn:aws:iam::111122223333:root) hands the decision to that account's identity policies, so anyone there with sts:AssumeRole on * can use it. A wildcard principal without strong conditions trusts everyone.
  • Cross-account IAM role: the caller needs an identity-based Allow for sts:AssumeRole and the trust policy must allow the caller. Add aws:PrincipalOrgID or aws:PrincipalOrgPaths conditions so only principals in your organisation, or a specific OU, qualify.
  • Third parties and the confused deputy: to stop a vendor being coerced into acting on another customer's account, require sts:ExternalId, a value unique per customer and generated by the vendor, not by you. See the Third-Party Access Guide.
  • Service principals: where a policy trusts an AWS service, add aws:SourceArn or aws:SourceAccount so the service acts only for your resource.
  • Session length: sessions run from 900 seconds to the role's maximum of 1 to 12 hours (default one hour). Keep privileged roles short.

IAM role chaining and the one-hour limit

Role chaining "is when you use a role to assume a second role", for example a CI role assuming a deployment role in each target account. It "limits your AWS Management Console, AWS CLI or AWS API role session to a maximum of one hour", whatever the second role's maximum, and a chained AssumeRole asking for longer fails. The security issue is attribution: each hop creates a new session, so the identity that started an assume role chain is easy to lose. Follow each AssumeRole event back to the first long-term or federated credential, and keep chains short and documented so an unexpected hop stands out.

Permissions boundaries and iam:PassRole

A permissions boundary (often called a permission boundary) sets "the maximum permissions that an identity-based policy can grant to an IAM entity" and grants nothing itself. Its main job is safe delegation: letting a team create roles for its workloads without creating one more powerful than itself.

  1. Write a boundary policy that allows the services the team owns and nothing in IAM, Organizations or security logging.
  2. Allow the team iam:CreateRole, iam:PutRolePolicy, iam:AttachRolePolicy and iam:PutRolePermissionsBoundary only with the condition iam:PermissionsBoundary equal to that boundary's ARN, which is the pattern AWS documents for users.
  3. Deny iam:DeleteRolePermissionsBoundary and any edit to the boundary policy itself, so the ceiling cannot be removed or widened.
  4. Restrict role names to a prefix so the team cannot touch platform roles.

iam:PassRole is the other half. Services such as EC2, Lambda and CloudFormation accept a role ARN and check that the caller has iam:PassRole on it. AWS is explicit that "PassRole is not an API call. PassRole is a permission, meaning no CloudTrail logs are generated for IAM PassRole." Whoever can pass an administrator role to a new function is effectively an administrator. Scope the Resource to named role ARNs or a prefix, add iam:PassedToService to limit the service, and do not rely on resource tags, which AWS says "does not have reliable results" for PassRole. See the Cloud PAM and CIEM Guide.

Service control policies and resource control policies

Service control policies cap what principals in member accounts can do; resource control policies, launched by AWS on 13 November 2024 with support for S3, STS, KMS, SQS and Secrets Manager and since extended to many more services, cap what anyone can do to resources in member accounts. AWS's own split: "Use an SCP when you need to limit permissions of IAM principals within your organization's member accounts. Use an RCP when you need to restrict IAM principals that are external to your organization accounts making requests to access resources within your organization's member accounts."

  • Neither grants: "an RCP never grants permissions", and nor does an SCP.
  • Gaps: neither affects the management account or service-linked roles, and RCPs do not apply to AWS managed KMS keys.
  • Data perimeter pattern: an RCP that denies S3, KMS, Secrets Manager or STS access when aws:PrincipalOrgID is not your organisation stops a misconfigured bucket or key policy granting outsiders access. Exempt AWS service principals with aws:PrincipalIsAWSService.
  • Testing: the policy simulator can include SCPs but "does not support resource control policies (RCPs)", so test RCPs on a low OU with CloudTrail review rather than simulation.

IAM condition keys that do the most work

Condition keyUse it toWatch for
aws:PrincipalOrgID, aws:PrincipalOrgPathsLimit resource and trust policies to your organisation or an OUService principals do not carry an organisation ID
aws:SourceArn, aws:SourceAccount, aws:SourceOrgIDPrevent cross-service confused deputy when trusting a service principalMissing on older bucket and key policies
sts:ExternalIdBind a third-party role to one customer relationshipValue must come from the vendor, not be chosen by you
aws:SourceVpceRequire access through a specific VPC endpointPairs with endpoint policies; see the network design
aws:SourceIpRestrict public source ranges"Can only be used for public IP address ranges" and is absent through a VPC endpoint
aws:MultiFactorAuthPresentRequire MFA for sensitive actionsUse BoolIfExists; plain Bool is "NOT RECOMMENDED"

IAM policy size limits and quotas

When a team hits a size limit, the easy fix is a wildcard, which is how many overly permissive IAM policies start. Character limits "can't be increased"; white space is not counted.

QuotaValue
Customer managed policy size6,144 characters
Inline policies, aggregate per entityUser 2,048; group 5,120; role 10,240 characters
Role trust policy length2,048 characters default, adjustable to 8,192
Managed policies attachedRole 20 default, 25 maximum; user 10 default, 20 maximum; group 10
Session policy2,048 characters for the JSON policy plus managed policy ARNs combined; up to 10 ARNs
Roles per account1,000 default, 10,000 maximum
Customer managed policies per account1,500 default, 10,000 maximum

When a workload needs more, split permissions across customer managed policies by service rather than collapsing to service:*.

IAM policy analysis: finding overly permissive and obfuscated policies

Set the IAM Access Analyzer zone of trust to the organisation so findings mean "outside the organisation".

  • External access analysis: resource policies, including role trust policies, granting access outside the zone of trust.
  • Internal access analysis: which internal principals can reach selected critical resources such as S3 buckets and DynamoDB tables.
  • Unused access analysis: unused roles, keys and passwords, and unused actions on active roles: the most direct way to shrink over-privileged IAM roles.
  • Policy validation: grammar and best-practice checks returning security warnings, errors, general warnings and suggestions.
  • Custom policy checks: CheckNoNewAccess (does an updated policy grant new access compared with the current one), CheckAccessNotGranted (are named critical actions or resources excluded) and CheckNoPublicAccess (can a resource policy grant public access). Run them in the pipeline on every IAM change; checks for new access are charged.
  • Policy generation: a draft least-privilege policy built from CloudTrail activity.

The IAM policy simulator answers "would this principal be allowed this action" without making a real request. It tests identity-based policies, one boundary at a time, SCPs and resource policies you supply, but not RCPs, and results can differ for VPC endpoint policies, role chaining and multiple resource policies on one resource.

IAM policy obfuscation

An obfuscated IAM policy is one written to be hard to read on purpose, so that a reviewer or keyword alert misses a dangerous grant. The policy language allows forms that defeat text search: action names are case insensitive ("iam:ListAccessKeys is the same as IAM:listaccesskeys"), wildcards can sit inside action names (iam:*AccessKey*, or ? for one character), NotAction and NotResource grant everything except a list, and a grant can be split across several statements, policies or policy versions. The defence is to stop reviewing strings. Normalise policies before comparison (lower-case actions, expand wildcards against the service action list, resolve NotAction), flag any NotAction with Allow for manual review, and rely on reasoning-based checks such as CheckAccessNotGranted for your list of sensitive actions (iam:PassRole, iam:CreatePolicyVersion, iam:UpdateAssumeRolePolicy, sts:AssumeRole on *), which evaluate what a policy allows rather than how it is written.

Implementation roadmap

  1. Inventory: export every role with its policies, boundary and last-used data, and tag an owner. See the NHI Ownership Guide.
  2. Turn on analysis: create organisation-wide external and unused access analysers; triage external trust findings first.
  3. Fix trust policies: replace account-root and wildcard principals with specific ARNs, add organisation, external ID and source conditions, and shorten privileged sessions.
  4. Gate changes in the pipeline: run policy validation and CheckNoNewAccess or CheckAccessNotGranted on every pull request that touches IAM, starting in report-only mode for two to four weeks before blocking.
  5. Right-size: replace broad AWS managed policies on workload roles with generated customer managed policies, one workload at a time, watching CloudTrail for AccessDenied errors.
  6. Delegate and guard: introduce boundaries and scoped PassRole, then deny-based SCPs and an RCP data perimeter, tested on a low OU first.

Rollback: customer managed policy changes roll back by setting the previous version as default; boundaries and SCPs roll back by detaching them. Keep policy JSON in source control so a revert is a reviewed change.

Decision guidance

  • Role or resource policy for cross-account access: use a role when the other account needs several actions across resources. Use a resource-based policy for a single bucket, key or queue, backed by an RCP.
  • Boundary or SCP: SCPs suit organisation-wide rules that apply to everyone in an account. Boundaries suit rules for a subset of roles inside an account, such as those created by a delegated team.
  • Managed or inline: default to customer managed. Use inline only when the permission must disappear with the identity.
  • Small estates can rely on Access Analyzer, scoped PassRole and a few deny SCPs. Large estates need pipeline checks, boundaries, RCPs and entitlement analysis that follows role chains across accounts.

Detection and measurement

Threat (ATT&CK v20)CloudTrail events and signalsPrimary control
T1098.003 Additional Cloud RolesCreatePolicyVersion with default set, SetDefaultPolicyVersion, AttachRolePolicy, PutRolePolicy, AttachUserPolicyBoundaries, SCP deny on IAM changes outside pipelines
T1098.003 via trust changesUpdateAssumeRolePolicy, CreateRole with an external principal, new Access Analyzer external findingsTrust policy review, aws:PrincipalOrgID
T1078.004 Valid Accounts: Cloud AccountsAssumeRole from unfamiliar accounts, networks or source identities; first use of dormant rolesUnused access removal, short sessions
Boundary removalDeleteRolePermissionsBoundary, PutRolePermissionsBoundary with a different ARNDeny on boundary changes
PassRole abuseNo PassRole event; watch CreateFunction, RunInstances and CreateStack that reference privileged role ARNsScoped PassRole, iam:PassedToService
  • External trust: active Access Analyzer external access findings on roles (target zero unexplained).
  • Unused permissions: share of roles with unused access findings, and median days to close.
  • Broad grants: count of policies with Action: "*", NotAction with Allow, or unscoped iam:PassRole.
  • Pipeline coverage: share of IAM changes checked before deployment.
  • Delegation safety: percentage of team-created roles carrying the required boundary (target 100).

Common failure patterns

  • Over-permissive EC2 IAM role: an instance role that can list and read every bucket turns one server-side flaw into a data breach, as in the Capital One breach, where a firewall's role credentials were taken from the metadata service.
  • Misconfigured IAM role trust: a cross-account role trusts a partner account's :root, so any principal there with broad STS permissions can assume it.
  • Unscoped PassRole: developers with iam:PassRole on * attach an administrator role to a function they control, and no PassRole event exists to alert on.
  • Boundary without a lock: a boundary is required at creation but nothing denies removing it later.
  • Long-lived keys with broad policies: a compromised key bound to an over-permissive IAM policy is abused fast: the AWS crypto-mining campaign had miners running within minutes. See the API Key Management Guide.

Framework mapping

Control areaNIST SP 800-53 Rev. 5CIS Controls v8.1ISO/IEC 27001:2022ATT&CK
Least-privilege policies, boundaries, PassRole scopingAC-6, AC-36.8A.5.15, A.8.2T1098.003
Role inventory, ownership, unused access removalAC-25.1, 5.3A.5.16, A.5.18T1078.004
Trust policies and cross-account accessAC-3, AC-206.1A.5.19, A.8.3T1078.004
Pipeline policy checks and change controlCM-3, CM-54.1A.8.32T1098.003
CloudTrail monitoring of IAM changesAU-6, AU-128.2, 8.11A.8.15, A.8.16T1098.003

Practitioner checklist

  • Inventory every role with its trust policy, permissions, boundary, owner and last-used date.
  • Replace wildcard and account-root principals in trust policies with specific ARNs plus organisation conditions.
  • Require sts:ExternalId on third-party roles and source conditions on service principal grants.
  • Scope iam:PassRole to named roles with iam:PassedToService; never allow it on *.
  • Enforce a permissions boundary on delegated role creation and deny its removal.
  • Run policy validation and custom policy checks on every IAM change in the pipeline.
  • Review unused access findings monthly and remove unused roles and actions.
  • Flag NotAction with Allow, Action: "*" and normalised sensitive actions for manual review.
  • Alert on policy version, trust policy and boundary changes outside the deployment pipeline.

Standards and references

Related NHI Mgmt Group resources: AWS Security Guide · Cloud Workload Identity Guide · Cloud PAM and CIEM Guide · Multi-Cloud Identity Guide · Service Account Security Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 18 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org