| name | apply-microservices-security |
| description | Use when building microservices that communicate with each other — implementing service-to-service mTLS, JWT propagation for user identity, and API gateway authentication to prevent lateral movement between services. |
| source | OWASP Microservices Security Cheat Sheet (owasp.org/www-project-cheat-sheets); NIST SP 800-204 (Microservices Security); Netflix Zuul/Istio documentation; Google BeyondProd whitepaper |
| tags | ["security","owasp","microservices","mtls","jwt","service-mesh","api-gateway","developer"] |
Apply Microservices Security
Implement mutual TLS between services, propagate user identity via JWT without leaking service-to-service credentials to clients, and enforce per-service authorization — preventing lateral movement within the service mesh when any single service is compromised.
Why This Is Best Practice
Adopted by: OWASP Microservices Security Cheat Sheet (2023) is the primary reference. NIST SP 800-204 (Security Strategies for Microservices) is the federal guidance. Google's BeyondProd (2019) describes their production microservices security model, which underpins Google Cloud's security design. Netflix, Uber, and Lyft all use Istio or Envoy-based service meshes with mTLS for service-to-service authentication. All major service mesh implementations (Istio, Linkerd, Consul Connect) provide mTLS as their primary security feature.
Impact: In a microservices architecture, services typically communicate over the internal network without authentication — any compromised container on the internal network can make arbitrary API calls to any service. The 2019 Capital One breach involved lateral movement from a compromised EC2 instance to S3 — the equivalent attack in microservices would be a compromised service accessing other services' data. Netflix's chaos engineering found that 80% of theoretical attack paths in their microservices architecture relied on unauthenticated internal service calls. mTLS eliminates this attack class by requiring cryptographic proof of service identity on every call.
Why best: Network segmentation (VPCs, security groups) provides perimeter security but doesn't authenticate services within the perimeter. mTLS provides cryptographic service identity — every service proves it is who it claims to be on every call. This enables zero-trust within the service mesh: even if an attacker compromises the network, they cannot make authenticated API calls without a valid service certificate.
Sources: OWASP Microservices Security Cheat Sheet; NIST SP 800-204; Google BeyondProd whitepaper (2019); Netflix Istio adoption guide
Steps
-
Enable mTLS between services with Istio:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: payment-service-mtls
namespace: production
spec:
host: payment-service.production.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
-
Propagate user identity via JWT without service credentials:
import jwt
from datetime import datetime, timedelta
INTERNAL_SECRET = get_secret("/production/internal-jwt-secret")
EXTERNAL_JWKS_URL = "https://auth.company.com/.well-known/jwks.json"
def gateway_auth_middleware(request):
external_token = request.headers.get(, ).removeprefix()
:
user_claims = verify_external_jwt(external_token, EXTERNAL_JWKS_URL)
Exception:
Response(, )
internal_token = jwt.encode({
: user_claims[],
: user_claims[],
: user_claims[],
: datetime.utcnow(),
: datetime.utcnow() + timedelta(minutes=),
: ,
: ,
}, INTERNAL_SECRET, algorithm=)
request.headers[] = internal_token
request.headers[] = user_claims[]
request.headers[]
forward_to_service(request)
Rules
- mTLS in PERMISSIVE mode (Istio default) allows plaintext — switch to STRICT before going to production.
- Internal tokens must have short TTLs (≤5 minutes) and must not be cached beyond that window — they're disposable credentials for a single request chain.
- Services must never accept the original client Authorization header as proof of internal identity — attackers who steal a user JWT can impersonate that user to all downstream services if there's no internal token.
- AuthorizationPolicy default action is ALLOW in Istio without a policy — explicitly deploy deny-by-default policies before adding allow rules.
Common Mistakes
- Sharing a single JWT signing key across all services — compromise of any service exposes the key; use asymmetric keys (RS256) so services can verify tokens without being able to mint them.
- Forwarding the client's JWT to downstream services directly — the client JWT has a long TTL and broad scope; create short-lived internal tokens scoped to the specific downstream call.
- No service-to-service authorization (only authentication) — verifying that a call comes from payment-service doesn't mean payment-service should be able to access user-service's admin endpoints; add operation-level authorization.
- Not rotating service certificates — Istio automatically rotates certificates every 24 hours; if using manual mTLS, implement automatic rotation with ≤90 day certs.