Using Mutual TLS authentication with Amazon API Gateway

Photo by Liane Metzler on Unsplash

The preamble

  • Hosted zone in Amazon Route 53: We will assume that a configured domain exists in Route 53 (say, ‘’)
  • AWS ACM certificate: A verified AWS Certificate Manager (ACM) issued public certificate exists that is associated with sub-domain ‘’. This certificate will be used as the identity of the custom domain name
  • Amazon S3 bucket: A bucket exists in Amazon S3 (say ‘partners-trust-store’) with appropriate bucket policies, that will be used to host a trust store bundle for partner certificates
  • Deployed REST API on Amazon API Gateway: A REST API with at least one resource and method has been deployed with a staging label (say ‘DEV’) and is accessible with the default ‘execute-api’ endpoint. Let’s consider ‘customer’ API with a GET endpoint: ‘/customer/{customer-id}’

Establish the trust

Generate certificate

openssl req -newkey rsa:2048 \
-nodes -keyout partner.key \
-out partner.csr
openssl x509 -signkey partner1.key \
-in partner.csr -req -days 365 \
-out partner.crt

Create the trust store

<Certificate Content>
<Certificate Content>
aws s3api put-object --bucket partners-trust-store \
--acl private --key trusted_partners.pem \
--body ./trusted_partners.pem

Configure custom domain name

Create custom domain name

aws apigateway create-domain-name --region ap-south-1 \
--domain-name "" \
--regional-certificate-arn arn:aws:acm:ap-south-1:<acct-id>:certificate/<cert-UUID> \
--endpoint-configuration types=REGIONAL \
--security-policy TLS_1_2 \
--mutual-tls-authentication truststoreUri=s3://partners-trust-store/trusted_partners.pem
"domainName": "",
"certificateUploadDate": "2021-06-19T10:47:19+05:30",
"regionalDomainName": "",
"regionalHostedZoneId": "Z3VO1THU9YC4UF",
"regionalCertificateArn": "arn:aws:acm:ap-south-1:<acct-id>:certificate/<cert-UUID>",
"domainNameStatus": "UPDATING",

Create API mappings

aws apigateway create-base-path-mapping \
--domain-name "" \
--base-path c360 \
--rest-api-id <api-id> \
--stage DEV

Disable default API endpoint

aws apigateway update-rest-api \
--rest-api-id <api-id> \
--patch-operations op=replace,path=/disableExecuteApiEndpoint,value='True'
aws apigateway create-deployment \
--rest-api-id <api-id> \
--stage-name DEV

Create ‘alias’ record in Route 53

"Comment": "UPSERT API gateway regional domain name record ",
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "<regionalHostedZoneId>",
"DNSName": "<regionalDomainName>",
"EvaluateTargetHealth": true
aws route53 change-resource-record-sets --hosted-zone-id <hosted-zone-id> --change-batch file://api-gw-domain-name.json

Test the setup

Figure-1: Unable to establish MTLS connection
Figure-2: Configure partner’s certificate and private key
Figure-3: MTLS connection established and API response received





Arik's father | Solution Architect | Amateur Photographer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Need to know Jupyter Notebook and Markdown Short cuts

How to Make A Free Website And Blog in 20 Minutes Or Less

Node.js: Top Trends You Should Watch in 2020

30+ Docker interview questions and answers

Development Update 04.11–04.25

DevOps Series: Automate Of Oracle 19c RAC Release Update from 19.3 to 19.4 Using Ansible — Part IV

Consumerisation of Business Software


Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Adrin Mukherjee

Adrin Mukherjee

Arik's father | Solution Architect | Amateur Photographer

More from Medium

Encrypt an already attached Unencrypted EBS volume on AWS EC2

Monitor your Employee Workstation using AWS Free Tier Services

Secure RDP to EC2 Private Instance Using AWS SSM

Build an AWS EC2 Monitoring Dashboard with CloudWatch using CDK: Step-By-Step