mTLS stands for Mutual TLS. By default, the TLS protocol only requires a server to authenticate itself to the client. The authentication of the client to the server is managed by the application layer. The TLS protocol also offers the ability for the server to request that the client send an X.509 certificate to prove its identity. This is called mutual TLS (mTLS) as both parties are authenticated via certificates with TLS.
In this blog post, we will demonstrate how to secure business application with mTLS (authentication), AWS Lambda Authorizer (fined-grained authorization), AWS WAF + Shield (DDOS, protection against web attacks, etc.) and JWT at AWS Api Gateway. Let’s take a look how our high level design –
Introducing mutual TLS authentication for Amazon API Gateway is best way to get started. We would use PetStore HTTP application as backend since it is available at Api Gateway as sample.
For the purpose of demo, we will use self-signed certificate as documented in the link above. mTLS is good for authentication but we need fine-grained authorization for our business application. We will use Lambda Authorizer as mentioned towards the end of the article under section – Additional authorization capabilities. There is a link to Lambda authorizer blueprint in GitHub but it was not much help for .Net Core guy like me! Samples are using TOKEN based authentication and we need sample for REQUEST based authorizer.
There are few details (or links) missing in AWS documentation. It’s okay if you are AWS veteran but I am an Azure guy and I needed attention to details to pull through all the bells and whistles. I wanted to share some of those details here so they may become handy for you.
We got our custom domain configured on api gateway and mTLS is working. You may use mtls-certificates.ps1 to create slef-signed certs. Now we need to fortify our defense with lambda authorizer. What format of payload api gateway sends to lambda authorizer of REQUEST type? Working with AWS Lambda authorizers for HTTP APIs is your friend. I didn’t know the version and I used the v2 to realize it does not work! You can copy the v1 specific Json schema to create request/response classes. It was easy for me as I use VS 2019 Enterprise. Bingo! I was able to extract the clientCertificate information from requestContext. Here is a snapshot of lambda authorizer FunctionHandler and you can find the source codes in GitHub project AWSLambdaAuthorizer. if you would like to test you can use the ready to go self-signed certificate in Tests folder, be sure to import the pfx certs in certificate store on current user before calling api at https://mtlsapi.aspnet4you.com/pets.
Remember client certificate is not enough to connect to our business api! Api gateway is fortified with AWS WAF (Shield Advance is not used for this demo, too expensive!) with IPSet restriction. WAF comes first in the order of execution. This way we can fend off the bad actors. mTLS client certificate authentication comes next. If you pass the mTLS check at the gateway, our next defense is Lambda Authorizer which will pass JWT token in the authorizer context and backend Api will use JWT for fine-grained authorization.
I was running into trouble to pass authorizer context property (JWT) to request header of backend api. Thanks to Magnus Engdal for sharing the solution in Stackoverflow. CloudWatch is your friend to debug execution details of api gateway. Don’t forget to redeploy the api!
Under Method Request / HTTP Request Headers, add the context property you want to forward
And under Integration Request / HTTP Headers add context property and mapped from
For this demo, we configured WAF to allow from certain IP (CIDRs). If you come from origin ip other than what’s configured, you will receive WafFilteredException Forbidden.
Lambda authorizer will send deny policy if you are using a client certificate signed by same issuer but not the one configured for our backend.
If you pass all the checks, you will be able to call backend api with JWT token passed from lambda authorizer.
Normally, client certificate and mTls is invoked from server since mTls is used for B2B integration. I have done both positive and negative tests from my desktop. Just for the sake of demo, I installed the client certificate on my Android phone so I can test right from mobile device.
Hope you found this block post to solve your business problem. Let me acknowledge the documentations that was helpful –
- Introducing mutual TLS authentication for Amazon API Gateway
- mTLS auth with AWS API Gateway
- Mutual TLS auth with AWS API Gateway Part 2 – check certificate revocation
- Create a Visual Studio .NET Core Lambda Project
- Working with AWS Lambda authorizers for HTTP APIs
- Use API Gateway Lambda authorizers
- How to pass API Gateway authorizer context to a HTTP integration
- Tools at Aspnet4you.com for generating Jwt token