MCP server service mesh security: Istio mTLS, Envoy authorization, and Wasm filters
A service mesh moves security controls out of your MCP server code and into the infrastructure layer — enforcing mutual TLS, fine-grained access policies, and request inspection without a single line of application code change.
The service mesh security model for MCP
MCP servers deployed in microservice architectures face a challenge: every service-to-service call is a potential attack vector. Without a service mesh, each MCP server must implement its own mTLS certificate management, authorization logic, and traffic policy — duplicated across dozens of services, consistently wrong in at least some of them.
A service mesh (Istio + Envoy) externalizes these controls. The Envoy sidecar proxy intercepts all inbound and outbound traffic, and the Istio control plane applies security policies uniformly. From the MCP server's perspective, it just receives and sends plain HTTP/JSON — the mesh handles encryption, authentication, and authorization at the infrastructure layer.
Pattern 1: Mutual TLS with STRICT mode
Istio's PeerAuthentication resource enforces that all traffic to an MCP server must use mutual TLS — both sides present certificates issued by the mesh CA:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: mcp-server-mtls
namespace: mcp-prod
spec:
selector:
matchLabels:
app: mcp-server
mtls:
mode: STRICT
In STRICT mode, any caller without a valid mesh-issued certificate is rejected at the sidecar level before the request reaches your MCP server process. This eliminates the "no TLS in internal traffic" assumption that lets lateral movement attacks escalate quickly.
To verify enforcement is active:
istioctl x check-inject -n mcp-prod kubectl exec -it $(kubectl get pod -l app=mcp-server -o name | head -1) \ -c istio-proxy -- pilot-agent request GET /stats | grep ssl.handshake
Pattern 2: AuthorizationPolicy for per-path access control
Istio's AuthorizationPolicy enforces which services can call which MCP server endpoints, using SPIFFE-based service identity — not IP addresses that can be spoofed:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: mcp-server-access
namespace: mcp-prod
spec:
selector:
matchLabels:
app: mcp-server
action: ALLOW
rules:
# Only the agent-gateway service can call tool endpoints
- from:
- source:
principals:
- "cluster.local/ns/agent-prod/sa/agent-gateway"
to:
- operation:
methods: ["POST"]
paths: ["/mcp/tools/*"]
# Prometheus can scrape metrics
- from:
- source:
namespaces: ["monitoring"]
to:
- operation:
methods: ["GET"]
paths: ["/metrics"]
The implicit default is DENY — any request not matching an ALLOW rule is rejected. This means a compromised service in the same namespace cannot call MCP tool endpoints unless it's the authorized agent gateway.
Pattern 3: Wasm filters for request inspection
Envoy's Wasm filter API lets you deploy custom inspection logic as a WebAssembly plugin that runs in the sidecar proxy — inspecting MCP tool call payloads for injection patterns without modifying the server:
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: mcp-prompt-injection-filter
namespace: mcp-prod
spec:
selector:
matchLabels:
app: mcp-server
url: oci://registry.internal/wasm/mcp-inspection:v1.2
phase: AUTHN
pluginConfig:
blocked_patterns:
- "ignore previous instructions"
- "system: you are now"
- "JAILBREAK"
max_body_size_kb: 64
action_on_match: "DENY"
The Wasm plugin runs synchronously in the request path — if it returns DENY, the 403 is returned before the MCP server processes the tool call. This provides a defense-in-depth layer against prompt injection that bypasses application-level sanitization.
Pattern 4: Traffic policy and circuit breaking
Istio's DestinationRule configures circuit breaking for downstream services the MCP server calls — preventing a slow or failing downstream service from exhausting the MCP server's connection pool:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: mcp-server-circuit-breaker
namespace: mcp-prod
spec:
host: downstream-api.mcp-prod.svc.cluster.local
trafficPolicy:
outlierDetection:
consecutiveGatewayErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 100
maxRequestsPerConnection: 10
h2UpgradePolicy: UPGRADE
SkillAudit and service mesh integration
SkillAudit's security audit surfaces application-layer vulnerabilities that a service mesh cannot remediate — SQL injection in tool handlers, hardcoded credentials, and command execution patterns. The mesh enforces transport-layer controls that code review cannot guarantee. They're complementary: run an audit to fix the application layer, then deploy mesh policies to enforce the infrastructure layer.