Paul Ayegbusi

Cybersecurity

Cloud Security

Security Researcher

Cybersecurity Content Creator

Case Study: Enforcing TLS-Only Access on Amazon S3

Overview

Misconfigured cloud storage is one of the most common causes of data exposure. In this scenario-driven case study, I implemented and validated TLS-only (HTTPS) access enforcement on an Amazon S3 bucket to ensure that all data in transit is protected from interception or downgrade attacks.

This case study demonstrates how insecure (HTTP) requests are explicitly blocked at the policy level while secure (HTTPS) requests continue to function as expected.


Scenario

An organization stores configuration files in an Amazon S3 bucket that may be accessed publicly or by external systems. While encryption at rest is already enabled, there is a requirement to:

  • Enforce encryption in transit
  • Prevent any accidental or malicious access over unencrypted HTTP
  • Prove the control works through practical testing

The challenge is to enforce this without relying on object ACLs and while maintaining modern S3 security best practices.


Architecture & Constraints

  • Service: Amazon S3
  • Object Ownership: Bucket Owner Enforced (ACLs disabled)
  • Access Control: Bucket policy only
  • Security Goal: Deny all non-TLS (http://) requests

Step 1: Encryption at Rest Verification

Before enforcing transport security, the bucket was verified to use server-side encryption (SSE) to protect data at rest.


Step 2: Enforce TLS-Only Access Using Bucket Policy

To block any non-secure traffic, a bucket policy was applied that:

  • Allows public read access only for testing purposes
  • Explicitly denies any request where aws:SecureTransport is false

This approach ensures that Deny rules override Allow rules, meaning HTTP requests are blocked even if public access exists.

Bucket Policy Used

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowPublicReadForTesting",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::0xzeteo/*"
    },
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::0xzeteo/*",
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}


Step 3: Testing & Validation

To validate the control, the same object was accessed using both HTTPS and HTTP.

Secure Request (HTTPS)

A TLS-encrypted request was sent to the object URL:

curl https://0xzeteo.s3.us-east-1.amazonaws.com/service.conf.lock

Result: Request succeeded and returned the object.


Insecure Request (HTTP)

The same object was requested over HTTP:

curl http://0xzeteo.s3.us-east-1.amazonaws.com/service.conf.lock

Result: Request failed with 403 AccessDenied.

This confirms that the bucket policy successfully blocks all non-TLS traffic.


Outcome

  • ✔ Encryption at rest verified
  • ✔ Encryption in transit enforced
  • ✔ Non-secure access paths fully blocked
  • ✔ Control validated with real-world testing

This setup ensures that even if an object is publicly accessible, it cannot be retrieved insecurely.


Security Takeaways

  • Bucket policies provide stronger, centralized security control than ACLs
  • aws:SecureTransport is a simple but powerful condition for enforcing HTTPS
  • Deny rules should always be used to enforce non-negotiable security requirements
  • Public access can exist without compromising transport security when properly controlled

Cleanup Note

After validation, the temporary public-read statement can be removed while keeping the TLS enforcement rule in place.