S3 Access Points are a clever way to manage access for different applications or teams to the same S3 bucket without resorting to complex bucket policies.
Let’s see one in action. Imagine you have a single S3 bucket, my-shared-data-bucket, where multiple tenants store their data. You want to give Tenant A access only to their prefix (tenant-a/) and Tenant B access only to theirs (tenant-b/).
First, you’d create a bucket policy on my-shared-data-bucket that denies all access by default, or at least restricts it severely. This is the foundation.
Then, you create an Access Point specifically for Tenant A:
aws s3control create-access-point \
--account-id 111122223333 \
--name tenant-a-access \
--bucket-arn arn:aws:s3:::my-shared-data-bucket \
--public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" \
--access-point-policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::444455556666:user/tenant-a-user"},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-shared-data-bucket/tenant-a/*"
}
]
}'
And another for Tenant B:
aws s3control create-access-point \
--account-id 111122223333 \
--name tenant-b-access \
--bucket-arn arn:aws:s3:::my-shared-data-bucket \
--public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" \
--access-point-policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::777788889999:user/tenant-b-user"},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-shared-data-bucket/tenant-b/*"
}
]
}'
Now, when tenant-a-user needs to access their data, they don’t use the bucket name my-shared-data-bucket. Instead, they use the Access Point ARN or its generated endpoint:
aws s3 cp my-local-file.txt s3://arn:aws:s3:us-east-1:111122223333:accesspoint/tenant-a-access/my-local-file.txt
Or, they can use the generated endpoint URL (which you can find in the AWS console or via aws s3control describe-access-point):
aws s3 cp my-local-file.txt s3://tenant-a-access.s3-accesspoint.us-east-1.amazonaws.com/my-local-file.txt
This Access Point policy is scoped to the Access Point itself, not the bucket. It allows tenant-a-user to perform s3:GetObject only on resources within the tenant-a/* prefix of the underlying my-shared-data-bucket. If tenant-a-user tries to access tenant-b/another-file.txt, the Access Point policy will deny it, even if the bucket policy might have allowed it.
The core problem Access Points solve is the complexity of managing granular permissions across many entities (users, roles, applications) for a single, shared S3 bucket. Without them, you’d be writing elaborate, often brittle, bucket policies with numerous Condition blocks to differentiate access based on IAM principals or object prefixes. This becomes unmanageable quickly as the number of tenants or applications grows. Access Points simplify this by allowing you to attach a specific, focused policy to each Access Point, effectively creating a dedicated entry point with its own access controls, all pointing to the same underlying bucket.
Internally, when you create an Access Point, AWS provisions a unique endpoint and associates it with your bucket. The Access Point’s policy is evaluated before the bucket policy. This means the Access Point policy acts as the first gatekeeper. If the Access Point policy allows an action, then the bucket policy is checked. If the Access Point policy denies an action, the request is rejected immediately, regardless of the bucket policy. This layered approach is key to its security and manageability.
You can also configure Access Points to enforce specific network controls, like requiring traffic to only come from a VPC endpoint. This adds another layer of security, ensuring that even if a user has the correct IAM credentials, their requests must originate from a trusted network.
The one thing most people don’t realize is that Access Point policies are evaluated against the object path as seen by the Access Point, not necessarily the full object path in the bucket if you’re using features like object ownership where the bucket owner is not the uploader. However, for the common case of a single account owning the bucket and the Access Point, the Resource element in the Access Point policy directly maps to the bucket’s object path, and the Principal is typically an IAM entity in the same account or a trusted account.
The next concept you’ll likely explore is how to use Access Points with S3 Replication or how to manage Access Points at scale using AWS Organizations and Service Control Policies.