AWS API Gateway should prevent use of TLS v1

AWS has announced that this is now configurable for edge-optimised API Gateway implementations:

  • https://aws.amazon.com/about-aws/whats-new/2019/06/amazon-api-gateway-adds-configurable-transport-layer-security-version-custom-domains/
  • https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-custom-domain-tls-version.html

In order for Gateway API with additional cloud front distribution to work, we need to

  1. From AWS Console, under API Gateway go to Custom Domain Name and delete the mapped entry.
  2. Create a new cloudfront distribution with

Cloudfront settings

  • Origin Domain Name as your Gate API endpoint https://abcdfefg.execute-api.us-east-1.amazonaws.com
  • Viewer Protocol Policy as HTTPS Only
  • Origin SSL Protocols as TLSv1.2, TLSv1.1 (Uncheck TLSv1)
  • Add a CNAME entry under Alternate Domain Name to refer to custom domain name
  • and few other defaults After the above changes are completed, accessing the custom domain name on https will enforce the TLS security settings as defined in Cloudfront distribution.

I have just been working on this extensively and through a great deal of trial & error, I can document what I believe is the current optimal solution to this. The answer from suman j was the best solution back in Oct 2017 however it does have a limitation and also AWS has evolved since then.

So what is the limitation?

If you are using Lambda with the API Gateway and delete the Custom Domain Name, then manually creating a CloudFront distribution and associating a Lambda Function requires a specific Lambda version number. That is, it does not support aliases. This is problematic with CI/CD where the version numbers can continually change. However, the API Gateway Custom Domain Name Base Path Mappings do support aliases so it can be better to continue using these.

So how has AWS evolved?

As of November 2017, API Gateway supports creating Regional Endpoints in Custom Domain Names. These endpoints do not create a CloudFront distribution, thus optimising the strategy of placing your own CloudFront distribution in front of them that prevents the use of TLS v1.0.

So how do I set it all up?

The steps I used to do this (via the console) are as follows. Note that you may need to change some settings to support your particular application. For the purposes of this documentation let’s say your api is named api.example.com.

  1. In API Gateway, edit your Custom Domain Name, add a Regional Configuration, select your certificate and click on Save. Note: for regional APIs, you need to use an ACM certificate from the same region as the API. More info here: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-regional-api-custom-domain-migrate.html


  2. Copy the Target Domain Name of the newly created Regional Endpoint. (Eg d-abcdefg123.execute-api.us-east-1.amazonaws.com)


  3. In Route 53 or your DNS Provider, change the mapping of your API from the Edge Optimized CloudFront target domain name to the newly created Regional Endpoint target domain name (ie d-abcdefg123.execute-api.us-east-1.amazonaws.com).


  4. Once the DNS change has propagated, edit the Custom Domain name and delete the Edge Optimized Endpoint by clicking on the x icon. This should then enable you to then create a new CloudFront distribution with the same CNAME of your API without AWS blocking you.


  5. In API Gateway, create a new Custom Domain Name with Domain Name = regional-api.example.com, Endpoint Configuration = Regional and select the ACM Certificate. Click on Save and then Edit and add the Base Path Mapping as per your current API and click on Save. Copy the Target Domain Name of the newly created Regional Endpoint. (Eg d-xyzabcd456.execute-api.us-east-1.amazonaws.com)


  6. In Route 53 or your DNS Provider, create a new CNAME record mapping regional-api.example.com to the newly created Regional Endpoint target domain name. (Ie d-xyzabcd456.execute-api.us-east-1.amazonaws.com)


  7. In CloudFront create a new Distribution with the following settings:



ORIGIN SETTINGS:

  Origin Domain Name = regional-api.example.com
   

  After entering the above the following hidden fields should then be displayed:   

  Origin SSL Protocols = TLSv1.2 & TLSv1.1

  Origin Protocol Policy = HTTPS Only

DEFAULT CACHE BEHAVIOUR SETTINGS: (these values are what I needed for the app that calls the API to work properly)


  Viewer Protocol Policy = Redirect HTTP to HTTPS
    

  Allowed HTTP Methods = GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE

  Cached HTTP Methods = OPTIONS

  Cache Based on Selected Request Headers = Whitelist
    

  Whitelist Headers = Authorization   


  Object Caching = Customize  

  Minimum TTL = 0

  Maximum TTL = 0

  Default TTL = 0 

  Forward Cookies = All
      

  Query String Forwarding and Caching = Forward all, cache based on all
    

  Smooth Streaming = No

  Restrict Viewer Access (Use Signed URLs or Signed Cookies) = No
    

  Compress Objects Automatically = No 
   

  Lambda Function Associations = None

 

DISTRIBUTION SETTINGS:

  Price Class = Use All Edge Locations
   

  AWS WAF Web ACL = None
     

  Alternate Domain Names (CNAMEs) = test-api.example.com
     

  SSL Certificate = Custom SSL Certificate (example.com)
   

  Custom SSL Client Support = Only Clients that Support Server Name Indication (SNI)
    

  Security Policy = TLSv1.1_2016 (recommended)
   

Supported HTTP Versions = HTTP/2, HTTP/1.1, HTTP/1.0

  1. While waiting for the CloudFront Distribution creation to complete (average 40 mins), in Route 53 or your DNS Provider create a new CNAME record mapping test-api.example.com to the newly created CloudFront Domain Name (eg d123abcdefg.cloudfront.net)


  2. Once the Distribution creation has completed fully test your application against test-api.example.com


  3. If the testing is all good then update the Alternate Domain Names (CNAMEs) of your new CloudFront to be = api.example.com. (note - this will not make it ‘live’, the DNS change below is required for this)


  4. Once the distribution update is complete (average 40 mins) then in Route 53 or your DNS Provider, update the CNAME record mapping of api.example.com to the newly created CloudFront Domain Name (ie d123abcdefg.cloudfront.net)


  5. If all is working well you can now delete the Route 53 / DNS CNA test-api.example.com record plus delete the api.example.com API Gateway Custom Domain Name.


  6. For bonus points, if using Route 53 it is recommended to use A and AAAA record aliases instead of CNAME’s for the Route 53 steps above (which I have done). This reduces cost slightly, hides the underlying CloudFront distribution somewhat and also enables IPv6 support.

I hope this helps! :-)