Amazon AWS SCS-C03: IAM Policy Evaluation in Practice
AWS IAM policy evaluation is easiest to understand as a set of overlapping permission filters. A request is not authorized because one policy says “Allow.” AWS evaluates the principal, action, resource, context, identity-based policies, resource-based policies, permissions boundary where present, session policies, service control policies, resource control policies where applicable, and any explicit deny. The effective permission is the result of all relevant policy types.
AWS currently documents the core rules clearly: explicit deny overrides allow; identity and resource policies can combine to grant access in many same-account scenarios; a permissions boundary limits the maximum permissions of a user or role; SCPs and RCPs create organization-level maximums; and session policies can further restrict temporary credentials. The details differ for resource-based policies and role sessions, which is why troubleshooting should start from the exact principal ARN and request context.
Policy evaluation belongs inside AWS Security Engineering.
Begin with the request context
Write down principal, action, resource ARN, account, Region, source network, tags, MFA state, and any other condition keys relevant to the request.
IAM policy models become much easier when teams reason about one concrete request rather than reading large JSON documents in isolation.
The same principal can receive different outcomes for two resources because conditions or resource policies differ.
Explicit deny wins
If any applicable policy type explicitly denies the request, AWS denies it even when another policy allows it.
This applies to identity policies, resource policies, SCPs, RCPs, permissions boundaries, and session policies in their relevant evaluation paths.
During troubleshooting, search for explicit denies before adding more allow statements that cannot override them.
Understand identity and resource policies
Identity-based policies are attached to IAM identities, while resource-based policies are attached to supported resources such as S3 buckets, KMS keys, queues, or topics.
In many same-account scenarios, permissions from the two types combine as a union unless another limiting policy or explicit deny applies.
Cross-account access normally requires trust on both sides: the principal must be allowed to act and the resource account must allow the external principal.
Use boundaries as permission ceilings
A permissions boundary does not grant anything.
Permissions boundaries define the maximum permissions that identity-based policies can give an IAM user or role.
A developer can attach an Administrator-like policy to a bounded role and still be unable to exceed the boundary, provided the surrounding resource policies and session semantics are designed correctly.
Account for Organizations policies
SCPs limit what principals in member accounts can do, while RCPs can limit what principals can do to covered resources according to current AWS Organizations behavior.
AWS governance uses these policies as organization guardrails rather than workload permissions.
If the applicable SCP/RCP path does not permit an action, a local IAM administrator cannot restore that permission by attaching another identity policy.
Remember session policies
Temporary credentials can be restricted by inline or managed session policies supplied when a role session is created.
Session policies intersect with the role’s identity permissions; they do not add permissions beyond what the role already allows.
Federation systems and brokers should keep session-policy generation visible enough that operators can explain why one session has less access than another using the same role.
Read conditions as part of the grant
Conditions can require tags, organization ID, VPC endpoint, source account, MFA, principal attributes, time, encryption context, or other supported request keys.
Two otherwise identical allow statements can behave differently because one condition does not match the request.
Use policy simulation and service-specific access analyzers where available, but verify the real request context when a production call still differs from the test.
Trace cross-account access from both sides
Cross-account troubleshooting should inspect the principal account, organization guardrails, role/session constraints, and resource policy in the target account.
For KMS, S3, SQS, SNS, and similar services, the resource-side policy can be the decisive boundary.
Cross-account data protection should preserve least privilege in both accounts rather than place one wildcard allow in the resource policy.
Use denial evidence before changing policy
CloudTrail, encoded authorization messages where supported, Access Analyzer, and service error context can narrow the denying layer.
For SCS-C03, the durable model is explicit deny → organization guardrails → boundary/session maximums → identity/resource allows → conditions → exact request context.
Policy evaluation stops being mysterious when every permission is treated as part of a layered authorization system rather than one JSON document.
The default state in IAM is implicit deny. If no applicable policy grants the request, AWS denies it. This is distinct from an explicit deny: implicit deny can be overcome by an applicable allow, while explicit deny cannot. Troubleshooting should identify which of these cases applies before engineers start editing policies.
Identity-based and resource-based policies are not symmetrical in every scenario. Resource policies that grant to a role session, federated session, or IAM user ARN can interact with permissions boundaries and session policies differently from policies that grant to the underlying role ARN. AWS documents these nuances in the permissions-boundary guidance, which is why high-risk resource policies should avoid broad session-principal grants unless the behavior is intentionally understood.
Role assumption creates a new principal context. The trust policy answers who may obtain the role session; the role’s identity policies, boundary, session policies, SCPs, and resource policies shape what that session can do. A correct permission policy on a role is useless if the trust policy lets an unintended external principal assume it.
iam:PassRole deserves special attention because it lets a principal give an IAM role to an AWS service. A developer who cannot call KMS directly might still create a Lambda function that runs with a powerful role if PassRole is too broad. Restrict PassRole to intended roles and, where useful, intended AWS services.
Service-linked roles add another layer. AWS services create or use roles with defined trust and permissions so they can operate on the customer’s behalf. Security teams should understand which service-linked roles are expected and avoid deleting or editing them casually during permission cleanup.
Condition keys can introduce hidden dependencies on tags. ABAC can scale authorization elegantly, but if users can change the resource tag that grants them access, the authorization model collapses. Protect authorization-sensitive tags through IAM, SCP, resource policy, or controlled deployment pipelines.
aws:PrincipalOrgID and organization-related condition keys can reduce cross-account policy sprawl by limiting resource access to principals from the enterprise organization. They are strong outer constraints, but they still trust every principal inside the permitted organization unless combined with narrower identity or account conditions.
Source-account and source-ARN conditions are important for service-to-service access. They can reduce confused-deputy risk when an AWS service calls a resource on behalf of a customer. Resource-policy designs should use the service’s documented condition pattern rather than rely on wildcard service principals alone.
Policy variables and wildcards should be used carefully. A short wildcard policy is easy to write and hard to reason about when AWS adds new APIs or resource types. For sensitive administrators, exact actions and resources are often worth the additional policy length because future privilege does not appear silently.
SCP troubleshooting should include the full OU inheritance path. A member account can inherit multiple SCPs from root and parent OUs. Moving the account between OUs is itself a security change because it can alter the maximum permission set instantly even though no IAM policy inside the account changed.
RCPs similarly add resource-centric organization limits where supported. They are useful for organization-wide resource guardrails, but their presence means the effective permission may be denied outside the account’s local IAM view. Central governance teams should make applicable organization policies visible to workload administrators to reduce confusion.
AWS IAM Access Analyzer policy validation can detect syntax issues and many risky policy patterns before deployment. Access Analyzer can also reason about external access for supported resource policies. These tools reduce manual review effort, but they do not know the business intent behind a technically valid grant.
The IAM Policy Simulator is useful for exploring identity-policy decisions but is not a complete reproduction of every service authorization path. Production troubleshooting should still inspect CloudTrail, resource policies, SCPs/RCPs, session context, permissions boundaries, and service-specific behavior.
Encoded authorization failure messages in supported AWS APIs can be decoded by a principal with appropriate STS permissions and can reveal which policy type contributed to denial. They are valuable when an EC2-style authorization error provides too little context for normal troubleshooting.
For security engineers, a repeatable worksheet helps: principal ARN, session ARN, action, resource, identity policies, boundary, session policy, SCP, RCP, resource policy, conditions, explicit denies. Filling this out turns complicated authorization into a deterministic analysis rather than a sequence of speculative policy edits.
Resource ownership should be included in authorization review. A technically valid S3 bucket policy that trusts an entire organization may still be too broad for one sensitive dataset. Policy evaluation tells you whether AWS will allow the request; security architecture must still decide whether the request should be possible from the business point of view.
Permission troubleshooting should preserve least privilege. When one API call fails, add or modify only the action and resource needed for the workflow instead of attaching a broad managed policy to “see if it works.” Broad temporary grants often become permanent and make later evaluation harder because many unrelated allows overlap.
Keep policy source under version control where possible. IAM roles, SCPs, boundaries, resource policies, and trust policies are easier to audit when changes can be reviewed as code and tied to a deployment. Manual console edits create the hardest kind of access problem: permissions that changed without the owning application team knowing why.