AWS 251: Permission boundaries and session policies
Why this matters to an architect
Enterprise teams often delegate role creation while retaining a centrally governed maximum. A permissions boundary can make that delegation safe - but only if administrators understand that a boundary limits identity-policy grants and does not grant anything itself. Session policies narrow temporary credentials for one session; they cannot expand the role or federated identity that produced them.
The simplistic formula “identity ∩ boundary ∩ session ∩ SCP” is a useful start but not a complete authorization model. Resource-based policies, principal type, same-account versus cross-account requests, service control policies (SCPs), resource control policies (RCPs), endpoint policies, KMS key policies, conditions, and explicit denies can change the result. This lesson teaches the calculation without hiding those exceptions.
Outcomes
By the end, you can:
- distinguish a grant, maximum-permission guardrail, session limiter, trust policy, and resource guardrail;
- calculate four supplied requests across identity, boundary, session, SCP, RCP, and resource policies;
- explain same-account IAM user, IAM role ARN, assumed-role session ARN, and federated-user session behavior;
- design delegated role creation that requires an approved boundary and prevents its removal;
- use policy simulation and CloudTrail as evidence while stating their limitations;
- diagnose implicit deny, explicit deny, missing context, role trust, and
PackedPolicySizefailures; - reject
NotPrincipal+Denypatterns that interact dangerously with bounded principals.
A short history and vocabulary
IAM began with identity and resource policies, then expanded to temporary STS sessions, Organizations guardrails, permissions boundaries, attribute-based access, and resource control policies. More layers allow enterprise delegation but also make “the policy says Allow” an incomplete statement.
| Policy/control | Attached/applied to | Can grant? | Primary purpose |
|---|---|---|---|
| identity policy | user/group/role | yes | principal actions/resources |
| resource policy | bucket, key, queue, role trust, etc. | yes, service-dependent | who can access that resource |
| permissions boundary | IAM user or role | no | maximum identity-policy permissions |
| session policy | STS role/federated session | no expansion | narrow one temporary session |
| SCP | organization root/OU/account | no | maximum permissions for member-account principals |
| RCP | organization root/OU/account | no | maximum permissions to member-account resources |
| role trust policy | IAM role resource policy | permits assumption | who/how may obtain role sessions |
| VPC endpoint policy | endpoint | no standalone identity grant | constrain requests through endpoint |
| KMS key policy/grant | KMS key | key-side authorization | who may administer/use key |
An explicit deny in any applicable policy wins. An implicit deny means no applicable allow survived all required limiting layers.
Start with the request context
Do not begin by reading random policies. Write the exact request:
principal/session ARN
account and organization path
action
resource ARN and resource account
Region and network path
request/session/resource/principal tags
MFA, source identity, external ID, source ARN/account
service-specific and global condition keys
Then identify every applicable policy source. A missing context value can make a conditional allow fail. Some services require multiple resource types or dependent actions; “the main action is allowed” may still be insufficient.
Boundaries: delegated maximum, not a grant
For ordinary identity-based authorization:
effective identity permission = identity-policy allows
∩ boundary allows
∩ session-policy allows (when present)
∩ SCP allows (when applicable)
If the developer policy grants s3:* but the boundary allows only s3:GetObject on arn:aws:s3:::team-data/*, the principal can receive at most that bounded object-read permission. If no identity policy grants GetObject, attaching the boundary still grants nothing.
A safe delegated-role design also constrains the delegator:
- allow role creation only with the approved boundary ARN (
iam:PermissionsBoundarycondition); - allow attaching only approved managed policies/paths/tags;
- restrict
iam:PassRoleby exact role/path andiam:PassedToService; - deny removing/changing the required boundary;
- prevent editing boundary policy versions/defaults;
- control trust policies so delegates cannot create an assumable privilege path;
- monitor IAM changes in CloudTrail/Config and test escape paths.
The boundary must cover permissions that delegated policies could otherwise grant, including IAM mutation, Organizations, KMS, STS, resource policies, and pass-role paths as appropriate. A weak delegation policy around a good boundary is still unsafe.
Session policies
An STS caller can optionally pass one inline session policy and up to ten managed session-policy ARNs (for operations that support them). Their permissions intersect with the role's identity policies; they cannot grant beyond the role. The combined plaintext for the inline policy and managed-policy ARN characters is limited to 2,048 characters. AWS also packs policies and session tags into a binary representation with a separate limit; inspect the STS utilization/size response rather than assuming plaintext success guarantees packing success.
Example: a deployment role can read every project artifact, but the CI job assumes it with a session policy allowing only one release prefix. Stolen job credentials then have a narrower scope for that session. The permanent role remains unchanged.
Session tags can drive ABAC through aws:PrincipalTag, but control who may call sts:TagSession, which tag keys/values may pass, and whether transitive tags survive role chaining. Do not let a caller self-assert Environment=prod without trusted IdP/mapping controls.
The resource-policy nuance
Resource policies require careful principal classification:
- A same-account resource-policy grant to an IAM role ARN is still limited by implicit denies in that role's boundary or session policy.
- A same-account grant directly to an assumed-role session ARN grants to that session; implicit denies in identity policy, boundary, or session policy do not limit that direct grant. Explicit denies and organization/resource controls still matter. AWS recommends role principals rather than session principals where possible.
- A same-account grant to an IAM user ARN is not limited by an implicit deny in that user's identity policy or boundary, though explicit denies still apply.
- Cross-account access normally requires the trusting resource/account side and the trusted principal/account side to permit the request.
- Service-specific policy semantics still apply; KMS authorization is not interchangeable with an S3 bucket-policy example.
Do not generalize one diagram to every principal/resource combination.
Dangerous NotPrincipal deny
AWS warns against resource-policy statements combining Effect: Deny with NotPrincipal for IAM users or roles that have a permissions boundary. Such a statement can deny bounded principals regardless of the values in NotPrincipal. Prefer a condition such as ArnNotEquals with aws:PrincipalArn where it correctly expresses the control, and test exact principals/context.
SCPs and RCPs
SCPs limit principals in member accounts; they do not grant permissions. RCPs limit access to resources in member accounts and can affect principals outside the organization. Applicable allows must survive these organization guardrails, and explicit denies win. Management-account and service-linked-role exceptions differ by control type, so check current Organizations documentation rather than assuming “SCP affects everything.”
An account administrator cannot override an organization explicit deny by adding an identity or bucket-policy allow. Diagnose with organization path, policy inheritance, conditions, principal type, resource account, and service support.
Evaluation workflow
- Authenticate the principal and identify the actual session ARN.
- Normalize action, resource(s), accounts, Region, and request context.
- Check explicit denies across applicable policy/control types.
- Find a valid grant from identity and/or resource policy according to principal/account semantics.
- Apply boundary and session intersections where they limit that grant.
- Apply SCP/RCP and service-specific guards.
- Evaluate conditions with actual context values.
- Confirm dependent actions/resource types.
- Compare simulation, CloudTrail denial, and a safe live positive/negative test.
“Allow in one policy” is only one row in this workflow.
Practical lab
Download the AWS251 policy-evaluation pack. It contains:
POLICY_EVALUATION_WORKBOOK.md;SUPPLIED_POLICY_CASES.mdwith four complete policy/request sets;DELEGATED_ROLE_GUARDRAIL.mdfor boundary-enforced role creation;ANSWER_DIRECTIONS.md, opened only after calculation.
For each case, build a table with principal, action, resource, context, identity allow/deny, boundary allow/deny, session allow/deny, SCP, RCP, resource policy, service control, and final result. Label whether the denial is explicit or implicit and identify the smallest safe correction. Include one expected positive and one unauthorized negative test.
Read-only CLI evidence
With owner permission, IAM is global but requests/resources can include Region context:
aws sts get-caller-identity
aws iam get-role --role-name replace-me
aws iam list-attached-role-policies --role-name replace-me
aws iam list-role-policies --role-name replace-me
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::REDACTED:role/replace-me \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::example-bucket/example-key
Retrieve each managed policy's default version and inline policy separately. get-role shows the boundary and trust policy, not all effective permissions. The simulator does not make a service request, does not supply all live context automatically, does not support RCPs, and can differ for endpoint policies, role chaining, or multiple resource policies. Treat it as preflight evidence, then use CloudTrail and tightly scoped live positive/negative tests where authorized.
Troubleshooting table
| Symptom | Evidence | Likely issue |
|---|---|---|
| boundary attached but no access | identity/resource grant | boundary is not a grant |
| role allows action, session denied | STS call/session policy | session narrowed role |
| AssumeRole denied | caller policy + trust + conditions | assumption path, not role workload policy |
| API denied only in member account | OU/account SCP | organization guardrail |
| resource grant behaves unexpectedly | exact principal ARN type | role versus session/user semantics |
| simulator allow, live deny | missing context/RCP/endpoint/service layer | simulator coverage gap |
| STS request rejected for size | plaintext and packed/session-tag utilization | session policy/tag quota |
| bounded role unexpectedly denied by resource policy | NotPrincipal + Deny | documented boundary interaction |
Cost, logging, and cleanup
IAM, STS, boundaries, and policy simulation generally have no separate hourly resource charge, but CloudTrail data storage/query, Config evaluations, access-analysis workflows, third-party IdP, and operational investigation can cost money. Bad authorization design costs outages and escalation time.
The supplied track creates nothing. If a sandbox test is approved, delete only course-owned users/roles/policies after dependency and last-access review, revoke sessions where appropriate, remove test resource policies, retain redacted CloudTrail evidence under policy, and prove final inventory. Never detach a production boundary as a troubleshooting experiment.
Knowledge check
- Why can a boundary allow
s3:GetObjectyet the request remain denied? - How does a session policy differ from a role identity policy?
- Why does principal ARN type matter for same-account resource-policy grants?
- Why is
NotPrincipalwithDenydangerous for bounded IAM principals? - What do SCPs and RCPs limit, and why do neither grant access?
- Which live-context gaps can make simulator and real results differ?
- How can a delegated creator remove or bypass a boundary if surrounding IAM permissions are weak?
- Why must an architect test both authorized and unauthorized requests?
Lesson acceptance
Pass requires correct outcomes and reasoning for all four supplied cases, a complete policy-layer matrix, explicit/implicit deny distinction, principal-ARN analysis, safe delegated-role design, simulator limitation statement, CloudTrail evidence plan, positive/negative tests, and no-create or verified cleanup proof.