We use HTTPS to verify web server identities with X.509 certificates, but TLS also supports mutual authentication, where the server uses certs to verify the client’s identity. Given that passwords are a bottomless source of compromise from credential stuffing, phishing, and so on, the idea of using a cryptographically secure, phishing-resistant authentication mechanism already included in every major browsing and operating system seems like a big win.
People have been wondering why is nobody using SSL client certificates? since 2008, and in 2015 a post titled In defense of client certificates admits the “UX can be pretty horrible”. In 2020, client certificates are still too difficult to distribute and use for an internet-scale app. However, they make sense for corporate web applications, where you can use MDM to deploy client certificates to managed devices. For example, the Okta Device Trust feature uses client certificates. Is there a way to support a client certificate-based “device trust” feature natively in AWS?
I had heard a rumor that you could “hack” support for mutual TLS in an AWS web application using AWS IoT. This post confirms that rumor, although it’s not… elegant. AWS doesn’t offer an obvious way to support mutual TLS for a web application without using your own code. With the recent release of API Gateway support for Lambda and IAM authorization, it seems likely that API Gateway will eventually support mutual TLS. But the current recommendation is to handle client certificates with custom code.
I spent some time playing around with AWS IoT APIs to see how I could support a system where browsers could present a client certificate and a web application could verify it without writing custom TLS handling code. I did get something working and I thought it was important to document since I didn’t see a solution like it anywhere else.
Generating an IoT certificate for the MacOS keychain
The first step is to put a certificate in the MacOS keychain. While I did this manually, it’s an “exercise to the reader” to implement something similar with an MDM system.
I modeled my computer as an AWS IoT Thing and generated a certificate for it using the AWS CLI:
aws iot create-keys-and-certificate --certificate-pem-outfile "iot.cert.pem" --public-key-outfile "iot.public.key" --private-key-outfile "iot.private.key"