Why Mutual TLS Is Really Hard
Cover photo by Adi Goldstein on Unsplash
What is wrong with this code?
const https = require('https');const options = { key: fs.readFileSync('client-key.pem'), cert: fs.readFileSync('client-cert.pem'), ca: fs.readFileSync('ca-cert.pem')};https.get('https://api.example.com', options, (res) => { ... });It looks fine, right? You provide the keys and the certs, and you have mTLS. Except this is a maintenance nightmare waiting to happen. The moment those certificates expire, your production environment dies. Silence. No traffic, just errors.
”But my infrastructure handles certificate rotation automatically!”
Sure, that is a fair point. If you are running on a mature cloud platform that abstracts the handshake, it feels easy. However, you are just moving the complexity elsewhere. When that automation fails (and it will), your debugging surface is massive. Is it the provider? Is it the secret manager? Is it your client config? You have traded simple code for a distributed system dependency.
”Isnt mTLS just about better security?”
It is about trust, actually. It proves who the client is, not just who the server is. The problem is that certificate lifecycle management is hard. You need to rotate keys, distribute them securely, and handle revocation lists. If you mess up the revocation list, you end up with services that cannot talk to each other while you scramble to update thousands of clients.
I often find that simple API keys or tokens are enough for most internal services. If you do not have a dedicated platform team to handle the certificate heavy lifting, do not force mTLS on your team. You will likely regret it. (I have seen this break CI/CD pipelines more times than I care to admit.)
The reality of distribution
Getting a certificate into a container is only half the battle. You need to rotate it without downtime. This implies you need a robust signaling mechanism to reload certificates without killing the process. Many legacy runtimes do not handle this gracefully. They hold onto the old file descriptor for the cert, meaning you stay stuck on an expired handshake until a full restart.
I admit, sometimes you really do need the level of identity assurance mTLS provides. If you are dealing with sensitive data that requires strict regulatory compliance, you have no choice. It is a necessary evil in those cases.
Before you commit to mTLS, ask yourself: do I have the operational maturity to handle certificate rotation? If the answer is no, stay away from it. Is there a simpler way to verify your caller?