How to Find and Block HTTP Access to AWS S3 Buckets
A common misconception in AWS cloud security is that enabling Server-Side Encryption (SSE) on an Amazon S3 bucket automatically locks down all data access to secure connections.
It’s easy to see why this happens. AWS recently made SSE-S3 the default for all new objects, ensuring data is encrypted automatically. However, encryption at rest does not equal encryption in transit.
Your bucket can have AES-256 (SSE-S3) or AWS KMS (SSE-KMS) fully enabled, but still happily accept GET or PUT requests over plaintext HTTP. If you are preparing for a security audit or hardening your organization’s cloud infrastructure, you need to address both.
Here is a breakdown of why these mechanisms are separate, how to audit your buckets for unencrypted traffic, and how to enforce HTTPS globally.
Data at Rest vs. Data in Transit
To secure an S3 bucket completely, you have to protect two different attack vectors:
- Server-Side Encryption (SSE): Protects data at rest. This ensures that once the data reaches AWS infrastructure, it is encrypted before being written to physical disks.
- SSL/TLS (HTTPS): Protects data in transit. This encrypts the network connection between the client making the API call and the AWS endpoint, preventing man-in-the-middle (MitM) attacks.
Because these operate at different layers, they are configured independently.
The SSE-C Exception: There is one scenario where encryption at rest does dictate encryption in transit. If you use Server-Side Encryption with Customer-Provided Keys (SSE-C), you are transmitting your raw encryption keys in the API headers. To prevent these keys from being intercepted, AWS proactively rejects any SSE-C request made over plain HTTP.
3 Ways to Audit Your S3 Buckets for HTTP Traffic
Before enforcing HTTPS via bucket policies, it is highly recommended to audit your current traffic. Breaking active legacy applications that rely on HTTP is a quick way to cause an outage.
1. Analyze Actual Traffic with Amazon Athena (Most Cost-Effective)
Monitoring CloudTrail Data Events for S3 can become prohibitively expensive, especially if you are managing petabyte-scale data. The most cost-effective method to analyze active traffic is to enable S3 Server Access Logging and query the logs using Amazon Athena.
S3 Access Logs record the TLS version and cipher suite for every request. If a request is made over HTTP, the tls_version field is logged as a hyphen (-).
Use this Athena query to isolate insecure traffic:
SQL
SELECT
bucket_owner,
bucket,
requestdatetime,
remoteip,
request_uri,
tls_version
FROM
s3_access_logs_table
WHERE
tls_version = '-'
This gives you the exact IP addresses and object URIs receiving HTTP requests, allowing you to track down the insecure clients.
2. Audit Compliance with AWS Config
If you want to continuously monitor which buckets allow HTTP access (regardless of whether they are actively receiving it), AWS Config is the fastest native tool.
Simply deploy the managed rule s3-bucket-ssl-requests-only. Config will evaluate all your buckets and flag any that do not have a bucket policy explicitly denying non-SSL requests.
3. Programmatic Audit via Boto3
For engineers who prefer infrastructure-as-code and automation, you can use Python and Boto3 to loop through your environment and identify vulnerable buckets.
This script iterates through all buckets, retrieves their policies, and checks if the aws:SecureTransport deny statement is missing:
Python
import boto3
import json
from botocore.exceptions import ClientError
def check_s3_https_enforcement():
s3 = boto3.client('s3')
response = s3.list_buckets()
vulnerable_buckets = []
for bucket in response['Buckets']:
bucket_name = bucket['Name']
try:
policy_response = s3.get_bucket_policy(Bucket=bucket_name)
policy = json.loads(policy_response['Policy'])
# Look for the specific Deny statement for SecureTransport == false
is_enforced = False
for statement in policy.get('Statement', []):
if statement.get('Effect') == 'Deny':
condition = statement.get('Condition', {})
bool_cond = condition.get('Bool', {})
if bool_cond.get('aws:SecureTransport') == 'false':
is_enforced = True
break
if not is_enforced:
vulnerable_buckets.append(bucket_name)
except ClientError as e:
# If the bucket has no policy, it does not enforce HTTPS
if e.response['Error']['Code'] == 'NoSuchBucketPolicy':
vulnerable_buckets.append(bucket_name)
else:
print(f"Error reading {bucket_name}: {e}")
print("Buckets not enforcing HTTPS:")
for b in vulnerable_buckets:
print(f" - {b}")
if __name__ == "__main__":
check_s3_https_enforcement()
How to Enforce HTTPS in S3
Once you have verified that no mission-critical applications are relying on plain HTTP, you can lock down the bucket.
To enforce TLS, you must attach a bucket policy that explicitly denies any request where the "aws:SecureTransport" condition is false.
Apply the following JSON to your Bucket Policy, replacing YOUR-BUCKET-NAME with your actual bucket name:
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceHTTPS",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::YOUR-BUCKET-NAME",
"arn:aws:s3:::YOUR-BUCKET-NAME/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
The Bottom Line
Securing AWS infrastructure requires defense in depth. Relying solely on S3’s default Server-Side Encryption leaves your data vulnerable in transit. By combining Athena for cost-effective traffic analysis, Boto3 for automated auditing, and strict Bucket Policies for enforcement, you can ensure your data is protected at every stage of its lifecycle.
