Skip to content

Amazon S3 – Security

Data sitting in S3 nearly always has to be encrypted, and the real question is not whether but who holds the key and where the encryption happens. S3 gives you four methods, and the deck is explicit that the exam expects you to know which one fits which situation.

Server-Side Encryption (SSE) — S3 does the encrypting after receiving the object:

  • SSE-S3 — Server-Side Encryption with Amazon S3-managed keys, enabled by default. The keys are handled, managed and owned by AWS.
  • SSE-KMS — Server-Side Encryption with KMS keys stored in AWS KMS. You use AWS Key Management Service to manage the encryption keys.
  • SSE-C — Server-Side Encryption with customer-provided keys, for when you want to manage your own keys.

Client-Side Encryption — you encrypt the data yourself before it ever reaches S3.

  • Encryption uses keys handled, managed and owned by AWS.
  • The object is encrypted server-side.
  • The encryption type is AES-256.
  • The request must carry the header "x-amz-server-side-encryption": "AES256".
  • It is enabled by default for new buckets and new objects.

This is the zero-effort option: upload over HTTP(S) with the header, and S3 encrypts the object with a key you never see.

  • Encryption uses keys handled and managed by AWS KMS.
  • The advantages of KMS are user control over the key and the ability to audit key usage with CloudTrail.
  • The object is encrypted server-side.
  • The request must carry the header "x-amz-server-side-encryption": "aws:kms".

Because the key lives in KMS, KMS quotas apply to your S3 traffic:

  • When you upload, S3 calls the GenerateDataKey KMS API.
  • When you download, S3 calls the Decrypt KMS API.
  • These calls count towards the KMS quota per second, which is 5,500, 10,000 or 30,000 requests per second depending on the region.
  • You can request a quota increase using the Service Quotas console.
  • The encryption still happens server-side, but the key belongs to you and lives outside AWS entirely — you manage it end to end.
  • S3 never keeps a copy of the key you hand it: it encrypts or decrypts with it and lets it go.
  • Traffic has to run over HTTPS — there is no HTTP option here.
  • Because nothing is stored, every single HTTP request has to carry the key in its headers.
  • The work is done through a client library — the Amazon S3 Client-Side Encryption Library is the one the deck names.
  • Ciphering happens on the client, before anything is sent to Amazon S3.
  • The reverse holds on the way back: the client is what deciphers the object after retrieving it.
  • Keys and the whole encryption cycle are entirely the customer’s responsibility.

From S3’s point of view the object is just opaque bytes, which is exactly the point: AWS never has the ability to read it.

Encryption in flight is also called SSL/TLS. Amazon S3 exposes two endpoints:

  • an HTTP endpoint, not encrypted,
  • an HTTPS endpoint, encrypted in flight.

HTTPS is recommended, it is mandatory for SSE-C, and most clients use the HTTPS endpoint by default.

You can refuse plain HTTP at the bucket with a bucket policy that keys on the aws:SecureTransport condition: requests arriving over http are denied, requests arriving over https pass. The deck illustrates it with a caller sitting in a separate account, Account B.

  • SSE-S3 encryption is automatically applied to new objects stored in an S3 bucket.
  • Optionally, you can “force encryption” with a bucket policy that refuses any PUT API call without the right encryption headers (SSE-KMS or SSE-C).
  • Note the ordering: bucket policies are evaluated before default encryption.

Cross-Origin Resource Sharing (CORS) is a web-browser mechanism that allows a page loaded from one origin to make requests to another origin.

An origin is the combination of scheme (protocol) + host (domain) + port. For https://www.example.com the port is implied: 443 for HTTPS, 80 for HTTP.

  • Same origin: http://example.com/app1 and http://example.com/app2.
  • Different origins: http://www.example.com and http://other.example.com.

The requests will not be fulfilled unless the other origin allows them using CORS headers, the best-known being Access-Control-Allow-Origin.

The browser flow is a preflight followed by the real request:

OPTIONS / <- preflight request
Host: www.other.com
Origin: https://www.example.com
Access-Control-Allow-Origin: https://www.example.com <- preflight response
Access-Control-Allow-Methods: GET, PUT, DELETE
GET / <- the actual request
Host: www.other.com
Origin: https://www.example.com

If a client makes a cross-origin request against your S3 bucket, you need to enable the correct CORS headers on that bucket. The deck calls this out as a popular exam question.

You can allow a specific origin, or * for all origins.

The canonical setup: a browser loads index.html from a static-website bucket my-bucket-html, and that page requests /images/coffee.jpg from a second static-website bucket my-bucket-assets. The second bucket must return Access-Control-Allow-Origin naming the first bucket’s website endpoint, or the image is blocked.

MFA (Multi-Factor Authentication) forces users to generate a code on a device — usually a phone or a hardware token — before performing important operations on S3.

Only two operations sit behind the MFA prompt:

  • erasing an object version for good,
  • turning versioning off (suspending it) on the bucket.

Two neighboring operations deliberately do not ask for a code:

  • switching versioning on,
  • reading back the list of deleted versions.

Two constraints: versioning must be enabled on the bucket to use MFA Delete, and only the bucket owner (the root account) can enable or disable MFA Delete.

For audit purposes, you may want to log all access to your S3 buckets.

  • Any request made to S3 — from any account, authorized or denied — is logged into another S3 bucket.
  • That data can then be analyzed with data analysis tools.
  • The target logging bucket must be in the same AWS region as the source bucket.
  • The log format is documented by AWS at https://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html.

A pre-signed URL is a time-limited link to a private object. You generate them using the S3 console, the AWS CLI or an SDK.

Expiration:

  • S3 console — from 1 minute up to 720 minutes (12 hours).
  • AWS CLI — configured with the --expires-in parameter in seconds, default 3600 seconds, maximum 604800 seconds (about 168 hours).

The crucial property: users given a pre-signed URL inherit the permissions of the user who generated the URL, for GET or PUT.

Examples from the deck:

  • allow only logged-in users to download a premium video from your bucket,
  • allow an ever-changing list of users to download files, by generating URLs dynamically,
  • temporarily allow a user to upload a file to a precise location in your bucket.

11. WORM: Glacier Vault Lock and S3 Object Lock

Section titled “11. WORM: Glacier Vault Lock and S3 Object Lock”

Both features implement a WORM (Write Once Read Many) model, where data cannot be altered or deleted for a period of time. They are the answer to compliance and data-retention questions.

  • Adopt a WORM model.
  • Create a Vault Lock policy, then lock the policy for future edits — after locking it can no longer be changed or deleted.
  • Helpful for compliance and data retention; the object cannot be deleted.

Versioning must be enabled. Object Lock blocks the deletion of an object version for a specified amount of time, and comes in two retention modes.

  • Compliance mode is the absolute one: no identity at all can overwrite or delete a locked object version, and that includes the root user. The mode itself is frozen too — you cannot switch it, and you cannot shorten the retention period.
  • Governance mode is the same protection with an escape hatch: the bulk of your identities are blocked from deleting, overwriting or touching the lock settings, while a privileged few hold permissions that let them adjust the retention or remove the object outright.

Two more controls:

  • A retention period pins the object down for a set span of time. Lengthening it later is allowed.
  • A legal hold has no clock: it holds the object for as long as it stays in place, and it operates separately from any retention period. Putting one on or taking one off is a single IAM permission away — s3:PutObjectLegalHold.

Access Points simplify security management for S3 buckets. Instead of one giant bucket policy that tries to express every team’s rules, you create one access point per audience.

Each access point has:

  • its own DNS name — either an Internet origin or a VPC origin,
  • an access point policy, similar to a bucket policy, which is how you manage security at scale.

The deck’s example: a bucket with /finance/… and /sales/… prefixes keeps a simple bucket policy, while a Finance access point grants read/write to the /finance prefix, a Sales access point grants read/write to the /sales prefix, and an Analytics access point grants read access to the entire bucket.

An access point can be defined so it is accessible only from within a VPC.

  • You must create a VPC endpoint to reach the access point — either a gateway or an interface endpoint.
  • The VPC endpoint policy must allow access to both the target bucket and the access point.

The resulting chain has three policies in it: the VPC endpoint policy, the access point policy and the bucket policy.

S3 Object Lambda uses AWS Lambda functions to change an object before it is returned to the calling application.

  • Only one S3 bucket is needed. On top of it you create a supporting S3 Access Point and one or more S3 Object Lambda Access Points.
  • Different consumers call different Object Lambda Access Points and get different views of the same stored object.

Use cases from the deck:

  • redacting personally identifiable information for analytics or non-production environments,
  • converting across data formats, such as XML to JSON,
  • resizing and watermarking images on the fly using caller-specific details, such as which user requested the object.
Item What to remember for the exam
SSE-S3 AWS-owned keys, AES-256, header x-amz-server-side-encryption: AES256, enabled by default
SSE-KMS KMS-managed keys, user control + CloudTrail audit, header x-amz-server-side-encryption: aws:kms
SSE-KMS limits Upload calls GenerateDataKey, download calls Decrypt; counts against 5,500 / 10,000 / 30,000 req/s regional quota; raise it via Service Quotas
SSE-C Customer-supplied key in the headers of every request, S3 does not store it, HTTPS mandatory
Client-side Client encrypts and decrypts itself; customer owns keys and the whole cycle
In transit HTTP and HTTPS endpoints; force HTTPS with a bucket policy on aws:SecureTransport
Default encryption vs policy SSE-S3 applies automatically to new objects; a bucket policy can reject unencrypted PUTs; bucket policies are evaluated first
CORS Origin = scheme + host + port; browser sends a preflight OPTIONS; the asset bucket must return Access-Control-Allow-Origin (specific origin or *)
MFA Delete Required to permanently delete a version and to suspend versioning; not to enable versioning or list versions; needs versioning on; only the root bucket owner can toggle it
Access Logs Logs every request from every account, allowed or denied; target bucket in the same region; never log a bucket into itself
Pre-signed URLs Inherit the generator’s permissions; console 1–720 min, CLI --expires-in default 3600 s, max 604800 s
Glacier Vault Lock WORM; lock the Vault Lock policy and it can never be changed or deleted
Object Lock Needs versioning; Compliance = nobody, not even root; Governance = some users can override; retention period can be extended; legal hold is indefinite, via s3:PutObjectLegalHold
Access Points Own DNS name and access point policy per audience; VPC origin requires a VPC endpoint whose policy allows both bucket and access point
Object Lambda Transform the object on read with Lambda; one bucket, a supporting access point and Object Lambda Access Points; redaction, format conversion, on-the-fly image processing