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

3 minute read
0

My customers use earlier TLS versions. When they access content from my Amazon Simple Storage Service (Amazon S3) buckets, I want to enforce the use of a recent TLS version.

Short description

It's a best practice to use modern encryption protocols for data in transit. To enforce the use of TLS version 1.2 or later for connections to Amazon S3, update your bucket's security policy.

Note: Customers must use TLS version 1.2 or later to access content that's stored in your S3 buckets.

For more information on the deprecation of TLS versions for AWS, see TLS 1.2 to become the minimum TLS protocol level for all AWS API endpoints.

Resolution

Use a resource-based policy that's attached to your bucket to enforce using TLS 1.2 or later for all connections to your S3 buckets.

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

  1. Open the Amazon S3 console.

  2. Select the bucket from the list.

  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
            }
          }
        }
      ]
    }

    This 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 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"
            }
          }
        }
      ]
    }

Confirm that you're using modern encryption protocols for 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

The example curl command returns Access Denied because Amazon S3 detects that your request doesn't use TLS version 1.2 or later.

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.

AWS OFFICIAL
AWS OFFICIALUpdated a year ago
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 2 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.

profile pictureAWS
EXPERT
replied 2 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 2 years ago

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

profile pictureAWS
MODERATOR
replied 2 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 2 years ago

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

profile pictureAWS
MODERATOR
replied 2 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 2 years ago

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

profile pictureAWS
MODERATOR
replied 2 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 2 years ago

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

profile pictureAWS
EXPERT
replied 2 years ago

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

profile pictureAWS
EXPERT
replied 2 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 2 years ago

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

profile pictureAWS
EXPERT
replied 2 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 2 years ago

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

profile pictureAWS
MODERATOR
replied 2 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.

profile pictureAWS
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.

profile pictureAWS
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 a year ago

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

profile pictureAWS
MODERATOR
replied a year 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 a year ago

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

profile pictureAWS
MODERATOR
replied a year ago