SSL, TLS & mTLS
Transport Layer Security (TLS) is the cryptographic protocol that secures most internet communication — HTTPS, email, database connections, and service-to-service API calls. SSL (Secure Sockets Layer) is TLS’s predecessor and is now deprecated, but the term “SSL” persists colloquially. Understanding TLS matters for every engineer working on networked systems: it underlies the security of your APIs, your users’ sessions, and your internal service mesh.
TLS Basics
TLS provides three security properties for a connection:
- Confidentiality: Data is encrypted in transit. An attacker who intercepts the packets sees only ciphertext, not the plaintext request or response.
- Integrity: A message authentication code (MAC) detects tampering. Any modification of data in transit causes the MAC verification to fail, and the connection is dropped.
- Authentication: The server proves its identity using a certificate signed by a trusted Certificate Authority (CA). The client knows it’s talking to the real server, not an impersonator.
TLS sits between the TCP layer and the application layer. Once a TLS session is established, the application sends data as if it were a normal TCP stream — TLS handles encryption and decryption transparently.
The TLS Handshake
Before any application data flows, TLS performs a handshake to establish the session. TLS 1.3 (current standard) completes in 1 round-trip (1-RTT), down from 2-RTT in TLS 1.2:
- ClientHello: The client sends supported TLS versions, a list of supported cipher suites, and a random nonce.
- ServerHello + Certificate: The server selects a cipher suite, sends its certificate (containing its public key), and generates its own random nonce. In TLS 1.3, the server also immediately sends its key share.
- Certificate verification: The client verifies the server’s certificate: checks the signature chain up to a trusted root CA, verifies the hostname matches the certificate’s Common Name or Subject Alternative Name (SAN), and checks the validity period and revocation status.
- Key exchange: Both sides use the Diffie-Hellman key exchange to derive a shared secret — without ever transmitting the secret. From this shared secret, session keys are derived for symmetric encryption (AES-GCM in TLS 1.3).
- Finished: Both sides send a Finished message (MAC of the full handshake transcript) to verify neither party was tampered with. Application data can now flow.
Why Diffie-Hellman? The server’s certificate contains a public key, but if that key were used directly for encryption, an attacker who later obtained the server’s private key could decrypt all recorded past sessions. DH key exchange provides forward secrecy: session keys are ephemeral, derived fresh per connection, and deleted after the session. A future private key compromise doesn’t decrypt past traffic.
Certificates and CAs
A TLS certificate is a digital document containing:
- The server’s public key
- The domain name(s) it’s valid for (Subject Alternative Names)
- Validity period (typically 90 days for Let’s Encrypt, up to 398 days for commercial CAs)
- The CA’s digital signature over all of the above
The certificate chain of trust:
- A Root CA is a self-signed certificate whose public key is baked into operating systems and browsers. There are ~50 trusted root CAs worldwide.
- Intermediate CAs are signed by a root CA. Root CAs rarely sign leaf certificates directly — they sign intermediates and keep root keys offline.
- Leaf certificates (your server’s certificate) are signed by an intermediate CA.
When a client verifies your certificate, it walks this chain: your cert → intermediate → root. If it finds the root in its trusted store, the chain is valid.
Let’s Encrypt is a free, automated CA that issues 90-day certificates via the ACME protocol. Certbot, Caddy, and Traefik automate renewal. The 90-day limit encourages automation and limits the damage from a compromised private key.
TLS Versions
| Version | Status | Notes |
|---|---|---|
| SSL 2.0 / 3.0 | Deprecated (broken) | Multiple critical vulnerabilities (POODLE, DROWN). Never use. |
| TLS 1.0 / 1.1 | Deprecated | Vulnerable to BEAST, CRIME. Disabled by all major browsers since 2020. PCI-DSS prohibits for cardholder data. |
| TLS 1.2 | Acceptable (with care) | Still widely supported. Safe with strong cipher suites (ECDHE + AES-GCM). Avoid weak ciphers like RC4, 3DES. |
| TLS 1.3 | Current standard | 1-RTT handshake, mandatory forward secrecy, removed weak cipher suites, 0-RTT session resumption. Use this. |
Mutual TLS (mTLS)
In standard TLS, only the server presents a certificate — the client is anonymous. Mutual TLS (mTLS) requires both sides to present and verify certificates. The client proves its identity to the server, not just the reverse.
mTLS handshake additions:
- After verifying the server’s certificate, the server sends a CertificateRequest.
- The client sends its certificate.
- The server verifies the client’s certificate against a trusted CA (typically an internal CA, not a public one).
- The client signs a message with its private key to prove it possesses the key corresponding to the certificate.
Where mTLS is used:
- Service-to-service authentication in microservices: Each service has a certificate issued by an internal CA. When Service A calls Service B, B verifies A’s certificate. This proves the caller is a legitimate internal service, not an attacker who gained network access. Service meshes (Istio, Linkerd) implement mTLS transparently via sidecar proxies.
- API authentication: Machine clients (IoT devices, partner systems) authenticate with client certificates rather than API keys. Certificates are harder to steal than bearer tokens and can be scoped per device.
- Zero Trust networking: Rather than trusting traffic from inside the network perimeter, every connection is authenticated with mTLS regardless of network location.
API keys are bearer tokens — anyone who has the key can use it. mTLS requires the caller to prove possession of the private key corresponding to a certificate, and private keys never leave the machine. A stolen API key grants immediate access; a stolen certificate without the private key is useless. For high-security service-to-service communication, mTLS provides stronger assurance than API keys.
TLS Termination
TLS can be terminated at different points in your infrastructure:
- Edge termination: TLS is terminated at the load balancer or CDN. Traffic between the load balancer and backend servers is unencrypted (or uses a separate, often less-validated TLS session). Simpler certificate management — only one place to manage certs. Traffic is exposed within the internal network.
- End-to-end encryption: TLS is maintained all the way to the application server. The load balancer passes encrypted traffic through (TCP passthrough) or re-encrypts with a backend certificate. More complex, but traffic is encrypted on the internal network too.
- mTLS end-to-end (service mesh): Every hop between services uses mTLS. The service mesh sidecar handles certificate issuance and rotation automatically. Istio’s control plane (Istiod) acts as the internal CA, issuing short-lived certificates (24 hours) to each pod.
Design Considerations
- Enforce TLS 1.2+ and reject old versions. Configure your load balancer or server to refuse TLS 1.0 and 1.1 connections. Most modern clients support TLS 1.2+. In nginx:
ssl_protocols TLSv1.2 TLSv1.3;. Use strong cipher suites only — disable RC4, 3DES, and export cipher suites. - Automate certificate renewal. A certificate that expires takes down HTTPS for all users. Certificates with 90-day validity (Let’s Encrypt) require renewal every ~60 days. Use Certbot, Traefik, or cloud-managed certificates (ACM, GCP Certificate Manager) that renew automatically. Alert when certificates are within 30 days of expiry.
- Enable HSTS. HTTP Strict Transport Security tells browsers to only connect via HTTPS for a specified duration:
Strict-Transport-Security: max-age=31536000; includeSubDomains. Prevents downgrade attacks where an attacker intercepts an HTTP redirect to HTTPS. - Store private keys securely. Private keys are as sensitive as passwords. Store them in a hardware security module (HSM), a secret manager (AWS Secrets Manager, HashiCorp Vault), or at minimum with strict filesystem permissions (
chmod 600, readable only by the process that needs it). Rotate them when personnel with access leave. - Use internal CAs for service-to-service mTLS. Public CAs are for user-facing endpoints. Internal service communication should use a private CA (Vault PKI, cert-manager on Kubernetes) that you control. Issue short-lived certificates (24 hours) — rotation is automatic, and compromised certificates expire quickly without needing revocation infrastructure.
- Verify certificates in clients. Internal services calling other internal services often disable certificate verification (“skip-verify”) for simplicity. This defeats the entire point of TLS — an MITM attacker can intercept without detection. Always verify, even on internal networks.