title: “S3 Access Without Public Exposure” created: 2026-07-20 updated: 2026-07-20 type: knowledge tags:
- aws
- s3
- security
- iam
- bucket-policy
- best-practice
- certification
S3 Access Without Public Exposure
What It Is
A pattern where you grant access to an S3 bucket exclusively through bucket policies with explicit principals, while keeping Block Public Access (BPA) fully enabled and ACLs disabled. No public exposure is needed.
Why It Matters
This is the AWS-recommended approach for S3 access control. It eliminates accidental data exposure while maintaining fine-grained access. Understanding this pattern is essential for certification exams and real-world architecture.
Key Concepts
What BPA Actually Blocks
BPA only blocks public access — meaning anonymous or Principal: "*" access. It does NOT block:
- Access by a specific IAM role or user (identified ARN)
- Cross-account access to a named principal
- Access from AWS services (CloudFront OAC, Lambda, etc.)
The Ideal Combination
| Layer | Setting | Purpose |
|---|---|---|
| BPA | All 4 settings ON | Safety net — prevents any public access |
| ACLs | Disabled (Bucket Owner Enforced) | Eliminates legacy complexity |
| Bucket Policy | Explicit principals only | Single source of truth for access |
Why It Works
A bucket policy with a specific principal (ARN) is not considered “public” by AWS. BPA’s BlockPublicPolicy setting only rejects policies that use Principal: "*" or have conditions that effectively make them public.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/MyAppRole"
},
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
→ BPA will not block this policy because the principal is identified, not anonymous.
BPA Behavior Matrix
| Bucket Policy Principal | BPA ON | Result |
|---|---|---|
"*" (everyone) | ON | Blocked by BlockPublicPolicy |
"arn:aws:iam::123456:role/X" (specific role) | ON | Allowed — not public |
"arn:aws:iam::999999:root" (cross-account) | ON | Allowed — identified principal |
{"Service": "cloudfront.amazonaws.com"} | ON | Allowed — AWS service principal |
Common Use Cases
- EC2 to S3: bucket policy grants access to an EC2 instance role
- Cross-account: bucket policy grants access to another AWS account’s role
- CloudFront to S3: bucket policy grants access to CloudFront OAC
- Lambda to S3: bucket policy grants access to Lambda execution role
Gotchas
Principal: "*"with aCondition(e.g., VPC endpoint) may still be considered public by BPA — test carefully- Account-level BPA overrides bucket-level settings — check both
- Disabling BPA is not needed for IAM-based access — if someone says “disable BPA to grant access to a role”, that’s wrong
- ACLs are legacy — prefer “Bucket Owner Enforced” object ownership to disable them entirely
See Also
- [[s3-block-public-access]] — The four BPA settings explained
- [[s3-bucket-policies]] — Policy structure and common patterns
- [[iam-instance-profiles]] — EC2 roles for S3 access without credentials
- [[aws-arns]] — ARN format for principals and resources
- [[s3-access-control-lists]] — Why ACLs are legacy