Skip to content

How do I enforce TLS 1.2 or later for my S3 buckets?

3 minute read
0

My customers use Transport Layer Security (TLS) versions that are earlier than 1.2. When they access content from my Amazon Simple Storage Service (Amazon S3) buckets, I want to enforce TLS 1.2 or later.

Resolution

To enforce TLS 1.2 or later for all connections to your Amazon S3 buckets, use a resource-based policy that's attached to your buckets.

Note: This guidance only applies to general purpose S3 buckets.

Note: Amazon S3 requires TLS 1.2 or later as the default for Amazon S3 API endpoints. If you want to enforce a higher encryption protocol version, such as TLS 1.3 or later, then the examples in this article still apply.

To attach a bucket policy that requires TLS version 1.2 or later, complete the following steps:

  1. Open the Amazon S3 console.
  2. In the list of general purpose S3 buckets, select the bucket that you want to configure.
  3. Choose the Permissions tab.
  4. Under Bucket Policy, choose Edit.
  5. Add a policy to deny access to the encryption protocols that you want to prevent. For example, use the following policy to deny all HTTPS requests that use TLS versions that are earlier than 1.2:
{  "Version": "2012-10-17",  
  "Statement": [  
    {  
      "Sid": "EnforceTLSv12orHigher",  
      "Principal": {  
        "AWS": "*"  
      },  
      "Action": [  
        "s3:*"  
      ],  
      "Effect": "Deny",  
      "Resource": [  
        "arn:aws:s3:::DOC_EXAMPLE_BUCKET/*",  
        "arn:aws:s3:::DOC_EXAMPLE_BUCKET"  
      ],  
      "Condition": {  
        "NumericLessThan": {  
          "s3:TlsVersion": 1.2  
        }  
      }  
    }  
  ]  
}

The preceding policy enforces HTTPS to increase security for your data in transit.

If your workload requires HTTP traffic to Amazon S3, then use the following policy. This policy allows HTTP traffic and blocks HTTPS traffic from TLS versions that are earlier than 1.2:

{  "Version": "2012-10-17",  
  "Statement": [  
    {  
      "Sid": "UpdateTLSv12",  
      "Effect": "Deny",  
      "Principal": {  
        "AWS": "*"  
      },  
      "Action": "s3:*",  
      "Resource": "arn:aws:s3:::DOC_EXAMPLE_BUCKET/*",  
      "Condition": {  
        "Bool": {  
          "aws:SecureTransport": "true"  
        },  
        "NumericLessThan": {  
          "s3:TlsVersion": "1.2"  
        }  
      }  
    }  
  ]  
}

Review your encryption protocols for Amazon S3

To test your new policy, run the following example curl command to make HTTPS requests that use a specific legacy protocol:

curl https://${BUCKET_NAME}.s3.us-east-1.amazonaws.com/image.png -v --tlsv1.0 --tls-max 1.0

Because Amazon S3 detects that your request uses a TLS version that's earlier than 1.2, the curl command returns "Access Denied".

Note: By default, curl sends an anonymous request. If your bucket is private, then you receive a "403 Access Denied" error for any TLS version. When you test with curl, generate an Amazon S3 presigned URL to gain access to your private objects.

It's a best practice to use AWS CloudTrail Lake to identify earlier TLS connections to AWS service endpoints. You can configure the CloudTrail Lake event data store to capture management events or data events.

23 Comments

When I enter the policy shown in this article, and then click the "Save Changes" button, I receive the error "policy has invalid resource".

replied 3 years ago

@ePost-User-4212034 : You need to replace the placeholder DOC-EXAMPLE-BUCKET in the policy with your bucket name. Otherwise you will get the error.

EXPERT
replied 3 years ago

Is there an appropriate command that would indicate that the S3 bucket is correctly using TLS 1.2 rather than just validating that its not using <1.2 TLS

This still gave me access denied curl https://${BUCKET_NAME}.s3.us-east-1.amazonaws.com/image.png -v --tlsv1.2 --tls-max 1.2

replied 3 years ago

@DevinF: Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 3 years ago

Hi, I'm having issue while upload file using above permissions in php.

Tesing Bucket name: testme

Content added in bucket permission: { "Version": "2012-10-17", "Statement": [ { "Sid": "EnforceTLSv12orHigher", "Effect": "Deny", "Principal": { "AWS": "" }, "Action": "s3:", "Resource": [
"arn:aws:s3:::testme" ], "Condition": { "NumericLessThan": { "s3:TlsVersion": "1.2" } } } ] }

Code sample PHP : if($s3->putObjectFile($tmp, $bucket , $foldername , S3::ACL_PUBLIC_READ) )

Should do anything more to allow file upload from my php server to s3 bucket?

abhishek@myshala.com

replied 3 years ago

Hello, @abhishek: Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 3 years ago

Hi, it looks like a mistake in condition, it should be (not "NumericLessThan", but "NumericGreaterThanEquals" - we should allow 1.2 and greater, not less):

"Condition": { "NumericGreaterThanEquals": { "s3:TlsVersion": "1.2" } }

replied 3 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 3 years ago

Be careful: the code sample above breaks HTTP requests! The correct complete condition clause is as follows:

"Condition": {
    "Bool": {
        "aws:SecureTransport": "true"
    },
    "NumericLessThan": {
        "s3:TlsVersion": "1.2"
    }
}
replied 3 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
EXPERT
replied 3 years ago

@Alex S, the condition is correct, it denies traffic if the TLS version is less than 1.2.

EXPERT
replied 3 years ago

it works if I tested directly using curl to the full Object URL of the AWS S3 which means TLS1.2 safe, but below that gives me AccessDenied

curl https://s3.ap-southeast-1.amazonaws.com/mybucket.mydomain.com/docs/url.html -v --tlsv1.0 --tls-max 1.0

Response:
<Error><Code>AccessDenied</Code><Message>Access Denied</Message>...</Error>
curl https://s3.ap-southeast-1.amazonaws.com/mybucket.mydomain.com/docs/url.html -v --tlsv1.0 --tls-max 1.2

Response:
HTTP/1.1 200 OK

but it still gives me AccessDenied when I open the url from Cloud Flare DNS

curl https://mybucket.mydomain.com/docs/url.html -v --tlsv1.0 --tls-max 1.2

Response:
<Error><Code>AccessDenied</Code><Message>Access Denied</Message>...</Error>

that has been configured as follow

DNS Records of mydomain.com
Type: CNAME
Name: mybucket
Content: mybucket.mydomain.com.s3-ap-southeast-1.amazonaws.com
Proxy Status: true

SSL/TLS
Overview > Your SSL/TLS encryption mode is Flexible
Edge Certificates > Minimum TLS Version > TLS 1.2
Edge Certificates > TLS 1.3 > Enables

Why is that? Please help, how can I solve it?

replied 3 years ago

@Yul I suggest you create a dedicated question on re:post to get support. thanks

EXPERT
replied 3 years ago

When I implement this policy on my bucket, then make a test connection with TLS 1.0 from one PC (running curl v7.81.0), I get the correct error: "no protocols available":

$ curl https://xxxxx.xxxxx.com.s3.us-east-1.amazonaws.com/image.png -v --tlsv1.0 --tls-max 1.0
*   Trying 52.216.179.86:443...
...
* TLSv1.2 (OUT), TLS header, Unknown (21):
* TLSv1.3 (OUT), TLS alert, protocol version (582):
* error:0A0000BF:SSL routines::no protocols available
* Closing connection 0
curl: (35) error:0A0000BF:SSL routines::no protocols available

However, testing from another PC (curl v7.58.0), it accepts the TLS 1.0 connection:

$ curl https://xxxxx.xxxxx.com.s3.us-east-1.amazonaws.com/image.png -v --tlsv1.0 --tls-max 1.0
*   Trying 52.216.88.158...
...
* SSL connection using TLSv1.0 / ECDHE-RSA-AES128-SHA

Why is the behavior different for different curl versions?

Surely the policy should make the server deny all TLS 1.0 connections?

replied 3 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 3 years ago

Is there a specify date when AWS will block any S3 request with insecure TLS version?

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 2 years ago

For SSH and HTTPS connection rejections it would be nice to send a reason to the connecting party rather than these rather ambigous Amazon responses..

Access Denied Extra Details: RequestId: 8HGEXAMPLE956HG, HostId: AB012455hfd548example54523sdgdggdGBHH Connection failed.

AND..

HTTP/1.1 403 Forbidden.. Connection #0 to host example-cdn.s3.eu-west-2.amazonaws.com left intact <Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>AB15EXAMPLE148D</RequestId><HostId>fhbfhbhbf555gkmgkmgkmkg/8877t6eyhdgfhfj788=</HostId></Error>

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 2 years ago

The second policy recommendation is written incorrectly. Its missing Version and Statement at the top. I would expect AWS to be more careful in its answers when giving policy recommendations, especially those with deny in the statement.

The correct statement in full would be:

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "UpdateTLSv12",
          "Effect": "Deny",
          "Principal": {
            "AWS": "*"
          },
          "Action": "s3:*",
          "Resource": "arn:aws:s3:::DOC_EXAMPLE_BUCKET/*",
          "Condition": {
            "Bool": {
              "aws:SecureTransport": "true"
            },
            "NumericLessThan": {
              "s3:TlsVersion": "1.2"
            }
          }
    }
    ]
}
replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 2 years ago

The resource has both bucket name with and without wildcards. Do we need both for the same bucket? "arn:aws:s3:::DOC_EXAMPLE_BUCKET/*", "arn:aws:s3:::DOC_EXAMPLE_BUCKET"

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 2 years ago