☰ All modules Tier 3 · S3 GuideCheat sheet ‹ containersec2 ›
Contents
  1. How S3 appears on DVA-C02
  2. 1. Buckets objects keys and metadata
  3. 2. Access control Block Public Access and access logs
  4. 3. Encryption at rest and in transit
  5. 4. Versioning MFA Delete and Object Lock
  6. 5. Replication CRR and SRR
  7. 6. Storage classes and lifecycle rules
  8. 7. Event notifications and EventBridge
  9. 8. Performance multipart uploads and Transfer Acceleration
  10. 9. Presigned URLs CORS and static websites
  11. 10. Access Points and Object Lambda
  12. Quick decision rules
  13. Changed vs older material

S3 — DVA-C02 Mastery Guide

  • Sources: course chapter 06 (S3). The slides serve as the syllabus only; all wording here is original.
  • Written 2026-10-12; values checked against AWS docs on 2026-10-12. The marker ⚠️ Changed: <current>. Older material may say <old>. flags a value or behaviour that differs from the course or from older practice tests: learn the current value. ⚠️ unverified marks anything that could not be confirmed in AWS documentation. Every change is listed in Changed vs older material; rows enter notes/current-facts.md once you confirm them.
  • Tier 3 (supporting), bank target 30 questions. Domains: Development with AWS Services (primary), Security.
  • Scope: buckets, objects, metadata and tags; IAM vs bucket policies, ACLs and Block Public Access; encryption (SSE-S3, SSE-KMS, DSSE-KMS, SSE-C, client-side, default encryption, TLS); versioning, MFA Delete and Object Lock; replication (CRR/SRR); storage classes and lifecycle rules; event notifications; performance (prefixes, multipart, byte ranges, Transfer Acceleration); presigned URLs, CORS and static websites; Access Points and Object Lambda. Covered elsewhere (one-line cross-references only): KMS key policies, request quotas and S3 Bucket Keys → notes/security-encryption-guide.md §2 and §5; policy evaluation logic, STS and cross-account roles → notes/advanced-identity-guide.md §9 and §11; IAM policy grammar and condition operators → notes/iam-guide.md §4–§5; SigV4 signing and credential lifetimes → notes/cli-sdk-policies-guide.md §10; Lambda resource-based policies, async retries and recursive-loop detection → notes/lambda-guide.md §2, §4, §12; SQS/SNS access policies and fan-out → notes/sqs-sns-kinesis-guide.md §6 and §8; EventBridge rules and CloudTrail data events → notes/monitoring-guide.md §6 and §10; CloudFront in front of S3 (OAC, signed URLs) → notes/cloudfront-guide.md §3 and §4; VPC gateway endpoints → notes/vpc-guide.md §3; DynamoDB as an S3 metadata index → notes/dynamodb-guide.md §14.
  • How to use it: /explain <topic> teaches from these sections (concept → exam facts → developer angle → traps → 3 check questions); /quiz s3 asks bank questions whose source_note links point at the ## N. headings below; /drill s3 fires short recall prompts from notes/s3-cheat-sheet.md. Suggested loop: read a section, answer its practice questions before opening the answers, /explain what is still unclear, then /quiz s3 and /drill s3.

How S3 appears on DVA-C02

S3 is the default answer whenever an application needs durable object storage, so it shows up inside Lambda, API Gateway, CloudFront, DynamoDB and CI/CD scenarios as well as in its own questions. The exam treats it from the developer's chair:

Typical question shapes: a scenario with one deciding constraint ("LEAST operational overhead", "MOST secure", "MOST cost-effective", "fewest code changes"); an error code or symptom to explain; "Which TWO…" with five options; the exact header, condition key, API action or CLI flag that does the job.

Domain map: Development with AWS Services → §1, §5, §6, §7, §8, §9 · Security → §2, §3, §4, §9 (presigned URLs), §10. Troubleshooting framing appears throughout (§1 errors, §3 KMS throttling, §7 missing events, §8 503).

Out of scope here: network design (VPC endpoints appear only as the path a request takes), S3 on Outposts, S3 Tables and S3 Vectors, storage-administration tools beyond what a developer configures (Storage Lens dashboards, Inventory details).

# Topic Why it is on the exam
1 Buckets objects keys and metadata Naming and size limits, immutable metadata vs mutable tags, consistency and conditional writes, 403 vs 404
2 Access control Block Public Access and access logs Who may call what: IAM vs bucket policy, cross-account rules, ACLs off, BPA guardrails, request logs
3 Encryption at rest and in transit Picking the encryption option under a key-control constraint; headers, KMS permissions and quotas, forcing TLS
4 Versioning MFA Delete and Object Lock Recovering from deletes and overwrites; WORM retention that even administrators can't bypass
5 Replication CRR and SRR What replicates, what doesn't, and the role, versioning and KMS settings it needs
6 Storage classes and lifecycle rules The cheapest class that still meets the retrieval-time constraint; automating transitions and expirations
7 Event notifications and EventBridge Event-driven processing, destination permissions, filters, fan-out and loop avoidance
8 Performance multipart uploads and Transfer Acceleration Request-rate scaling per prefix, 503 Slow Down, big and distant uploads, partial reads
9 Presigned URLs CORS and static websites Direct browser and mobile access without sharing credentials; preflight fixes; public website hosting
10 Access Points and Object Lambda Per-application endpoints and policies for shared buckets; transforming data on read (and its availability change)

1. Buckets objects keys and metadata

Concept

Exam facts

Developer angle

# Create a bucket outside us-east-1 and upload with metadata and tags
aws s3api create-bucket --bucket invoices-archive-7f3a --region eu-west-1 \
  --create-bucket-configuration LocationConstraint=eu-west-1
aws s3api put-object --bucket invoices-archive-7f3a --key 2026/10/inv-1001.pdf \
  --body inv-1001.pdf --content-type application/pdf \
  --metadata customer-id=c-8812,source=billing \
  --tagging "Classification=Internal&Project=Blue"

aws s3api head-object --bucket invoices-archive-7f3a --key 2026/10/inv-1001.pdf

# "Edit" metadata = rewrite the object with REPLACE
aws s3api copy-object --bucket invoices-archive-7f3a --key 2026/10/inv-1001.pdf \
  --copy-source invoices-archive-7f3a/2026/10/inv-1001.pdf \
  --metadata-directive REPLACE --content-type application/pdf \
  --metadata customer-id=c-8812,source=billing,reviewed=yes

# Tags are replaced as a whole set
aws s3api put-object-tagging --bucket invoices-archive-7f3a --key 2026/10/inv-1001.pdf \
  --tagging 'TagSet=[{Key=Classification,Value=Confidential},{Key=Project,Value=Blue}]'

# "Folders" are prefixes + a delimiter
aws s3api list-objects-v2 --bucket invoices-archive-7f3a --prefix 2026/ --delimiter /

Create-only-once with a conditional write (boto3):

import boto3
from botocore.exceptions import ClientError

s3 = boto3.client("s3")

def write_once(bucket: str, key: str, body: bytes) -> bool:
    """Return True if this call created the object, False if it already existed."""
    try:
        s3.put_object(Bucket=bucket, Key=key, Body=body, IfNoneMatch="*")
        return True
    except ClientError as err:
        if err.response["ResponseMetadata"]["HTTPStatusCode"] == 412:
            return False  # someone else won the race
        raise  # 409 Conflict and other errors: let the caller retry

Traps

Practice questions

  1. A developer runs the same nightly report job on two EC2 instances for high availability. Both instances sometimes finish at the same moment and upload reports/2026-10-12.csv, and the first completed upload must never be replaced. No new AWS service may be added. Which solution meets these requirements with the fewest code changes?

    • A. Enable S3 Versioning so that both uploads are kept as separate versions of the key.
    • B. Add the If-None-Match: * header to each upload and treat an HTTP 412 as already written.
    • C. Acquire a lock item with a conditional PutItem on a DynamoDB table before each instance calls PutObject.
    • D. Apply an Object Lock legal hold to the report as soon as the upload finishes.
  2. A developer must correct the Content-Type of 3,000 existing objects that were uploaded as binary/octet-stream, and must label each object with Reviewed=yes so that an IAM policy condition can match it. Which TWO actions accomplish this? (Select TWO.)

    • A. Copy each object onto itself with --metadata-directive REPLACE and the correct --content-type.
    • B. Call head-object with the new --content-type value for each key.
    • C. Call put-object-tagging for each object with the complete new tag set.
    • D. Add a lifecycle rule whose filter matches the objects and rewrites their Content-Type to the correct value.
    • E. Call put-object-acl on each object with an x-amz-meta-content-type header.
Answers
  1. B. The conditional header makes S3 reject the second writer with 412 Precondition Failed, which is one parameter in existing code. A keeps both uploads but the later one becomes current, so the first result is replaced as the visible object; C works but adds a service; D acts after the fact and needs Object Lock, so it doesn't stop the race.
  2. A, C. Content-Type is system metadata that is changed only by rewriting the object, and tags are set with PutObjectTagging (include any existing tags because the set is replaced). B only reads metadata; D isn't something lifecycle can do (it transitions and expires); E changes ACLs, not metadata, and ACL calls fail when ACLs are disabled.

2. Access control Block Public Access and access logs

Concept

Exam facts

Developer angle

Bucket policy that lets one role from a partner account read a prefix, refuses plain HTTP and keeps everyone else inside the organization:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PartnerReadExports",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::222233334444:role/report-reader" },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::partner-exports/exports/*"
    },
    {
      "Sid": "PartnerListExports",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::222233334444:role/report-reader" },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::partner-exports",
      "Condition": { "StringLike": { "s3:prefix": "exports/*" } }
    },
    {
      "Sid": "DenyPlainHttp",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": ["arn:aws:s3:::partner-exports", "arn:aws:s3:::partner-exports/*"],
      "Condition": { "Bool": { "aws:SecureTransport": "false" } }
    }
  ]
}
aws s3api put-bucket-policy --bucket partner-exports --policy file://policy.json
aws s3api get-bucket-policy-status --bucket partner-exports      # IsPublic true/false
aws s3api put-public-access-block --bucket partner-exports \
  --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3control put-public-access-block --account-id 111122223333 \
  --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api get-bucket-ownership-controls --bucket partner-exports

# Server access logging: destination policy for logging.s3.amazonaws.com, then enable
aws s3api put-bucket-policy --bucket orders-logs --policy file://log-delivery-policy.json
aws s3api put-bucket-logging --bucket orders-prod \
  --bucket-logging-status '{"LoggingEnabled":{"TargetBucket":"orders-logs","TargetPrefix":"orders-prod/"}}'

Traps

Practice questions

  1. An application role in account 222233334444 must read objects under exports/ in a bucket owned by account 111122223333. The role's IAM policy allows s3:GetObject on arn:aws:s3:::partner-exports/exports/*, but every request fails with AccessDenied. Objects use SSE-S3 and the bucket uses the Bucket owner enforced setting. What must the bucket owner add?

    • A. A bucket ACL grant of READ to the canonical user ID of account 222233334444 for the bucket.
    • B. An IAM role in account 111122223333 whose trust policy allows s3.amazonaws.com.
    • C. A change to the bucket's Block Public Access settings that turns off RestrictPublicBuckets.
    • D. A bucket policy statement that allows that role s3:GetObject on objects under exports/.
  2. A developer enables server access logging on bucket orders-prod in us-east-1 with put-bucket-logging, choosing destination bucket orders-logs. A day later no log objects exist. orders-logs is in eu-west-1, uses the Bucket owner enforced setting, and its bucket policy allows only the company's administrator role. Which TWO actions will make log delivery work? (Select TWO.)

    • A. Enable versioning and MFA Delete on the destination bucket.
    • B. Use a destination bucket in us-east-1 that is owned by the same account.
    • C. Grant the S3 Log Delivery group WRITE and READ_ACP permissions through the destination bucket's access control list.
    • D. Turn on S3 Transfer Acceleration for the destination bucket.
    • E. Add a bucket policy statement that lets logging.s3.amazonaws.com call s3:PutObject on the destination.
Answers
  1. D. Cross-account access needs an Allow on both sides: the identity policy exists, so the bucket policy must grant the role. A fails because ACLs are disabled; B describes a service role, which a reader doesn't need; C is unrelated because nothing here is public.
  2. B, E. An S3 log destination must be in the same Region and account, and the logging service principal needs s3:PutObject through the bucket policy. A doesn't grant anything; C is impossible while ACLs are disabled; D only speeds up client uploads.

3. Encryption at rest and in transit

Concept

Exam facts

Option Key control Request header(s) Notes
SSE-S3 S3 owns and rotates the keys; AES-256 (GCM) x-amz-server-side-encryption: AES256 Default for all buckets, free, no per-key audit trail
SSE-KMS KMS key: AWS managed aws/s3 or customer managed x-amz-server-side-encryption: aws:kms, x-amz-server-side-encryption-aws-kms-key-id, optional x-amz-server-side-encryption-context Key policy control, CloudTrail logs every GenerateDataKey/Decrypt, KMS request charges and quotas
DSSE-KMS KMS key + a second, S3-managed layer x-amz-server-side-encryption: aws:kms:dsse Two independent AES-256 layers for compliance; costs more; no S3 Bucket Keys
SSE-C You supply the key on every request x-amz-server-side-encryption-customer-algorithm: AES256, -customer-key (base64 256-bit key), -customer-key-MD5 HTTPS only; S3 keeps only a salted HMAC of the key; lose the key, lose the data
Client-side You (Amazon S3 Encryption Client, AWS Encryption SDK) none S3 stores ciphertext (and still adds SSE-S3 on top)

Developer angle

# One object with a customer managed KMS key
aws s3api put-object --bucket finance-docs --key q3/ledger.csv --body ledger.csv \
  --server-side-encryption aws:kms \
  --ssekms-key-id arn:aws:kms:eu-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab

# Bucket default: SSE-KMS with an S3 Bucket Key (fewer KMS calls)
aws s3api put-bucket-encryption --bucket finance-docs --server-side-encryption-configuration '{
  "Rules": [{
    "ApplyServerSideEncryptionByDefault": {
      "SSEAlgorithm": "aws:kms",
      "KMSMasterKeyID": "arn:aws:kms:eu-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
    },
    "BucketKeyEnabled": true
  }]
}'
aws s3api get-bucket-encryption --bucket finance-docs

# SSE-C with the high-level CLI: raw 32-byte key file, same key to read it back
aws s3 cp scan.tif s3://legacy-scans/scan.tif --sse-c AES256 --sse-c-key fileb://customer.key
aws s3 cp s3://legacy-scans/scan.tif ./scan.tif --sse-c AES256 --sse-c-key fileb://customer.key

Bucket policy that rejects uploads not encrypted with one specific KMS key:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "RequireLedgerKey",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::finance-docs/*",
    "Condition": {
      "StringNotEquals": {
        "s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:eu-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
      }
    }
  }]
}
import boto3

s3 = boto3.client("s3")
KEY_ARN = "arn:aws:kms:eu-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
s3.put_object(Bucket="finance-docs", Key="q3/ledger.csv", Body=b"id,amount\n1,10\n",
              ServerSideEncryption="aws:kms", SSEKMSKeyId=KEY_ARN, BucketKeyEnabled=True)
obj = s3.get_object(Bucket="finance-docs", Key="q3/ledger.csv")  # no SSE parameters on GET
print(obj["ServerSideEncryption"], obj["SSEKMSKeyId"])

Traps

Practice questions

  1. A finance application must store reports encrypted with a key whose use is recorded in CloudTrail and whose key policy is controlled by the security team, and auditors require that any upload not using that particular key is rejected. Which approach meets the requirements with the LEAST operational overhead?

    • A. Use SSE-C with keys kept in AWS Secrets Manager, and have the application pass the key with every request.
    • B. Keep the default SSE-S3 encryption and turn on CloudTrail data events to audit every request to the bucket.
    • C. Make the customer managed key the SSE-KMS default and deny uploads in the bucket policy unless they name that key.
    • D. Encrypt each file with the AWS Encryption SDK before uploading it, and store the encrypted data keys in DynamoDB.
  2. After switching a busy bucket's default encryption from SSE-S3 to SSE-KMS with a customer managed key, a developer sees intermittent upload and download failures caused by KMS ThrottlingException errors. Which TWO actions reduce or remove the failures? (Select TWO.)

    • A. Switch the default encryption to DSSE-KMS so that S3 batches the KMS calls.
    • B. Enable an S3 Bucket Key in the bucket's default encryption configuration.
    • C. Add the x-amz-server-side-encryption-context header to every upload request.
    • D. Request a higher KMS symmetric cryptographic request quota in Service Quotas.
    • E. Enable S3 Transfer Acceleration so that uploads and downloads enter AWS through the nearest edge locations.
Answers
  1. C. SSE-KMS with a customer managed key gives key-policy control and CloudTrail records of key use, and the bucket policy rejects uploads that use another key. A works but leaves key storage, rotation and delivery to you on every call; B gives no control over the key and logs only S3 API calls; D adds custom key management.
  2. B, D. A Bucket Key lets S3 derive data keys locally, removing most KMS calls, and a higher quota raises the ceiling. A adds a second layer and doesn't support Bucket Keys; C changes the context, not the call rate; E speeds up long-distance transfers and adds no KMS capacity.

4. Versioning MFA Delete and Object Lock

Concept

Exam facts

Developer angle

# Versioning
aws s3api put-bucket-versioning --bucket contracts-store --versioning-configuration Status=Enabled
aws s3api list-object-versions --bucket contracts-store --prefix contracts/acme.pdf
aws s3api get-object --bucket contracts-store --key contracts/acme.pdf \
  --version-id 3HL4kqtJlcpXroDTDmJ.rmSpXd3dIbrHY acme-old.pdf
# Undo an accidental delete: remove the delete marker (its own version ID)
aws s3api delete-object --bucket contracts-store --key contracts/acme.pdf \
  --version-id UfKXp1i9e3cmZ8Uyw9GS2s0C8dCQWVdG

# MFA Delete: root user's credentials and MFA device, CLI only
aws s3api put-bucket-versioning --bucket contracts-store \
  --versioning-configuration Status=Enabled,MFADelete=Enabled \
  --mfa "arn:aws:iam::111122223333:mfa/root-account-mfa-device 123456"

# Object Lock on an existing versioned bucket, 7-year compliance default
aws s3api put-object-lock-configuration --bucket trade-records --object-lock-configuration \
  '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Years":7}}}'
aws s3api put-object-legal-hold --bucket trade-records --key 2026/t-889.json \
  --legal-hold Status=ON
aws s3api get-object-retention --bucket trade-records --key 2026/t-889.json

# Governance mode in a separate test bucket: set a lock, then remove the version anyway
aws s3api put-object-retention --bucket retention-sandbox --key test/t-1.json \
  --retention '{"Mode":"GOVERNANCE","RetainUntilDate":"2027-01-01T00:00:00Z"}'
aws s3api delete-object --bucket retention-sandbox --key test/t-1.json \
  --version-id 3sL4kqtJlcpXroDTDmJ.rmSpXd3dIbrHY --bypass-governance-retention  # needs s3:BypassGovernanceRetention

Traps

Practice questions

  1. A user deleted contracts/acme.pdf from a versioning-enabled bucket with a plain DeleteObject call that didn't include a version ID. The developer must make the latest content available again under the same key as quickly as possible. What should the developer do?

    • A. Delete the delete marker by calling delete-object with the marker's version ID.
    • B. Restore the object from S3 Glacier Flexible Retrieval with restore-object.
    • C. Suspend versioning on the bucket so that the previous version becomes current again.
    • D. Run an S3 Batch Replication job that copies the previous version back to the same key.
  2. A company must keep trade confirmations immutable for 7 years so that no user, including administrators with full S3 permissions, can delete them or shorten the protection. The existing bucket already has versioning enabled and contains data. Which TWO steps meet the requirements? (Select TWO.)

    • A. Create a new bucket, because Object Lock can be turned on only when a bucket is created.
    • B. Enable Object Lock on the existing bucket with put-object-lock-configuration.
    • C. Set a default retention of 7 years in COMPLIANCE mode.
    • D. Set a default retention of 7 years in GOVERNANCE mode and deny s3:BypassGovernanceRetention in the bucket policy.
    • E. Enable MFA Delete on the bucket by using the root user's MFA device.
Answers
  1. A. Removing the delete marker makes the previous version current again immediately. B applies to archived objects, not deletes; C changes how future writes are versioned and doesn't remove the marker; D adds a job for something a single call fixes.
  2. B, C. Object Lock can now be enabled on an existing versioned bucket, and compliance mode can't be bypassed or shortened by anyone. A is outdated; D can be undone by an administrator who edits the bucket policy; E only adds MFA to permanent deletes and doesn't enforce a retention period.

5. Replication CRR and SRR

Concept

Exam facts

Developer angle

Role trust policy (S3 assumes the role):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "s3.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}

Replication configuration with KMS opt-in, delete marker replication and a cheaper storage class for the copy:

{
  "Role": "arn:aws:iam::111122223333:role/s3-replication-role",
  "Rules": [{
    "ID": "invoices-to-eu",
    "Priority": 1,
    "Status": "Enabled",
    "Filter": { "Prefix": "invoices/" },
    "DeleteMarkerReplication": { "Status": "Enabled" },
    "SourceSelectionCriteria": { "SseKmsEncryptedObjects": { "Status": "Enabled" } },
    "Destination": {
      "Bucket": "arn:aws:s3:::invoices-replica-eu",
      "StorageClass": "STANDARD_IA",
      "EncryptionConfiguration": {
        "ReplicaKmsKeyID": "arn:aws:kms:eu-west-1:111122223333:key/9f1e2d3c-4b5a-6789-0abc-def123456789"
      }
    }
  }]
}
aws s3api put-bucket-versioning --bucket invoices-replica-eu --versioning-configuration Status=Enabled
aws s3api put-bucket-replication --bucket invoices-us --replication-configuration file://replication.json
aws s3api get-bucket-replication --bucket invoices-us
aws s3api head-object --bucket invoices-us --key invoices/2026/inv-77.pdf --query ReplicationStatus

Traps

Practice questions

  1. A team enables Cross-Region Replication from bucket media-us to bucket media-eu. New uploads appear in media-eu, but the 4 million objects that existed before the rule was created don't. Which solution copies those objects with the LEAST operational overhead while keeping their version IDs and metadata?

    • A. Run aws s3 sync from an EC2 instance in the destination Region.
    • B. Create an S3 Batch Replication job for the existing objects.
    • C. Add a second replication rule with a higher priority for the same prefix.
    • D. Enable S3 Replication Time Control on the existing rule.
  2. Objects encrypted with SSE-KMS under a customer managed key in us-east-1 aren't replicating to a destination bucket in us-west-2, while SSE-S3 objects replicate correctly. Which TWO changes are required? (Select TWO.)

    • A. Enable delete marker replication on the replication rule.
    • B. Turn on S3 Bucket Keys for the destination bucket's default encryption.
    • C. Add SourceSelectionCriteria with SseKmsEncryptedObjects set to Enabled to the rule.
    • D. Change the replication role's trust policy so that the role trusts kms.amazonaws.com instead of s3.amazonaws.com.
    • E. Set a ReplicaKmsKeyID in us-west-2 and grant the role kms:Decrypt and kms:Encrypt on the two keys.
Answers
  1. B. A Batch Replication job copies the pre-existing objects on demand, keeping their metadata and version IDs. A needs compute and creates new versions rather than true replicas; C still applies only to new writes; D only adds a 15-minute target for new objects.
  2. C, E. KMS-encrypted objects need the explicit opt-in plus a destination-Region key and KMS permissions for the role. A concerns deletes; B changes how the destination calls KMS but doesn't enable replication of KMS objects; D is wrong because S3, not KMS, assumes the replication role.

6. Storage classes and lifecycle rules

Concept

Exam facts

Class (x-amz-storage-class) AZs Designed availability Minimum duration Minimum billable size Access
S3 Standard (STANDARD, default) ≥ 3 99.99 % none none milliseconds
Intelligent-Tiering (INTELLIGENT_TIERING) ≥ 3 99.9 % none none (objects < 128 KB aren't monitored) milliseconds; opt-in archive tiers need a restore
Standard-IA (STANDARD_IA) ≥ 3 99.9 % 30 days 128 KB milliseconds, per-GB retrieval fee
One Zone-IA (ONEZONE_IA) 1 99.5 % 30 days 128 KB milliseconds, retrieval fee, lost if the AZ is destroyed
Glacier Instant Retrieval (GLACIER_IR) ≥ 3 99.9 % 90 days 128 KB milliseconds, higher retrieval fee
Glacier Flexible Retrieval (GLACIER) ≥ 3 99.99 % after restore 90 days 40 KB metadata overhead per object restore first: minutes to hours
Glacier Deep Archive (DEEP_ARCHIVE) ≥ 3 99.99 % after restore 180 days 40 KB metadata overhead per object restore first: within 12 or 48 hours
Express One Zone (EXPRESS_ONEZONE) 1 (you pick it) 99.95 % none none single-digit milliseconds, directory buckets only

Developer angle

lifecycle.json for the CLI (JSON, not XML): tier and expire logs, cap noncurrent versions, clean up multipart leftovers and orphaned delete markers:

{
  "Rules": [
    {
      "ID": "logs-tiering",
      "Status": "Enabled",
      "Filter": { "Prefix": "logs/" },
      "Transitions": [
        { "Days": 30, "StorageClass": "STANDARD_IA" },
        { "Days": 90, "StorageClass": "GLACIER" }
      ],
      "Expiration": { "Days": 365 }
    },
    {
      "ID": "versions-and-uploads",
      "Status": "Enabled",
      "Filter": { "Prefix": "" },
      "NoncurrentVersionTransitions": [{ "NoncurrentDays": 30, "StorageClass": "GLACIER_IR" }],
      "NoncurrentVersionExpiration": { "NoncurrentDays": 365, "NewerNoncurrentVersions": 3 },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
    },
    {
      "ID": "orphan-delete-markers",
      "Status": "Enabled",
      "Filter": { "Prefix": "" },
      "Expiration": { "ExpiredObjectDeleteMarker": true }
    }
  ]
}
aws s3api put-bucket-lifecycle-configuration --bucket app-data \
  --lifecycle-configuration file://lifecycle.json
aws s3api get-bucket-lifecycle-configuration --bucket app-data

# Choose the class at upload time
aws s3 cp dataset.parquet s3://app-data/hot/dataset.parquet --storage-class INTELLIGENT_TIERING

# Restore an archived object for 3 days with the cheapest tier, then check progress
aws s3api restore-object --bucket app-data --key archive/2019/report.pdf \
  --restore-request '{"Days":3,"GlacierJobParameters":{"Tier":"Bulk"}}'
aws s3api head-object --bucket app-data --key archive/2019/report.pdf --query Restore

# Activate the optional Intelligent-Tiering archive tiers
aws s3api put-bucket-intelligent-tiering-configuration --bucket app-data --id archive-cold \
  --intelligent-tiering-configuration '{"Id":"archive-cold","Status":"Enabled","Tierings":[{"Days":90,"AccessTier":"ARCHIVE_ACCESS"},{"Days":180,"AccessTier":"DEEP_ARCHIVE_ACCESS"}]}'

Traps

Practice questions

  1. An application stores scanned invoices that are read often during their first week and rarely afterwards, but when an auditor asks for one it must be returned within milliseconds. Invoices must be kept for 5 years at the lowest storage cost. Which lifecycle design meets these requirements?

    • A. Transition objects to S3 Glacier Deep Archive after 7 days and expire them after 1,825 days.
    • B. Transition objects to S3 One Zone-IA after 7 days and expire them after 1,825 days.
    • C. Store objects in S3 Intelligent-Tiering with the Deep Archive Access tier activated after 180 days.
    • D. Transition objects to S3 Glacier Instant Retrieval after 7 days and expire them after 1,825 days.
  2. A versioning-enabled bucket has a single lifecycle rule that expires current versions 30 days after creation, yet the object count and the storage bill keep growing. Which TWO additions stop the growth? (Select TWO.)

    • A. A NoncurrentVersionExpiration action that deletes noncurrent versions after a set number of days.
    • B. Suspending versioning on the bucket so that the existing expiration action deletes the objects permanently from now on.
    • C. A bucket policy statement that denies s3:PutObject for objects older than 30 days.
    • D. A change to the rule's filter from a key prefix to an object tag.
    • E. A separate rule with ExpiredObjectDeleteMarker set to true.
Answers
  1. D. Glacier Instant Retrieval keeps millisecond access at archive storage prices after the busy first week. A needs a restore of up to 12 hours; B costs more per GB and isn't resilient to AZ loss; C's Deep Archive Access tier also needs a restore.
  2. A, E. Expirations in a versioned bucket only create delete markers, so the noncurrent versions must be expired and the leftover markers removed. B doesn't delete the versions already kept; C blocks new uploads instead of deleting anything; D changes which objects match but not what the rule does.

7. Event notifications and EventBridge

Concept

Exam facts

Developer angle

{
  "LambdaFunctionConfigurations": [{
    "Id": "extract-pdf-text",
    "LambdaFunctionArn": "arn:aws:lambda:eu-west-1:111122223333:function:extract-text",
    "Events": ["s3:ObjectCreated:*"],
    "Filter": { "Key": { "FilterRules": [
      { "Name": "prefix", "Value": "inbox/" },
      { "Name": "suffix", "Value": ".pdf" }
    ] } }
  }],
  "QueueConfigurations": [{
    "Id": "audit-deletes",
    "QueueArn": "arn:aws:sqs:eu-west-1:111122223333:object-deletes",
    "Events": ["s3:ObjectRemoved:*"]
  }],
  "EventBridgeConfiguration": {}
}
aws lambda add-permission --function-name extract-text --statement-id s3-docs-in \
  --action lambda:InvokeFunction --principal s3.amazonaws.com \
  --source-arn arn:aws:s3:::docs-in --source-account 111122223333
aws s3api put-bucket-notification-configuration --bucket docs-in \
  --notification-configuration file://notification.json
aws s3api get-bucket-notification-configuration --bucket docs-in
import urllib.parse

import boto3

s3 = boto3.client("s3")

def handler(event, context):
    for record in event.get("Records", []):          # the s3:TestEvent message has no Records
        bucket = record["s3"]["bucket"]["name"]
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])  # keys arrive URL-encoded
        if not key.startswith("inbox/"):
            continue                                  # never react to our own output
        size = s3.head_object(Bucket=bucket, Key=key)["ContentLength"]
        print(f"processing s3://{bucket}/{key} ({size} bytes)")

EventBridge rule pattern that matches only large uploads under one prefix:

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "bucket": { "name": ["docs-in"] },
    "object": {
      "key": [{ "prefix": "inbox/" }],
      "size": [{ "numeric": [">", 1048576] }]
    }
  }
}

Traps

Practice questions

  1. A developer wants every .csv file uploaded under incoming/ to be processed by two independent services: a Lambda function and an application that consumes an SQS queue. Creating a second event notification with the same prefix and suffix fails with an error about overlapping configurations. Which solution meets the requirements with the LEAST operational overhead?

    • A. Publish the notification to one SNS standard topic that both the function and the queue subscribe to.
    • B. Change the Lambda function so that it also forwards a copy of every event it receives to the SQS queue.
    • C. Replicate the objects to a second bucket so that each bucket triggers one of the consumers.
    • D. Change the second configuration's suffix to .CSV so that the two filters no longer overlap.
  2. A developer configures an S3 event notification that invokes a Lambda function for s3:ObjectCreated:*, but put-bucket-notification-configuration fails because S3 can't validate the Lambda destination. For another bucket, the team wants events delivered to an SQS FIFO queue to keep per-key ordering. Which TWO statements are correct? (Select TWO.)

    • A. The Lambda execution role must include the s3:PutBucketNotification permission for the bucket before S3 can call it.
    • B. The function's resource-based policy must allow s3.amazonaws.com to call lambda:InvokeFunction for that bucket.
    • C. The bucket must have versioning enabled before notifications can target Lambda.
    • D. S3 can't notify an SQS FIFO queue directly, so the events should be routed through Amazon EventBridge.
    • E. The SQS FIFO queue must be created in a different Region from the bucket.
Answers
  1. A. One notification to an SNS topic fans the same event out to both subscribers with no code. B couples the services and adds code; C doubles storage and adds replication lag; D is case-sensitive, so lowercase .csv files would reach only one consumer.
  2. B, D. S3 validates that it can invoke the function, which the function's resource-based policy provides, and FIFO queues are reachable only through EventBridge. A puts a configuration permission in the wrong place (the caller needs it, not the function); C isn't a requirement; E is wrong because destinations must be in the bucket's Region.

8. Performance multipart uploads and Transfer Acceleration

Concept

Exam facts

Developer angle

import boto3
from boto3.s3.transfer import TransferConfig
from botocore.config import Config

# Parallel multipart upload through the Transfer Acceleration endpoint
s3 = boto3.client("s3", config=Config(s3={"use_accelerate_endpoint": True}))
transfer = TransferConfig(multipart_threshold=100 * 1024 * 1024,
                          multipart_chunksize=64 * 1024 * 1024,
                          max_concurrency=10)
s3.upload_file("survey-2026.zip", "field-uploads", "asia/survey-2026.zip", Config=transfer)

# Read only the first KiB of the object (for example, a file header)
part = s3.get_object(Bucket="field-uploads", Key="asia/survey-2026.zip", Range="bytes=0-1023")
print(part["ContentRange"], len(part["Body"].read()))
aws s3api put-bucket-accelerate-configuration --bucket field-uploads \
  --accelerate-configuration Status=Enabled
aws configure set default.s3.use_accelerate_endpoint true
aws configure set default.s3.multipart_chunksize 64MB

# The low-level multipart flow that the tools run for you
aws s3api create-multipart-upload --bucket field-uploads --key raw/big.bin   # returns UploadId
aws s3api upload-part --bucket field-uploads --key raw/big.bin --part-number 1 \
  --body part-001 --upload-id "$UPLOAD_ID"                                     # returns ETag
aws s3api complete-multipart-upload --bucket field-uploads --key raw/big.bin \
  --upload-id "$UPLOAD_ID" --multipart-upload file://parts.json
aws s3api list-multipart-uploads --bucket field-uploads                       # find leftovers
aws s3api abort-multipart-upload --bucket field-uploads --key raw/big.bin --upload-id "$UPLOAD_ID"
aws s3api get-object --bucket field-uploads --key raw/big.bin --range bytes=0-1023 first-kib.bin

parts.json lists every part number with the ETag returned by upload-part: {"Parts":[{"PartNumber":1,"ETag":"\"8a2a1f6c...\""}]}.

Traps

Practice questions

  1. An analytics job running in the bucket's Region reads about 40,000 small objects per second, all stored under the single prefix data/, and receives many HTTP 503 Slow Down responses. Which change most directly raises the sustainable read rate?

    • A. Enable S3 Transfer Acceleration on the bucket and send all reads through the s3-accelerate endpoint instead.
    • B. Move the objects to the S3 Standard-IA storage class.
    • C. Spread the objects across several prefixes such as data/0/ to data/9/ and read them in parallel.
    • D. Increase the multipart upload part size that the writer uses to 100 MB.
  2. Field teams in Asia upload survey files of 2–20 GB to a bucket in us-east-1 over unreliable links. Uploads are slow and often restart from zero after a dropped connection. Which TWO changes improve speed and resilience? (Select TWO.)

    • A. Use multipart upload (for example, the SDK transfer manager) so parts go in parallel and only failed parts are retried.
    • B. Upload each file with a single PutObject call to keep the number of requests low.
    • C. Create a new bucket whose name contains periods, so that it can match the company's domain name for uploads.
    • D. Enable S3 Transfer Acceleration on the bucket and send uploads to the s3-accelerate endpoint.
    • E. Store the files in S3 One Zone-IA so that S3 spends less time copying data across Availability Zones during the upload.
Answers
  1. C. About 5,500 GETs per second are supported per prefix, so 40,000 reads per second need around eight or more prefixes read in parallel. A only helps long-distance transfers; B changes price, not request capacity; D affects uploads, not reads.
  2. A, D. Multipart upload parallelises the transfer and retries only failed parts, and Transfer Acceleration shortens the long-distance path. B can't exceed 5 GB and restarts entirely on failure; C breaks Transfer Acceleration, which doesn't allow periods; E changes storage resilience, not upload speed.

9. Presigned URLs CORS and static websites

Concept

Exam facts

Developer angle

import boto3

s3 = boto3.client("s3", region_name="eu-west-1")

# Private download for 15 minutes
download_url = s3.generate_presigned_url(
    "get_object", Params={"Bucket": "billing-docs", "Key": "invoices/2026/inv-1001.pdf"}, ExpiresIn=900)

# Direct upload of one key for 10 minutes; the client must send the same Content-Type
upload_url = s3.generate_presigned_url(
    "put_object", ExpiresIn=600,
    Params={"Bucket": "user-uploads", "Key": "uploads/u-42/avatar.png", "ContentType": "image/png"})

# Browser form upload limited to 20 MiB
form = s3.generate_presigned_post(
    "user-uploads",
    "uploads/u-42/report.pdf",
    Conditions=[["content-length-range", 1, 20 * 1024 * 1024]],
    ExpiresIn=600,
)
print(form["url"], form["fields"])
aws s3 presign s3://billing-docs/invoices/2026/inv-1001.pdf --expires-in 900
curl -X PUT -T avatar.png -H "Content-Type: image/png" "$UPLOAD_URL"

aws s3api put-bucket-cors --bucket user-uploads --cors-configuration file://cors.json

# Static website: index/error documents, relax BPA for policies, public-read policy
aws s3 website s3://www.example.com/ --index-document index.html --error-document error.html
aws s3api put-public-access-block --bucket www.example.com \
  --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=false,RestrictPublicBuckets=false
aws s3api put-bucket-policy --bucket www.example.com --policy file://public-read.json

cors.json for a single-page app that uploads with presigned PUTs and needs the ETag:

{
  "CORSRules": [{
    "ID": "spa-uploads",
    "AllowedOrigins": ["https://app.example.com"],
    "AllowedMethods": ["GET", "PUT"],
    "AllowedHeaders": ["Content-Type", "x-amz-*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }]
}

public-read.json for the website bucket:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "PublicReadForWebsite",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::www.example.com/*"
  }]
}

Traps

Practice questions

  1. A mobile app lets signed-in users upload profile videos of up to 2 GB directly to S3 without routing the bytes through API Gateway. Each upload must be possible for only 10 minutes and only to that user's own key. What should the backend return to the app?

    • A. The access key of an IAM user that has s3:PutObject permission on the bucket.
    • B. A presigned URL for PutObject on uploads/<user-id>/video.mp4 that expires after 600 seconds.
    • C. A URL created with aws s3 presign --expires-in 600 for the user's key.
    • D. The bucket's static website endpoint, after enabling website hosting and adding a CORS rule that allows PUT.
  2. A single-page app served from https://app.example.com uploads files with JavaScript straight to https://media-bucket.s3.eu-west-1.amazonaws.com using presigned PUT URLs. The browser reports that the preflight request was rejected, and the app also needs to read the ETag response header after each upload. Which TWO configuration items fix this? (Select TWO.)

    • A. A CORS rule on the bucket that hosts the single-page app, allowing PUT requests from https://app.example.com.
    • B. Turning off Block Public Access on media-bucket.
    • C. A CORS rule on media-bucket that allows PUT and the app's headers from https://app.example.com.
    • D. Enabling static website hosting on media-bucket.
    • E. ETag listed in the ExposeHeaders element of that CORS rule.
Answers
  1. B. A presigned PUT limits the upload to one key and 10 minutes while the backend keeps its own credentials. A hands out long-term credentials (least secure); C produces a GET URL, so uploads fail; D's website endpoint doesn't accept uploads and would need a public bucket.
  2. C, E. The bucket being called must answer the preflight for that origin, method and headers, and ETag must be exposed for JavaScript to read it. A is the wrong bucket; B is unrelated, because the presigned signature authorizes the request; D serves public HTTP pages and has nothing to do with CORS for the REST endpoint.

10. Access Points and Object Lambda

Concept

Exam facts

Developer angle

# One access point per consumer; one restricted to a VPC
aws s3control create-access-point --account-id 111122223333 --name billing-ap \
  --bucket data-lake-prod
aws s3control create-access-point --account-id 111122223333 --name reporting-vpc-ap \
  --bucket data-lake-prod --vpc-configuration VpcId=vpc-0a1b2c3d4e5f67890
aws s3control put-access-point-policy --account-id 111122223333 --name billing-ap \
  --policy file://billing-ap-policy.json
aws s3control get-access-point --account-id 111122223333 --name reporting-vpc-ap

# Object calls through the access point: pass its ARN (or alias) as the bucket
aws s3api get-object --bucket arn:aws:s3:eu-west-1:111122223333:accesspoint/billing-ap \
  --key billing/2026/q3.csv q3.csv

billing-ap-policy.json (access point side):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::111122223333:role/billing-app" },
    "Action": ["s3:GetObject", "s3:PutObject"],
    "Resource": "arn:aws:s3:eu-west-1:111122223333:accesspoint/billing-ap/object/billing/*"
  }]
}

Bucket policy that delegates access control to the account's own access points:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DelegateToOwnAccessPoints",
    "Effect": "Allow",
    "Principal": { "AWS": "*" },
    "Action": "*",
    "Resource": ["arn:aws:s3:::data-lake-prod", "arn:aws:s3:::data-lake-prod/*"],
    "Condition": { "StringEquals": { "s3:DataAccessPointAccount": "111122223333" } }
  }]
}

Object Lambda function shape (for accounts that still use the feature):

import urllib.request

import boto3

s3 = boto3.client("s3")

def handler(event, context):
    ctx = event["getObjectContext"]
    with urllib.request.urlopen(ctx["inputS3Url"]) as resp:   # presigned URL to the original object
        original = resp.read().decode("utf-8")
    redacted = original.replace("@", "[at]")                    # stand-in for real PII redaction
    s3.write_get_object_response(RequestRoute=ctx["outputRoute"],
                                 RequestToken=ctx["outputToken"],
                                 Body=redacted.encode("utf-8"))
    return {"statusCode": 200}

Traps

Practice questions

  1. A data lake bucket is shared by 40 teams and its bucket policy has reached the 20 KB size limit. Each team needs its own permissions on its own prefix, and one team must be able to access data only from its VPC. Which solution scales with the LEAST operational overhead?

    • A. Create one access point per team with its own policy and a VPC origin for the restricted team, delegating from the bucket policy.
    • B. Create a separate bucket for each team and use S3 Replication to copy the shared datasets into every team's bucket.
    • C. Replace the bucket policy with object ACLs that grant each team access to its prefix.
    • D. Create an IAM user for each team, attach a prefix-scoped policy, and keep the access keys in AWS Secrets Manager.
  2. A company's customer-support tool must show order records with card numbers masked, while S3 keeps only the original, unmasked files. The account has never used S3 Object Lambda. Which TWO approaches keep a single stored copy? (Select TWO.)

    • A. Create an S3 Object Lambda Access Point backed by a supporting access point.
    • B. Invoke a Lambda function through a function URL or API Gateway that returns the masked record.
    • C. Store a masked second copy of each file in another bucket and keep it in sync with S3 Same-Region Replication.
    • D. Use S3 Select to drop the card-number fields on the server side.
    • E. Have the support tool download the original object and mask the field in its own code before display.
Answers
  1. A. Access points give each team a small policy of its own, a VPC origin restricts one of them, and the bucket policy shrinks to a single delegation statement. B multiplies storage and pipelines; C relies on ACLs, which are disabled by default and can't express VPC restrictions; D swaps roles for long-term keys and solves nothing about policy size.
  2. B, E. Calling Lambda through another front door or masking in the client both keep one stored copy and are available to new customers. A is closed to new customers since November 2025; C stores a second copy; D is no longer available to new customers either.

Quick decision rules

Objects, access and encryption (§1–§3)

Protection and copies (§4–§5)

Classes, events and speed (§6–§8)

Browser access and shared buckets (§9–§10)

Changed vs older material

Learn the Current column; older practice material may still show the Older material may say value. Rows enter notes/current-facts.md only after you confirm them; the rows marked pre-verified are already there and were re-checked on 2026-10-12.

Topic Older material may say Current (verified 2026-10-12) Source
§1 · Maximum object size 5 TB 50 TB (48.8 TiB) in all Regions and storage classes since 2025-12-02; single PUT still 5 GB What's New
§1 · Buckets per account 100 (soft limit) 10,000 by default, raisable to 1,000,000 (2024-11-14) What's New
§1 · Bucket naming rules Only xn-- prefix and -s3alias suffix are reserved Also reserved: sthree-, amzn-s3-demo- prefixes and --ol-s3, .mrap, --x-s3, --table-s3 suffixes; must begin and end with a letter or digit; optional account regional namespace (-an suffix) AWS docs
§1 · Conditional writes (pre-verified) Not supported; last writer wins If-None-Match: * (2024-08-20) and If-Match (2024-11-25) on PutObject, CompleteMultipartUpload; on CopyObject (destination key) since 2025-10-29; 412 on failure; s3:if-none-match / s3:if-match AWS docs · What's New
§1 · Conditional deletes (pre-verified) Deletes are unconditional DeleteObject / DeleteObjects with If-Match on general purpose buckets since 2025-09-16; s3:if-match What's New
§1 · Searching object metadata Not possible in S3; build an index (for example in DynamoDB) S3 Metadata (GA 2025-01-27) keeps queryable Iceberg metadata tables (Athena); an own index is still valid AWS docs
§2 · Object Ownership / ACLs (pre-verified) ACLs enabled (Object writer) for buckets created by API, CLI or CloudFormation Bucket owner enforced (ACLs disabled) for all new buckets since April 2023; other ACLs fail with 400 AccessControlListNotSupported AWS docs
§2 · Block Public Access default (pre-verified) On by default only for console-created buckets All four settings on for every new bucket, whatever the creation method, since April 2023; existing buckets unchanged What's New
§2 · Block Public Access levels Bucket and account level Also organization level (AWS Organizations S3 policy, all four settings together); most restrictive level wins AWS docs
§2 · Server access log destinations An S3 bucket in the same Region An S3 bucket in the same Region and account, or CloudWatch Logs (structured, cross-account/Region, KMS) AWS docs
§3 · Default encryption (pre-verified) Objects unencrypted unless default encryption or headers are set SSE-S3 on all new uploads in every bucket since 2023-01-05, free, can't be disabled; existing objects unchanged AWS docs
§3 · Number of encryption methods Four (SSE-S3, SSE-KMS, SSE-C, client-side) Five: DSSE-KMS added 2023-06-13 (aws:kms:dsse) AWS docs
§3 · KMS request quota hit by SSE-KMS 5,500 / 10,000 / 30,000 requests per second by Region 10,000 default, 20,000 in seven Regions, 100,000 in us-east-1, us-west-2, eu-west-1 (shared symmetric quota) AWS docs
§3 · SSE-C availability (pre-verified) Usable on any bucket over HTTPS Blocked by default since April 2026 for new buckets (except Bahrain, UAE) and accounts without SSE-C objects; enable with BlockedEncryptionTypes = NONE; otherwise 403 AWS docs
§3 · Re-encrypting existing objects Always rewrite them with CopyObject or Batch Operations Copy UpdateObjectEncryption switches SSE-S3/SSE-KMS objects to SSE-KMS (new key or Bucket Key) in place, keeping ETag and Last-Modified; unencrypted, SSE-C and DSSE-KMS objects still need a copy AWS docs
§4 · Object Lock on existing buckets Only at bucket creation Can be enabled on existing versioned buckets since 2023-11-20; can't be disabled afterwards AWS docs
§5 · Replication of SSE-C objects SSE-C objects aren't replicated Replicated like unencrypted and SSE-S3 objects since 2022-10-24 AWS docs
§5 · Replication Time Control SLA 99.99 % of objects within 15 minutes (SLA) SLA covers 99.9 % within 15 minutes per Region pair per month (credits below 99.9 %); 99.99 % is the design figure on the overview page AWS SLA
§6 · Storage class list Seven classes Eight: S3 Express One Zone (2023-11-28, directory buckets, single AZ) AWS docs
§6 · Glacier Flexible/Deep Archive minimum billable size 40 KB No minimum billable size; 40 KB metadata overhead per archived object (8 KB at Standard + 32 KB at the archive rate) AWS docs
§6 · Intelligent-Tiering archive thresholds "700+ days" Archive Access 90–730 days, Deep Archive Access 180–730 days AWS docs
§6 · Small objects in lifecycle transitions Objects < 128 KB skip only IA transitions and still go to Glacier Flexible Retrieval / Deep Archive Objects < 128 KB aren't transitioned to any class by default since September 2024 (older configurations keep the old behaviour until edited); override with size filters or varies_by_storage_class AWS docs
§6 · Wait before transitions to Standard-IA / One Zone-IA 30 days in S3 Standard first No minimum age since 2026-07-16 (Days 0 or more; with 0, objects are eligible at the first midnight UTC after creation); the 30-day minimum storage charge still applies What's New · AWS docs
§8 · S3 Select Filter rows server-side with SQL No longer available to new customers since 2024-07-25 AWS docs
§10 · S3 Object Lambda Available to any account Existing customers and selected APN partners only since 2025-11-07; no new capabilities AWS docs