- Using multiple browser sessions to test access from different identities.
- Creating a bucket and uploading objects/folders.
- Inspecting an IAM user policy that only lists buckets.
- Creating bucket policies to allow
GetObjectandDeleteObjectfor specific prefixes. - Allowing anonymous (public) read access for a folder after disabling Block Public Access.
- Granting a user from another AWS account permissions to list and delete objects.
- Blue tab: account one / user1 (bucket owner)
- Green tab: account one / user2
- Yellow tab: account two / admin
1 — Create the bucket and upload example objects
In the blue tab (account one / user1):- Create a bucket named
kk-resource-policies. - Keep defaults: Block all public access enabled, versioning disabled, and do not use ACLs (legacy).
- Upload a set of files and folders, for example:
file1.txt,file2.txt,file3.txt,secondfile.txt- folders:
logs/,media/,traces/
file1.txt:
2 — Test initial access
- As the bucket creator (blue tab / user1), open an object via the console’s “Open” action — it should succeed because you are the authenticated owner.
- If you copy an object URL and open it in a private/incognito window (anonymous user), you should see Access Denied because the bucket remains locked down by default.
3 — Inspect user2’s IAM policy
Switch to the green tab (account one / user2) and inspect the user’s IAM policies. In this demo, user2 only has a policy that allows listing buckets and bucket contents:
s3:ListAllMyBuckets) and request ListBucket (which may require the bucket ARN to succeed), but cannot GetObject or DeleteObject without an explicit bucket policy or additional IAM permissions.
4 — Listing the bucket contents as user2
In the S3 console (green tab), user2 can see thekk-resource-policies bucket and list objects. However, attempting to open an object (perform GetObject) results in Access Denied — expected, since no GetObject permission exists yet.

5 — Add a bucket policy to grant user2 read access to logs/
Back in the blue tab (account one / user1), open the bucket’s Permissions → Bucket policy editor and add a statement that grants user2s3:GetObject only within the logs/ prefix.
Example minimal statement (Principal is the user ARN):
GetObject is the API action used to retrieve an object:

6 — Verify user2 can read logs/ but not other prefixes
- Save the bucket policy, switch to the green tab (user2), navigate into the
logs/prefix and open a log object. The Open action should now succeed (download or display depends on the object’s content type). - Confirm user2 still cannot access objects in other prefixes; for example, opening
file1.txtshould still return Access Denied.
7 — Allow user2 to delete objects in traces/
To let user2 delete objects under a different prefix such astraces/, add another statement to the bucket policy:
- Deleting
traces/trace1as user2 should succeed. - Deleting
file1.txt(outsidetraces/) should still fail with Access Denied.
8 — Action vs Resource: bucket-level vs object-level
Some S3 actions operate on buckets, others on objects. Supply the matching ARN(s) in theResource element.
If you include both bucket-level and object-level actions in a single statement, provide both ARN types in the
Resource array. S3 evaluates and matches each action to the appropriate resource.
Example single-statement that mixes actions (note both resource ARNs included):
9 — Allow public (anonymous) GetObject for media/
To make objects inmedia/ publicly readable, add a statement with "Principal": "*" and Action: "s3:GetObject" that targets media/*. Note: Block Public Access settings may prevent adding public policies — you must intentionally disable or adjust them.
Block Public Access is a safety mechanism to prevent accidental public exposure. Only disable or relax the specific checks you need, and confirm your objects are intended to be public before applying a policy that grants anonymous access.

media/*:
media/ become reachable via their public object URLs. Objects outside media/ remain restricted.
10 — Combined example bucket policy
A combined example of the statements shown above:11 — Grant cross-account access (account two → this bucket)
To allow a user from another AWS account to perform actions against this bucket, add a statement with their user ARN as thePrincipal. In the demo the external user is arn:aws:iam::040497317401:user/admin.
Example cross-account statement to allow listing the bucket and deleting objects in logs/:
12 — Test cross-account access with CloudShell (account two)
In the yellow tab (account two / admin), use AWS CloudShell or the AWS CLI configured for that admin user. Initially, listing the bucket will return Access Denied:logs/ (should succeed):
13 — Summary and best practices
- Use bucket (resource) policies to grant cross-account or anonymous access; use IAM policies for permissions tied to a specific IAM identity.
- Be granular: grant only the actions and prefixes required (least privilege).
- Remember action vs resource scope: supply bucket ARNs for bucket-level actions and object ARNs (with
/*) for object-level actions. - Block Public Access protects against accidental exposure — only disable or relax the checks you intentionally need.
- When testing permissions, use separate browser sessions or CLI profiles (as demonstrated) to verify the effective permissions from different identities.
When building bucket policies, refer to the S3 API Reference to confirm whether an action is bucket-level or object-level, and include the correct ARN(s) in each statement’s
Resource element.