AWS 112: S3 permissions, encryption and Block Public Access
The real problem
A team recognizes the name S3 permissions, encryption and Block Public Access but has not connected the feature to a real requirement, identity boundary, network or data path, failure mode, price dimension, and cleanup owner. A plausible configuration could still fail the workload.
Final outcome
The learner will produce a requirement-led artifact for S3 permissions, encryption and Block Public Access, inspect the matching AWS control plane in the Management Console, run a matching CloudShell or AWS CLI query, interpret the output, diagnose one failure, defend one architecture choice, and prove cleanup or approved retained state.
The practical outcome is not a command transcript. It must show what was expected, what happened, what the result proves, what it does not prove, and which evidence would change the decision.
Learning objectives
By the end of this lesson, the learner can:
- explain authorization layers;
- explain block public access;
- explain object ownership;
- explain default encryption;
- explain sse-kms boundary;
- connect control-plane state to the real data, network, identity, or application behavior;
- identify cost and cleanup ownership before any optional mutation;
- troubleshoot from evidence without opening broad access or adding broad permissions.
Relationship model
Requirement
|
v
Identity and policy -> AWS configuration -> network or data path -> workload behavior
| | | |
+--------------------+----------------------+--------------------+
|
v
monitoring, cost, recovery, cleanup
Use this model to separate an AWS object that exists from a result that actually works. Every arrow is a verification boundary.
Prerequisites, permissions, Region, and safety
- Learning baseline: This sequence assumes practical Linux knowledge but no prior cloud-computing or AWS knowledge. Cloud, networking, security, data, automation, and architecture concepts must come from completed earlier lessons. If a prerequisite checkpoint is incomplete, return to its linked lesson before continuing.
- Confirm a non-root caller with
aws sts get-caller-identityand keep the account number private. - Use
ap-south-1unless this lesson explicitly names a second Region. - Confirm the intended profile and Region with
aws configure listbefore interpreting an empty result. - Use read-only List, Get, and Describe permissions for the named services. Design exercises run locally and require no resource-creation permission.
- This is a no-create lesson. Console and CLI work is read-only, and every design artifact is created locally.
- Never publish account IDs, public addresses, ARNs containing private account data, session IDs, presigned URLs, object data, credentials, or KMS material.
- Do not use root, world-open SSH or RDP, disabled TLS verification, unowned resources, or irreversible retention controls in a training exercise.
Core model
| Concept | What the learner must understand |
|---|---|
| Authorization layers | S3 evaluates identity policies, bucket or access-point policies, organization controls, permissions boundaries, session policies, Block Public Access, ownership, and explicit denies. KMS adds a separate key-authorization path. |
| Block Public Access | S3 Block Public Access exists at organization, account, bucket, and access-point scopes. Effective protection uses the most restrictive applicable settings and overrides attempts that conflict with it. |
| Object Ownership | Bucket owner enforced is the default for new general purpose buckets and disables ACLs. Policies become the primary access mechanism. |
| Default encryption | S3 automatically encrypts new uploads with SSE-S3 as a base behavior. Bucket default encryption can deliberately use SSE-S3, SSE-KMS, or DSSE-KMS according to requirements and cost. |
| SSE-KMS boundary | SSE-KMS adds KMS key policy and grant or IAM permission requirements, request quotas, Region scope, audit events, and KMS cost. An S3 allow does not override a KMS deny. |
| Transport protection | Bucket policies can deny requests that do not use TLS with the aws:SecureTransport condition. Encryption at rest and encryption in transit solve different requirements. |
How it works
Troubleshoot AccessDenied by identifying principal, action, bucket or object ARN, ownership, access point, all policy limits, BPA state, TLS, VPC endpoint conditions, encryption headers, and KMS authorization. Do not respond by making the bucket public.
Read the result in layers:
- Scope: account, Region, VPC, bucket, AZ, endpoint, principal, object version, or resource ARN.
- Control plane: the requested configuration exists and reached an expected state.
- Behavior: the request, connection, health check, replication, restore, or application result meets the requirement.
- Operations: monitoring, failure owner, cost, retention, rollback, and cleanup are known.
Control-plane success is necessary but not sufficient. A resource can be available while policy, routing, DNS, health, data, or application behavior remains wrong.
Architecture decision table
| Requirement | Preferred direction | Why |
|---|---|---|
| Private training bucket | All four bucket BPA settings plus bucket owner enforced | No public ACL or policy path is required. |
| Simple low-cost server-side encryption | SSE-S3 | S3 manages the encryption keys without KMS request cost. |
| Need customer-controlled key policy and KMS audit | SSE-KMS with scoped key policy | The control is worth the added authorization and cost only when required. |
| Cross-account producer | Bucket policy and identity policy with ownership design | Both sides and encryption permissions must align. |
Professional questions normally contain several valid services. State the requirement that selects one option, why the nearest alternative fails it, and what changed requirement would reverse the choice.
Authorization model: evaluate the complete request context
Start with six facts: principal/session, action, resource ARN, request attributes, resource owner, and encryption key. Then evaluate every applicable policy layer.
Organizations SCP / RCP and account guardrails
|
IAM identity policy + session policy + permissions boundary
|
bucket policy or access-point policy + VPC endpoint policy
|
Block Public Access + Object Ownership / ACL behavior
|
S3 authorization result
|
KMS key policy / IAM / grant result when KMS is required
v
final outcome
An explicit deny in an applicable layer wins. A permissions boundary or SCP normally limits the maximum available permission; it does not grant access by itself. Cross-account requests generally require trust/allowance from both the caller side and resource side, plus KMS authorization when used. Service principals can require confused-deputy conditions such as aws:SourceArn and aws:SourceAccount.
Resource shape matters:
| Need | Typical action/resource distinction |
|---|---|
| List selected keys | s3:ListBucket on arn:aws:s3:::bucket, with a prefix condition where required |
| Read objects | s3:GetObject on arn:aws:s3:::bucket/prefix/* |
| Read exact historical version | s3:GetObjectVersion on the object resource plus version-aware request |
| Upload object | s3:PutObject on the object resource, with encryption/tag conditions where required |
| Permanently delete a version | s3:DeleteObjectVersion, not merely s3:DeleteObject |
| Manage bucket configuration | Specific bucket-level action on the bucket resource; keep separate from data-plane roles |
Do not solve a 403 by adding s3:*. Preserve the request ID/error, identify whether S3 intentionally masks object existence, inspect caller/session and policy simulation/access-analysis evidence, then test the smallest hypothesis.
Object Ownership and ACLs
Bucket owner enforced Object Ownership disables ACLs and makes the bucket owner own every object. It is the default/recommended policy-centered model for most modern general purpose buckets. Upload requests that attempt unsupported ACL grants can fail, so remove legacy public-read or cross-account canned ACL behavior when migrating.
ACLs remain relevant to legacy systems and some specialized resource types/features, but they add a second authorization and ownership model. If an integration truly requires ACLs, document object writer/owner, bucket owner access, canned ACL/header requirements, BPA interaction, migration plan, and tests. “ACLs exist” is not a reason to enable them.
Block Public Access: four controls and their purpose
At account, bucket, and access-point scopes, S3 evaluates the applicable Block Public Access posture. Organization-level policy can also enforce it. The four familiar settings address different paths:
| Setting | Prevents |
|---|---|
BlockPublicAcls | New public ACL grants through relevant PUT operations |
IgnorePublicAcls | Public ACLs from granting effective access, including older ones |
BlockPublicPolicy | A bucket/access-point policy update that would make access public |
RestrictPublicBuckets | Broad/public and cross-account access through a public policy, subject to documented service-principal behavior |
Keep all four enabled for private buckets. BPA does not remove an old ACL or rewrite a policy; it blocks/ignores effective public paths according to the setting. It also does not stop an overly broad private identity policy, a compromised authorized role, an unsafe presigned URL, or unintended access from a specifically trusted account.
Use IAM Access Analyzer for S3 findings and policy checks, S3 Storage Lens exposure indicators, AWS Config/Security Hub controls, and direct effective-access tests. A green console badge is useful evidence, not the entire security proof.
Encryption choices and request flow
S3 automatically applies SSE-S3 to new uploads when no other encryption is requested. “Encrypted by default” does not answer who controls keys, who can decrypt, whether dual-layer encryption is required, or how existing versions were encrypted.
SSE-S3
S3 owns and operates the keys. It has no separate customer KMS key policy or KMS API charge. Use it when baseline server-side encryption satisfies the requirement. Authorization remains controlled by S3/IAM policies.
SSE-KMS
S3 requests KMS data-key operations under a KMS key. Design:
- AWS owned/AWS managed versus customer managed key requirement;
- same-Region key compatibility and correct key ARN rather than an unsafe alias assumption;
- key policy, IAM permissions, grants, key administrators versus key users;
kms:GenerateDataKeyfor writes andkms:Decryptfor reads/copies as applicable;- encryption context conditions, service/principal constraints, rotation, disable/deletion safeguards;
- KMS request rate, cost, CloudTrail evidence, replication and cross-account permissions.
An S3 allow cannot override a missing KMS allow or KMS explicit deny. A disabled key can make otherwise healthy S3 objects unreadable. Schedule key deletion only through an owned, reviewed recovery process.
S3 Bucket Keys
An S3 Bucket Key reduces direct KMS request traffic and can lower SSE-KMS request cost substantially by deriving short-lived data keys from a bucket-level key. It changes the KMS encryption-context shape from an individual object ARN toward the bucket ARN, so existing conditions must be reviewed. Bucket Keys work with SSE-KMS and replication scenarios but are not supported with DSSE-KMS.
DSSE-KMS, SSE-C, and client-side encryption
DSSE-KMS gives two independent server-side encryption layers for requirements that call for dual-layer protection. It adds KMS control/cost and does not support Bucket Keys.
With SSE-C, the client supplies the key and its digest over TLS on every applicable read/write request; S3 does not store the key. The customer must protect, map, rotate, and recover it. A lost key means lost plaintext access.
Client-side encryption protects bytes before they reach S3. The application owns envelope format, data-key protection, algorithm/SDK compatibility, metadata, rotation/re-encryption, range behavior, recovery, and key availability. It is not a free substitute for server-side controls.
Enforce transport and encryption safely
A common TLS-only bucket-policy statement explicitly denies s3:* when aws:SecureTransport is false. For AWS-service compatibility and security-control interpretation, follow current AWS guidance on service-principal conditions rather than blindly copying an old policy.
Encryption-header policies need careful semantics. A policy that denies a missing SSE-KMS header can reject clients that rely on a correctly configured bucket default encryption. Decide whether the requirement is “stored result uses this encryption” or “every caller must explicitly request this encryption,” then test multipart, copy, replication, log-delivery, and AWS-service writers. Use default encryption as the baseline and narrowly scoped deny conditions only when the stronger request constraint is intentional.
Network access and browser CORS are separate
- An S3 gateway endpoint adds route-table paths from a VPC and has an endpoint policy; it does not place an ENI in each subnet and has no hourly endpoint price, though wider architecture costs remain.
- An S3 interface endpoint uses PrivateLink ENIs, security groups, DNS behavior, AZ placement, hourly/data processing charges, and can support private on-premises paths in designs where documented.
- Bucket policies can restrict expected VPC endpoint or network context, but a wrong deny can lock out console, break-glass, replication, or service delivery. Preserve an alternate reviewed recovery path.
- CORS tells a browser whether frontend JavaScript may read a cross-origin response. It does not grant S3 permission. A request can be authorized but blocked by browser CORS, or CORS-allowed but denied by IAM.
- Website endpoints and REST endpoints differ. For private content and HTTPS viewer delivery, prefer CloudFront with Origin Access Control over exposing a website bucket.
Access points, presigned access, and shared datasets
An S3 access point has a unique hostname and policy for a bucket use case. Use separate access points to express team/application boundaries and network origin controls rather than growing one unreviewable bucket policy. Effective access still depends on the access-point policy, bucket policy delegation, caller policies, BPA, endpoint policies, and KMS.
A presigned URL delegates the signer's effective permission for a bounded operation and time. Its real lifetime cannot exceed the underlying temporary credential. Treat it like a bearer credential: keep duration short, bind method/object/checksum/content constraints where supported, avoid logs/chats, and provide revocation controls through credential/policy changes when risk demands.
Worked authorization failures
Failure 1: ListObjectsV2 works but GetObject fails
Listing uses a bucket-level action/resource; reading uses an object-level action/resource. Check exact key, object policy path, version action, endpoint conditions, and encryption. Do not add a wildcard simply because one action succeeded.
Failure 2: S3 policy allows read but response is KMS AccessDenied
Confirm the object's actual encryption and key ARN. Evaluate the caller against KMS key policy/IAM/grants, key state, encryption context, account/Region, and VPC endpoint path. Grant only the necessary key operation to the workload role and retest the exact object.
Failure 3: browser reports CORS while CLI succeeds
CLI success proves S3 authorization for that principal, not browser preflight approval. Inspect browser developer-network evidence: origin, method, requested headers, OPTIONS response, actual request status, and CORS response headers. Configure only expected origins/methods/headers; never make the bucket public as a CORS fix.
Failure 4: CloudFront receives 403 from a private origin
Verify OAC attachment/signing, distribution ARN condition in the bucket policy, object key, KMS permissions for encrypted origin objects, and whether the origin is a REST bucket endpoint rather than an incompatible website endpoint/OAC combination.
Required security test matrix
| Test | Expected result |
|---|---|
| Approved workload role, approved prefix, TLS | Allow and return/upload the expected object |
| Same role, another tenant prefix | Explicit or implicit deny |
| Anonymous REST request | Deny for a private bucket |
| HTTP/non-secure request represented in policy analysis | Explicit deny |
| Approved S3 permission but missing KMS decrypt | Deny at the KMS boundary |
| Presigned URL before expiry | Only its exact delegated operation succeeds |
| Presigned URL after expiry or changed method/key | Deny |
| Browser origin not in CORS rule | Browser cannot expose the response; S3 authorization remains a separate observation |
For each, record principal/session, action, resource, relevant condition context, expected decision, observed API/error, request ID with safe redaction, CloudTrail/access evidence where enabled, and rollback. Never include a live presigned URL or account-identifying policy in public evidence.
AWS Management Console guided practice
Before opening a service page, write the expected account, Region, starting state, and evidence. Do not choose Create, Save, Purchase, Lock, or Delete unless the lesson explicitly authorizes the live track.
- Open S3 Block Public Access settings at account scope, then inspect the supplied bucket Permissions page and effective bucket BPA without changing account controls.
- Inspect Object Ownership, bucket policy status, access points, ACL state, and default encryption; map each to a separate authorization or data-protection boundary.
- Use IAM Access Analyzer for S3 findings or supplied evidence to explain whether a bucket is public or shared outside the intended account or organization.
For each step, capture the field name and value in text. A screenshot may support the record but does not replace the explanation. Console labels can evolve, so use the service search and current documentation if a navigation label differs.
CloudShell and AWS CLI practice
CloudShell is the default browser-based command environment taught in AWS 028. AWS 029 and AWS 030 cover local CLI installation and authentication. This lesson therefore does not assume that an unconfigured local shell is ready.
Start every session with:
export AWS_DEFAULT_REGION="ap-south-1"
aws sts get-caller-identity --query Arn --output text
aws configure list
Redact the account portion of the ARN before sharing. Then perform the topic query:
Inspect public-access block, ownership controls, default encryption, versioning, and bucket policy on an approved bucket.
NW_BUCKET="replace-with-owned-bucket-name"
aws s3api get-public-access-block --bucket "$NW_BUCKET"
aws s3api get-bucket-ownership-controls --bucket "$NW_BUCKET"
aws s3api get-bucket-encryption --bucket "$NW_BUCKET"
aws s3api get-bucket-policy-status --bucket "$NW_BUCKET"
Expected interpretation:
All BPA booleans true and IsPublic false support a private posture, but effective access still depends on identity, endpoint, organization, object, and KMS controls.
Replace every replace-with-... sample value before running its command, and use only an explicitly owned resource. Explain each option first. These queries are read-only; a successful response does not authorize a later create or delete operation.
Practical work
Create p06-security-plan.md. Require all four BPA settings, bucket owner enforced, no ACL use, explicit SSE-S3 for the lab, TLS-only bucket policy, least-privilege replication role, no public website configuration, private evidence handling, and one denied anonymous request test. Add a production branch for SSE-KMS covering key ownership, policy, replication, rotation, audit, quota, and cost. No policy is applied yet.
The evidence package must contain:
- the problem and final requirement in the learner's own words;
- caller type and Region with private identifiers redacted;
- exact planned values, ownership, and cost class;
- one Console observation and matching CLI or API evidence;
- one behavior result or supplied data-plane record;
- one denied, failed, or counterexample result and evidence-led diagnosis;
- one architecture choice plus the rejected alternative;
- cleanup proof or explicit retained-state owner, expiry, and next lesson.
Verification standard
Use expected state before observed state. Record timestamps in UTC and preserve the original failure before changing anything. A passing submission answers all four questions:
- What exact requirement was tested?
- Which evidence proves the AWS configuration?
- Which evidence proves the workload behavior?
- What remains unproven or requires later monitoring?
If AWS returns no rows, verify account, Region, permission, filters, pagination, resource type, and deletion state before concluding that nothing exists.
Common failures and troubleshooting
| Symptom | Evidence first | Likely boundary | Smallest safe response |
|---|---|---|---|
| object appears missing | caller, Region, filters, pagination, tags | scope or read permission | align scope before creating a duplicate |
| state remains pending or unavailable | service state, events, dependencies, quotas | dependency or capacity | correct the named dependency and wait with a bound |
| AccessDenied | principal, action, resource, explicit-deny context | identity, resource, endpoint, organization, or KMS policy | change only the proven policy layer |
| configuration exists but behavior fails | route, DNS, security, listener, health, logs, object version | data path or application | test the next boundary and change one control |
| bill is higher than expected | hours, bytes, requests, AZs, addresses, retention | cost model or retained resource | stop optional work and reconcile the ledger |
| cleanup is blocked | dependency inventory and owning service | deletion order or immutable state | remove owned dependants in reviewed reverse order |
Do not troubleshoot by attaching administrator access, opening administration ports to the internet, disabling encryption, retrying uncontrolled creation, deleting unknown resources, or weakening retention.
Cost, cleanup, and retained state
No AWS resource is created. Close CloudShell and remove or redact downloaded evidence.
Cleanup evidence requires terminal state and an after-inventory. Search related ENIs, public IPv4 addresses, EBS volumes and snapshots, load balancers, target groups, Auto Scaling instances, endpoints, logs, S3 versions and delete markers, backup recovery points, and global IAM roles when they apply. Billing data can lag, so schedule a later review.
Architecture and certification decisions
- Certification coverage: SAA-C03; SOA-C03; SAP-C02; DOP-C02.
- Exam mapping: SAA D1-D4.
- Explain service scope, failure boundary, consistency, recovery, security, operations, and price rather than matching a keyword.
- Treat availability and durability, encryption and authorization, routing and filtering, health and lifecycle, backup and replication, and discount and capacity as separate concepts.
- Do not reproduce protected certification questions.
Knowledge check
- Does an S3 allow grant KMS decrypt automatically?
Expected direction: No. KMS authorization is also required.
- What does bucket owner enforced do to ACLs?
Expected direction: It disables ACLs and assigns bucket-owner ownership.
- Are new S3 uploads encrypted by default?
Expected direction: Yes, with SSE-S3 as the baseline behavior.
- Should an AccessDenied be fixed by disabling BPA?
Expected direction: No. Locate the exact denied authorization layer.
Completion gate and assessment
| Area | Points | Passing evidence |
|---|---|---|
| Requirement and model | 15 | Correct scope, terminology, and final outcome |
| Console evidence | 15 | Current path and interpreted fields |
| CLI or API evidence | 15 | Scoped command, expected result, and limitations |
| Behavior or decision exercise | 20 | Reproducible result or defensible architecture reasoning |
| Troubleshooting | 15 | Original symptom, hypothesis, one change, retest, rollback |
| Security and cost | 10 | Least privilege, data protection, current price dimensions |
| Cleanup and handoff | 10 | Terminal-state proof or approved retained-state record |
Pass at 80 out of 100 with no critical safety failure. A missing practical artifact, unexplained output, unsafe access, destructive action outside the owned scope, unplanned billed resource, or false cleanup claim requires remediation and a changed retest.