Security·Infrastructure Defense

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.

Related: Kubernetes MCP security · eBPF runtime security · 50-question security checklist