An auditing role needs to read one prefix of a bucket, and nobody is allowed to edit the role. A service user is refused a secret whose resource policy “allows the account”. A role in a partner account is named in a bucket policy and still gets AccessDenied. Three puzzles, one question: when a resource has its own policy, which side has to say yes? The answer depends on whether the request crosses an account boundary, and on exactly what the resource policy names.
One account: either side can allow
Within a single account, the IAM User Guide treats identity-based and resource-based policies as a union: “If an action is allowed by an identity-based policy, a resource-based policy, or both, then AWS allows the action.” It repeats the point in a note: “If either the identity-based policy or the resource-based policy within the same account allows the request and the other doesn’t, the request is still allowed.”
So the auditing role does not need an identity statement at all. A bucket policy statement that names the role and allows s3:GetObject on that prefix can grant the access without the role’s own policies being touched. (A role that IAM Identity Center manages is the documented exception to naming it directly: the Principal guide says to name the account as the principal and reference the permission set’s role ARN in a condition, because that ARN’s suffix changes if the role is recreated.)
An explicit deny still beats both. The union only adds up Allows, and the evaluation order looks for a Deny in every policy before any Allow counts.
The exceptions
Not every resource policy works this way. The guide names two that “must explicitly allow access for principals”: IAM role trust policies and AWS KMS key policies. It adds that resource-based policies for other services “may also require an explicit Allow statement within the same account”, so check the service’s own documentation.
The principal you name matters too. If a same-account resource policy “grants permission directly to the IAM user or the session principal that is making the request”, an implicit deny in an identity-based policy, a permissions boundary or a session policy does not change the result. A grant to an IAM role ARN is weaker: it is still “limited by an implicit deny in a permissions boundary or session policy”.
Across accounts: both sides must allow
When the principal lives in one account (the trusted account) and the resource in another (the trusting account), AWS “performs two evaluations”, one in each account, and “the request is allowed only if both evaluations return a decision of Allow”. The requester needs an identity-based policy that allows the request to the resource, and the resource-based policy must allow the requester.
That is the partner’s problem. The bucket policy names its role, which covers the trusting account. Its own account must also give the role an identity-based policy that allows the action on that bucket. The trusted account’s evaluation also includes policies that limit identity-based policies, such as a permissions boundary, so a boundary there can refuse a request the bucket policy welcomes.
The account principal delegates, it does not grant
A resource policy can name a whole account, either as arn:aws:iam::111122223333:root or as the bare account ID. The guide is precise about what that does: it “delegates authority to the account”. The two forms “behave the same way”, and the ARN ending in :root “does not limit permissions to only the root user of the account”. It does not hand access to every identity in the account either.
Delegation means the account’s own IAM policies decide which users and roles get in. The same-account shortcut above needs a resource policy that grants to the requesting principal itself, and naming the account is not that. So the service user refused a secret whose policy allows the account is missing an identity-based policy that allows secretsmanager:GetSecretValue on that secret.
You could name the user in the secret’s policy instead, and it would work. Granting in IAM keeps the user’s access in one place to review, next to the rest of its permissions.
Block Public Access sits above the policy
S3 adds one more layer for buckets. Block Public Access settings “override these policies and permissions”, and when the organisation, account, bucket and access point settings differ, S3 applies “the most restrictive combination”. Two of the four settings act on bucket policies:
- BlockPublicPolicy makes S3 “reject calls to
PutBucketPolicyif the specified bucket policy allows public access”. The public statement is never saved. - RestrictPublicBuckets limits a bucket that already has a public policy “to only AWS service principals and authorized users within the bucket owner’s account”. If the same bucket policy also contains a public statement, that setting blocks cross-account access even for a named partner role.
S3 decides what counts as public. A bucket policy is non-public only if it grants to fixed values, such as specific principals, a set of aws:SourceIp ranges that are not too broad, or a specific aws:SourceVpce. "Principal": "*" with no limiting condition is public. The settings never rewrite your policy, though: “removing a block public access setting causes a bucket or object with a public policy or ACL to again be publicly accessible”. Turning the guard off to share one file exposes everything the policy already allows.
What the exam guides ask
The SCS-C03 guide asks you to “Design, interpret, and implement IAM policies by following the principle of least privilege (for example, permission boundaries, session policies)” (Skill 4.2.3) and to “Analyze authorization failures to determine causes or effects (for example, IAM Policy Simulator, IAM Access Analyzer)” (Skill 4.2.4). The SAA-C03 guide covers it under “Design secure access to AWS resources” (Task 1.1), and the DEA-C01 guide asks you to “Create custom IAM policies when a managed policy does not meet the needs” (Skill 4.2.1).
A scenario on this topic hides one deciding detail: whether the principal and the resource share an account, or what the resource policy’s Principal element names. The distractors ignore it:
- Edit the identity you were told to leave alone. In one account the resource policy can grant on its own.
- Let the principal assume a more powerful role. It works, and grants far more than one prefix.
- Make the objects public. With Block Public Access on, as the organisation requires, S3 rejects it, and it gives the data to everyone rather than to one role.
- Add statements to a resource policy that already allows the requester or its account. The missing Allow is in IAM, on the requester’s side.
When you troubleshoot for real, ask in order: same account or not, what the resource policy names (a principal or a whole account), which identity policy allows the action, and whether Block Public Access is in play.
Play it
The free stage below holds Larkspur Mutual’s claims bucket and database secret, all in one account. Audit needs to read reports, and its role is managed by IAM Identity Center, so you may not edit it. The nightly job’s service user has no Secrets Manager statement, and the secret’s policy names the account. Marketing wants a brochure readable by anyone; the organisation forbids public buckets. In the Policy Stepper you edit identity and resource statements, run each request, and read in the Access matrix which gate allowed or refused it. Put each grant where the evaluation logic expects it, and see what the debrief says when a fix works but sits in the other policy.