Today’s Lesson
Security for Legal SaaS — Episode 15: Service-to-Service Authentication
Beyond the Perimeter: Internal Trust
Your API gateway authenticates external users. But what about the services behind it? When your document service calls your search index, when your billing service queries your matter database, when your AI inference service requests document content — how do these services prove their identity to each other? The “trusted network” assumption — that anything inside your VPC (Virtual Private Cloud — your isolated private network in the cloud) is legitimate — fails the moment an attacker gains internal access.
Key stat: CrowdStrike reports that lateral movement — attackers pivoting between internal services after initial compromise — is present in 70%+ of advanced threat campaigns. Internal service authentication is what stops initial access from becoming total compromise.
For legal SaaS, the internal services carry the most sensitive data — the privilege classification engine, the document store, the billing system with trust account details. If any internal service can impersonate another, a single compromised container means total data access.
Mutual TLS (mTLS)
Standard TLS authenticates the server to the client. Mutual TLS (mTLS) adds the reverse — the client also presents a certificate, and the server validates it. Both parties prove their identity cryptographically before any data flows.
How mTLS Works Between Services
| Step | What Happens |
|---|---|
| 1 | Service A connects to Service B |
| 2 | Service B presents its certificate (standard TLS) |
| 3 | Service B requests Service A’s certificate |
| 4 | Service A presents its certificate |
| 5 | Service B validates A’s certificate against a trusted CA |
| 6 | Connection established — both identities verified |
Certificate Management at Scale
| Concern | Solution |
|---|---|
| Issuance | Internal CA (e.g., HashiCorp Vault PKI, cert-manager for Kubernetes) |
| Short-lived certificates | 24-hour validity with automatic rotation |
| Revocation | Short lifetimes make revocation less critical; combine with OCSP stapling |
| Identity encoding | Service name in certificate SAN (e.g., document-service.internal.lawfirm.app) |
Operational reality: Manual certificate management for mTLS at scale is unsustainable. HashiCorp Vault’s PKI engine or Kubernetes cert-manager automates issuance and rotation. Without automation, teams disable mTLS when certificates expire during incidents — creating permanent security gaps.
Service Mesh: mTLS Without Application Changes
A service mesh is an infrastructure layer that handles service-to-service communication — including mTLS — transparently. Your application code doesn’t change; the mesh’s sidecar proxies handle authentication, encryption, and authorization.
Istio and Linkerd
| Feature | Istio | Linkerd |
|---|---|---|
| mTLS | Automatic between all meshed services | Automatic with zero-config |
| Authorization policies | Fine-grained (service A can call service B’s /api/documents but not /api/billing) | Service-level only (L4) |
| Certificate management | Built-in CA (istiod) or external CA integration | Built-in identity with short-lived certs |
| Complexity | High (Envoy proxies, complex config) | Lower (Rust proxy, simpler model) |
| Overhead | ~2–5ms latency per hop | ~1–2ms latency per hop |
Authorization Policies (Istio Example)
mTLS proves identity. Authorization policies define what each identity can do:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: document-service-access
spec:
selector:
matchLabels:
app: document-service
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/api-gateway"]
to:
- operation:
methods: ["GET"]
paths: ["/api/documents/*"]
- from:
- source:
principals: ["cluster.local/ns/default/sa/ai-inference"]
to:
- operation:
methods: ["GET"]
paths: ["/api/documents/*/content"]
This says: the API gateway can GET any document endpoint. The AI inference service can only GET document content — nothing else. Istio’s security documentation covers the full policy model.
JWT Service Tokens
For services that don’t use a mesh — or for cross-cluster communication — JWT (JSON Web Token) service tokens provide request-level authentication. Each service has a signing key; tokens include claims about the calling service’s identity and permitted scopes.
JWT vs. mTLS
| Dimension | mTLS | JWT Service Tokens |
|---|---|---|
| Authentication level | Connection (long-lived) | Per-request |
| Identity proof | Certificate from trusted CA | Signed token with claims |
| Scope/permissions | Requires separate authz layer | Encoded in token claims |
| Revocation | Certificate expiry/CRL | Short-lived tokens + token blacklist |
| Network dependency | Requires TLS termination per service | Works over any transport |
Best Practice: Combine Both
Use mTLS for transport security (encryption + connection-level identity). Use JWTs for request-level authorization (scopes, permissions, audit trail). Google’s BeyondProd paper describes this layered approach:
- mTLS ensures the network connection is between legitimate services
- JWT ensures the specific request is authorized for the claimed operation
- Short-lived tokens (5-minute validity) limit the window if a token leaks
Network Segmentation for Privileged Data
Not all internal services should talk to all other services. Network segmentation restricts communication paths so that compromise of one service doesn’t grant access to everything.
Segmentation for Legal SaaS
| Zone | Services | Access Rules |
|---|---|---|
| Public | API gateway, static assets | Accepts external traffic |
| Application | Business logic services | Only reachable from gateway |
| Data | Document store, search index, database | Only reachable from application zone |
| Privileged | Privilege classification engine, audit log, encryption key service | Only reachable from specific application services with mTLS + authz policy |
Critical rule: The privilege classification engine — which determines whether a document is attorney-client privileged — must be in the most restricted zone. If an attacker can call it directly, they can reclassify documents to non-privileged and access them through normal channels. Network segmentation + mTLS + authorization policy = defence in depth.
Practical Patterns for 3–5 Service Architectures
Not every legal SaaS team runs Kubernetes with a service mesh. For smaller deployments (3–5 services), practical options exist:
Option 1: Shared Secret + HMAC (Simplest)
Services share a secret and sign requests with HMAC-SHA256. Simple, no certificate infrastructure. Breaks down at scale — secret rotation requires coordinating all services simultaneously.
Option 2: JWT with Asymmetric Keys (Moderate)
Each service has a private key for signing. Other services have the public key for validation. Auth0’s service-to-service documentation describes the client credentials flow pattern. Scales better — adding a service means distributing one new public key.
Option 3: mTLS with Vault-Managed Certificates (Production)
HashiCorp Vault as internal CA. Each service requests short-lived certificates via the Vault API. Automatic rotation. No mesh overhead. Works with any HTTP framework that supports TLS client certificates.
Recommendation for legal SaaS startups: 3 services or fewer: JWT with asymmetric keys (client credentials flow). Use Auth0 or roll your own with short-lived tokens. 4–8 services: mTLS with Vault or cert-manager. Worth the infrastructure investment. 9+ services or Kubernetes: Full service mesh (Linkerd for simplicity, Istio for fine-grained authz).
Zero Trust: Never Trust the Network
The unifying principle is Zero Trust — no implicit trust based on network location. Every service call is authenticated and authorized, whether it crosses the internet or travels between containers on the same host.
Google’s BeyondCorp pioneered this model: “The network is always hostile. Every request must be authenticated, authorized, and encrypted.”
For legal SaaS, this means the document service doesn’t trust a request just because it came from within the VPC. It validates the caller’s identity (mTLS certificate or JWT), checks authorization (does this service have permission to read this client’s documents?), and logs the access for audit.
Conclusion
Internal services are not inherently trustworthy. A compromised container, a leaked service credential, or a misconfigured network policy can turn internal access into total data breach. Service-to-service authentication — whether through mTLS, JWTs, service mesh, or a combination — ensures that every internal call is identified, authorized, and auditable. For legal SaaS carrying privileged data across service boundaries, this isn’t architecture gold-plating — it’s the control that prevents lateral movement from becoming catastrophic disclosure.
Next episode: Email Security for SaaS — where we’ll cover SPF, DKIM, DMARC, and why your transactional emails might be landing in spam or getting spoofed.