TLS and mTLS#
TLS is the encryption-and-authentication layer that turns HTTP into HTTPS, gRPC into TLS-gRPC, and any TCP/UDP stream into a private channel. The TLS handshake exchanges cryptographic keys, verifies server identity (via certificate chain), and optionally verifies the client (mTLS).
sequenceDiagram
participant C as Client
participant S as Server
C->>S: ClientHello (supported ciphers, random)
S->>C: ServerHello (chosen cipher) + Cert + Finished
C->>S: KeyShare + Finished
Note over C,S: TLS 1.3: 1-RTT before data
C->>S: encrypted application data
mTLS adds a second leg: the server demands CertificateRequest, the client presents a cert signed by a trusted CA, and the server verifies before accepting requests. Now common inside service meshes for zero-trust service-to-service identity.
TLS 1.3 (RFC 8446) is the modern standard. It cuts the handshake to one RTT, removes legacy ciphers, and bakes in forward secrecy.
TLS 1.3 handshake#
sequenceDiagram
participant C as Client
participant S as Server
C->>S: ClientHello(key_share, ciphers, SNI, ALPN)
Note over S: pick cipher, generate key_share
S->>C: ServerHello(key_share, cipher) {encrypted}<br/>Cert, CertVerify, Finished
C->>S: Finished
Note over C,S: keys derived, 1-RTT complete
C->>S: encrypted application data
- Key exchange: Ephemeral Diffie-Hellman (X25519 or P-256). Forward-secure by default; compromising server's long-term key doesn't decrypt past traffic.
- AEAD ciphers only: AES-GCM, ChaCha20-Poly1305. No CBC, no RC4.
- SNI (Server Name Indication): client says which hostname so the server can pick the right cert. Visible in cleartext until ESNI/ECH ships.
- ALPN: negotiate the next protocol (h2, h3, http/1.1) inside the handshake.
Certificates and PKI#
flowchart TB
Root[Root CA] --> Inter[Intermediate CA]
Inter --> Leaf[Server cert<br/>example.com]
Inter --> Leaf2[Server cert<br/>api.example.com]
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
The server presents a chain [leaf, intermediate, root?]. The client validates:
- Each cert signed by the next.
- The chain anchors in a trusted root (system root store).
- The leaf's
Subject Alternative Namesinclude the hostname. - Validity period (
notBefore/notAfter). - Not revoked (OCSP / OCSP stapling / CRLite).
Session resumption#
sequenceDiagram
participant C as Client
participant S as Server
Note over C,S: Initial handshake
C->>S: ClientHello
S->>C: ServerHello + NewSessionTicket
Note over C: store ticket
Note over C,S: Next session (later)
C->>S: ClientHello(psk_identity=ticket, early_data)
S->>C: ServerHello + 0-RTT accepted
- Tickets survive across servers if they share a ticket-encryption key.
- 0-RTT data: send app data on the first flight after a resumed session. Replay-safe only for idempotent endpoints.
mTLS#
sequenceDiagram
participant C as Client
participant S as Server
C->>S: ClientHello
S->>C: ServerHello + Cert + CertificateRequest
C->>S: Cert (client) + CertVerify + Finished
S->>C: Finished
Note over C,S: Both sides identified
mTLS in practice:
- Service mesh (Istio, Linkerd, Consul): the sidecar terminates inbound mTLS and originates outbound mTLS. Application code sees plaintext localhost.
- API gateways: clients in a partner ecosystem (banks, healthcare) authenticate with certs instead of API keys.
- IoT / device: long-lived device certs replace symmetric secrets.
Certificate management#
flowchart LR
CA[Internal CA<br/>SPIFFE / Vault / cert-manager] -->|cert+key| Pod1[Workload pod]
CA -->|cert+key| Pod2[Workload pod]
Mon[Rotation controller] -.30-day rotation.-> CA
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
- Short-lived certs (24h-30d) are best practice; revocation is hard, expiry is easy.
- SPIFFE/SPIRE issues workload identity certs scoped to a service.
- cert-manager (Kubernetes) automates issuance and renewal from Let's Encrypt or internal CAs.
- AWS Private CA / GCP CAS: managed PKI.
Common attacks and mitigations#
| Attack | Mitigation |
|---|---|
| Downgrade to TLS 1.0/1.1 | Disable old versions |
| Heartbleed | Patched in OpenSSL; modern stacks unaffected |
| Padding oracle | TLS 1.3 uses only AEAD; no CBC |
| Certificate transparency log | Required by browsers |
| Compromised CA | Cert pinning, public-key pinning (HPKP - deprecated), CT |
| SNI sniffing | ECH (Encrypted Client Hello) - shipping |
Performance notes#
- Session resumption + ticket sharing across edge nodes is critical for CDNs.
- TLS terminates at the LB or app; the cost is CPU. Hardware (AES-NI) makes AES-GCM nearly free; ChaCha20 is faster on mobile without AES-NI.
- mTLS adds verification cost (~1 extra signature check per connection); typically negligible.
Where TLS / mTLS is used#
flowchart TB
TLS((TLS / mTLS))
CR[Crypto primitives<br/>underlying math]
H3[HTTP/3 + QUIC<br/>TLS 1.3 integrated]
MESH[Service mesh<br/>top mTLS consumer]
GW[API Gateway<br/>termination boundary]
CR --> TLS
TLS --> H3
TLS --> MESH
TLS --> GW
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class TLS service;
class CR,H3,MESH,GW datastore;
Glossary & fundamentals#
| Tag | Concept | What it is | Page |
|---|---|---|---|
HLD |
Security fundamentals | overview page | security-fundamentals |
HLD |
HTTP3 QUIC | TLS 1.3 baked in | http3-quic |
HLD |
Service mesh | top consumer of mTLS | service-mesh |
HLD |
API gateway | TLS termination boundary | api-gateway |
Quick reference#
TLS 1.3 handshake#
1 RTT for new connections; 0 RTT for resumed. Mandatory AEAD ciphers (AES-GCM, ChaCha20-Poly1305). Forward secrecy via ephemeral DH.
Cert validation#
- Chain to trusted root
- Each cert signed by next
- Leaf SAN matches hostname
- Validity period current
- Not revoked (OCSP / CRLite)
ALPN#
h2, h3, http/1.1 negotiated in handshake.
mTLS#
- Server requests client cert
- Used by service meshes, B2B APIs, IoT
- Pairs with SPIFFE for workload identity
Cert management#
- Short-lived (1d - 30d) preferred
- cert-manager (k8s), SPIRE, Vault, AWS PCA
- Automate; revocation is hard
Performance#
- TLS termination at LB or app
- AES-NI makes AES-GCM near-free
- ChaCha20 wins on mobile without AES-NI
- mTLS adds one signature check per conn
Gotchas#
- SNI is cleartext until ECH
- 0-RTT is replay-able; restrict to safe methods
- Self-signed certs need explicit trust on every client
- Wildcard certs don't cover deeper subdomains
Refs#
- RFC 8446
- Cloudflare TLS 1.3 explainer
- SPIFFE docs
FAQ#
What is the difference between TLS and mTLS?#
TLS authenticates only the server with a certificate. mTLS adds a second leg where the client also presents a certificate, giving both sides verified identity.
How does the TLS 1.3 handshake work?#
TLS 1.3 cuts the handshake to one round trip. ClientHello carries key shares and supported ciphers, ServerHello replies with its choice plus its certificate and Finished message.
Why use mTLS in microservices?#
mTLS gives every service a verifiable identity and encrypts service-to-service traffic without relying on network perimeter trust. It is the backbone of zero-trust meshes.
What is forward secrecy in TLS?#
Forward secrecy uses ephemeral key exchange so a compromise of long-term keys later cannot decrypt past sessions. TLS 1.3 makes forward secrecy mandatory.
How do TLS certificate chains work?#
A server certificate is signed by an intermediate CA, which is signed by a root CA the client trusts. The chain validates each link until a trusted root is reached.
Related Topics#
- Security Fundamentals: the parent page for AuthN/AuthZ/Encryption
- Service Mesh: the biggest production user of mTLS
- HTTP/3 and QUIC: TLS 1.3 integrated into the transport
Further reading#
- RFC - RFC 8446 - TLS 1.3
- Blog - Cloudflare - A Detailed Look at TLS 1.3
- Doc - Let's Encrypt - How it Works
- Doc - SPIFFE - Identity for workloads