AWS IAM Policy Evaluation: Architecture and Trade-Offs
AWS IAM authorization becomes difficult when teams treat “the IAM policy” as one document. In a real AWS request, several policy types can participate: identity-based policies, resource-based policies, permissions boundaries, session policies, AWS Organizations service control policies (SCPs), resource control policies (RCPs), VPC endpoint policies, and service-specific controls. The effective decision depends on the request context and the way those policy layers combine.
This is why IAM policy evaluation deserves architecture-level treatment. The goal is not to memorize a single flowchart. It is to know which policies can grant, which only limit, where explicit deny wins, and how account boundaries change the evaluation. Those decisions matter across AWS architecture, security, networking, operations, and application design.
AWS builds a request context when an authenticated principal attempts an action. AWS documentation describes the core reasoning through Principal, Action, Resource, and Condition—the PARC model. Additional context can include tags, source IP information, organization identifiers, session attributes, network information, and service-specific keys.
The first architecture question is therefore: who is asking to do what, to which resource, under which conditions? A policy statement that looks permissive in isolation may not apply to the request because the resource does not match or a condition fails. Another statement may apply an explicit deny because a network, tag, region, or organization condition is present.
Cloud identity and access starts with roles, policies, service identities, and least privilege. AWS-specific policy evaluation extends those principles with a rich set of policy layers and cross-account rules.
AWS authorization begins from implicit deny. If no applicable policy produces the required allow under the evaluation rules, the request is denied. An explicit Deny that applies to the request overrides an Allow.
That simple rule is important because many troubleshooting mistakes start with “I found an Allow, so this should work.” An allow may be limited by a permissions boundary, session policy, SCP, RCP, or another applicable control. It may also be defeated by an explicit deny elsewhere.
When diagnosing access, search for the most restrictive applicable layer before expanding permissions. Adding another identity policy will not fix an SCP deny. Broadening an S3 bucket policy will not help if the request is blocked by a VPC endpoint policy. Architecture determines which control owns the decision.
Within the same account, AWS generally evaluates identity-based and resource-based permissions so that an allowed action can be granted by one or the other, subject to important principal and service nuances. An explicit deny in either still overrides the allow.
Permissions boundaries behave differently. A boundary defines the maximum permissions an IAM user or role can receive from identity-based policies; it does not grant permissions by itself. For those identity permissions, the effective set is the intersection of what the identity policy allows and what the boundary allows.
This distinction is useful in delegated administration. A platform team can let application teams create or attach policies while a boundary prevents those policies from exceeding an approved ceiling. The trade-off is complexity: when a developer sees an Allow attached to a role, the boundary may make the resulting permission smaller than the role policy suggests.
When a role or federated user receives a temporary session, session policies can further restrict what that session can do. Like permissions boundaries, they limit rather than grant the underlying identity permissions.
This can be valuable for just-in-time workflows. A role might be broadly capable enough for several operational tasks, while a specific automation or session receives a policy that limits it to the task being performed. The blast radius of temporary credentials is reduced without creating a new permanent role for every narrow operation.
The trade-off is observability and support. Administrators diagnosing a denied request need to know which session was created, what session policy was passed, which role policies apply, and whether other guardrails also participate. Good architecture records that context rather than leaving support teams to infer it from the role name.
AWS Organizations SCPs define maximum permissions for principals in member accounts. RCPs define maximum permissions available to resources in member accounts for supported services. Neither policy type grants access by itself. The underlying identity or resource policy still has to authorize the request.
SCPs are effective for coarse-grained constraints such as preventing use of unapproved services or regions, protecting security controls from modification, or enforcing organization-wide restrictions. RCPs add a resource-centric organization boundary that can limit how resources are accessed, including by principals outside the organization where supported.
Guardrails improve consistency, but they should be introduced carefully. A broad explicit deny at a high organizational level can break automation across many accounts. Test policies in a limited organizational unit, document exceptions, and use condition keys that match the actual boundary you are trying to enforce.
For a typical cross-account request, AWS evaluates the trusted account containing the requesting principal and the trusting account containing the resource. The requesting principal needs identity-side permission to make the request, and the resource side needs a resource policy or trust relationship that accepts that principal. AWS allows the request only when both account evaluations allow it.
This two-sided model explains a common failure pattern: an engineer updates the role policy in Account A but never changes the bucket policy, key policy, or role trust in Account B. The principal now has permission to ask, but the resource still has no reason to trust the request.
Cross-account design should make ownership explicit. Who controls the principal? Who controls the resource? Which side can revoke access? Which organization guardrails apply to each account? Those questions matter more than copying a policy example without understanding the trust boundary.
Resource policies add a service-specific authorization layer. Amazon S3 bucket policies, IAM role trust policies, AWS KMS key policies, and other resource-based mechanisms place authorization close to the resource. That can make cross-account sharing and service access possible, but it also means IAM troubleshooting must account for service-specific semantics.
Not every resource policy handles principals, session ARNs, or service delegation in exactly the same way. AWS documentation calls out important interactions between resource-based grants, permissions boundaries, and session principals. Architects should avoid overgeneralizing from one service.
Use resource policies when the resource owner needs to express who may access the object, but keep the principal-side least-privilege policy as well. Two-sided permission often makes intent clearer and reduces accidental exposure.
Teams often start with broad permissions because they do not yet know the exact actions a workload needs. The architecture should include a path from discovery to reduction. CloudTrail activity, service documentation, IAM Access Analyzer, and controlled testing can help identify actual permissions and external access.
Least privilege also changes over time. A role that was appropriate for deployment may be too broad for steady-state runtime. A new feature may add API calls. A decommissioned workflow may leave unused permissions behind. Periodic review should therefore be part of access design.
Comparing AWS, Azure, and Google Cloud identity models helps separate general least-privilege principles from provider-specific implementation choices.
An access-denied message can represent an implicit deny or an explicit deny. Start with the principal and session actually used, the API action, the resource ARN, and the relevant condition context. Then enumerate the policy layers that can affect that request.
Check whether the identity policy grants the action. Check resource-based policy or trust where required. Inspect permissions boundaries and session policies. Determine whether an SCP or RCP restricts the account. For private network paths, consider endpoint policies. Finally, look for explicit denies and condition mismatches.
Tools can accelerate the work, but they do not replace the model. IAM Access Analyzer can validate and analyze policies, CloudTrail can show request context, and AWS error messages increasingly identify policy types involved in a denial. The administrator still needs to understand why that policy type has authority over the request.
One practical design exercise is to take the same requirement—such as “developers may deploy only approved services in approved regions”—and express it at several layers. An identity policy can grant a narrow set of deployment actions. An SCP can prevent entire member accounts from leaving an organizational boundary. Conditions can restrict region or tags. A permissions boundary can constrain what delegated administrators are allowed to grant. Comparing these options clarifies which team owns the control and how widely a mistake would propagate.
Also distinguish preventive controls from detective ones. IAM policy evaluation decides whether a request is authorized, while CloudTrail, Access Analyzer findings, and security monitoring help explain or detect access patterns. Mature architecture uses both: prevention to stop disallowed actions and evidence to verify that the permission model still matches the organization’s intent.
Identity policies are a natural place for workload and human permissions. Resource policies express resource-owner trust. Permissions boundaries support delegated administration. Session policies narrow temporary credentials. SCPs and RCPs establish organization-wide ceilings. Endpoint policies add network-path constraints. Conditions make many of these controls context-sensitive.
A good design uses the smallest number of layers necessary to express clear responsibility. More policy layers can create stronger defense in depth, but they also increase the number of places an operator must inspect during an outage. The architecture should therefore balance centralized guardrails with local clarity.
This shared IAM knowledge supports several AWS certification paths, including SAA-C03 and the more complex decisions around multi-account landing zones found in SAP-C02.
