Shared API keys are the path of least resistance for MCP gateway authentication. They’re also the biggest identity mistake you can make with agentic AI. When one key authorizes every agent that calls a tool server, you lose the ability to scope access, rotate credentials per-workload, or audit which specific agent did what. Workload identity solves this. Here’s how to set it up.

Why Shared Secrets Fail at MCP Scale

An MCP gateway sits between your AI agents and the tools they call: databases, internal APIs, code execution environments, file systems. Most teams secure that path with a single API key or bearer token distributed to every agent that needs access.

The problem scales with the number of agents. Each new agent that holds the shared secret extends the blast radius if any one of them is compromised. You can’t revoke access for a single misbehaving agent without rotating the key for all of them. You can’t tell from audit logs which agent called which tool. And you can’t enforce least-privilege because least-privilege requires knowing who’s asking.

According to NIST SP 800-207, zero trust architecture requires that every access request be authenticated and authorized independently, regardless of how the requester got onto the network. A shared secret fails that requirement by design: it authenticates the key, not the workload holding it.

Non-Human Identities (NHI) now outnumber human identities in most enterprise environments. Your access controls probably don’t reflect that yet.

What Workload Identity Actually Means for MCP Gateways

Workload identity means each agent gets its own cryptographic credential bound to that specific workload, not to a human account or a shared key. The credential proves identity at the machine level. It’s short-lived, automatically rotated, and verifiable by the gateway without a round-trip to a central authority.

The two main standards are:

SPIFFE/SPIRE: SPIFFE (Secure Production Identity Framework for Everyone) is an open standard that assigns each workload a cryptographically signed identity document called an SVID (SPIFFE Verifiable Identity Document). SVIDs are short-lived, attestation-based, and verifiable via X.509 certificates or JWT tokens. SPIRE is the reference implementation, handling issuance, rotation, and attestation automatically.

Workload Identity Federation: Cloud providers (AWS IAM Roles Anywhere, GCP Workload Identity Federation) can issue short-lived credentials to workloads based on attestation from their native platforms. These federate with OAuth 2.0 and OIDC, which makes them composable with existing authorization systems.

mTLS: Mutual TLS requires both the agent and the MCP server to present valid certificates at connection time. Neither side implicitly trusts the other. The certificate proves identity; the gateway enforces which certificate is permitted to call which tool.

The difference from a shared secret is fundamental. A certificate bound to a specific workload identifies that workload. A shared API key identifies whoever holds it, which tells you nothing useful when multiple agents hold the same value.

Step-by-Step: Setting Up MCP Gateway Authentication with Workload Identity

This setup assumes you’re running agents in a Kubernetes environment, though the same pattern applies to containers on ECS, VMs, or serverless functions.

Step 1: Choose Your Identity Standard

Before configuring anything, decide which identity mechanism fits your environment:

ScenarioRecommended approach
Kubernetes-native agentsSPIRE with Kubernetes workload attestation
AWS ECS or Lambda agentsAWS IAM Roles Anywhere with X.509 certificates
GCP Cloud Run or GKE agentsGCP Workload Identity Federation
Multi-cloud or heterogeneousSPIRE with federated trust domains
Existing service mesh (Istio, Linkerd)Leverage built-in mTLS with SPIFFE integration

If you’re starting from scratch, SPIRE is the most portable option. It runs on Kubernetes, VMs, and bare metal, and it produces standard SVIDs that work with any SPIFFE-aware gateway.

Step 2: Deploy a SPIRE Server and Agents

Install the SPIRE server and agent in your cluster. The server acts as the certificate authority and policy engine. The agent runs on each node and handles workload attestation.

# spire-server.yaml (simplified)
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: spire-server
  namespace: spire
spec:
  selector:
    matchLabels:
      app: spire-server
  template:
    spec:
      containers:
        - name: spire-server
          image: ghcr.io/spiffe/spire-server:1.9.0
          args:
            - -config
            - /run/spire/config/server.conf

The SPIRE agent runs as a DaemonSet on each node. It attests workloads using Kubernetes service account tokens and node identity, then delivers SVIDs to workloads through a Unix domain socket.

Step 3: Register Your AI Agents as Workloads

Each agent needs a registration entry that maps its deployment context (namespace, service account, pod labels) to a SPIFFE identity URI.

spire-server entry create \
  -parentID spiffe://your-trust-domain/node/k8s-node-01 \
  -spiffeID spiffe://your-trust-domain/agent/research-agent \
  -selector k8s:ns:ai-workloads \
  -selector k8s:sa:research-agent \
  -ttl 3600

The resulting SPIFFE ID (spiffe://your-trust-domain/agent/research-agent) is the cryptographic identity your MCP gateway will authenticate against. The TTL controls how often the SVID rotates — hourly rotation is a reasonable default.

Do this for each agent separately. The entire point is that agent/research-agent and agent/data-pipeline have distinct identities with distinct policy scopes.

Step 4: Configure Your MCP Gateway for Identity-Based Authentication

The gateway needs to verify incoming agent credentials and map them to policy. Two approaches work here:

Option A: mTLS with certificate validation

Configure the gateway to require client certificates and validate them against your SPIRE trust bundle. The gateway rejects any connection that doesn’t present a valid, unexpired SVID.

# Example: nginx as MCP gateway frontend
server {
    listen 443 ssl;
    ssl_certificate /etc/ssl/gateway-cert.pem;
    ssl_certificate_key /etc/ssl/gateway-key.pem;
    ssl_client_certificate /etc/ssl/spire-trust-bundle.pem;
    ssl_verify_client on;
    ssl_verify_depth 2;

    location / {
        # Extract SPIFFE ID from client cert for policy enforcement
        proxy_set_header X-SPIFFE-ID $ssl_client_s_dn;
        proxy_pass http://mcp-server-backend;
    }
}

Option B: JWT-SVID validation at the gateway

SPIRE can issue JWT-SVIDs alongside X.509 certificates. The agent presents the JWT as a bearer token. The gateway validates it using the SPIRE JWKS endpoint.

# Gateway middleware: validate JWT-SVID
import jwt
import requests

def validate_agent_identity(token: str, allowed_spiffe_ids: list[str]) -> str:
    jwks = requests.get("https://spire-server/jwks.json").json()
    claims = jwt.decode(token, jwks, algorithms=["RS256"], audience="mcp-gateway")
    spiffe_id = claims.get("sub")
    if spiffe_id not in allowed_spiffe_ids:
        raise PermissionError(f"Agent {spiffe_id} not authorized for this gateway")
    return spiffe_id

Either approach gives you the SPIFFE ID of the calling agent, which you use in the next step to scope tool access.

Step 5: Enforce Per-Agent Tool Authorization

Authentication tells you who’s calling. Authorization tells you what they’re allowed to call. Build your tool policy against SPIFFE IDs, not IP addresses or shared tokens.

# MCP gateway policy (conceptual)
policies:
  - agent: "spiffe://your-trust-domain/agent/research-agent"
    allowed_tools:
      - web_search
      - document_reader
    denied_tools:
      - code_executor
      - database_writer

  - agent: "spiffe://your-trust-domain/agent/data-pipeline"
    allowed_tools:
      - database_reader
      - database_writer
    denied_tools:
      - web_search

This is least-privilege at the workload level. The research agent can’t touch the database. The data pipeline can’t browse the web. Neither holds a credential that would let them attempt it.

Step 6: Log Every Interaction by Identity

With shared secrets, your gateway logs show IP addresses and timestamps. With workload identity, every log line includes the calling agent’s SPIFFE ID.

{
  "timestamp": "2026-08-14T14:23:01Z",
  "agent_id": "spiffe://your-trust-domain/agent/research-agent",
  "tool_called": "web_search",
  "query": "recent NIST guidance zero trust",
  "status": "authorized",
  "latency_ms": 142
}

This is the audit trail that compliance frameworks require. PCI-DSS v4.0 mandates explicit access review for each connection. DORA requires continuous authorization monitoring. An identity-indexed log satisfies both.

Step 7: Add Continuous Authorization

Authentication at connection time isn’t enough for long-running agent sessions. Add a re-authorization check at defined intervals. SPIRE handles credential rotation automatically; your gateway should re-validate the agent’s SVID on each tool call, not just at session start.

If you revoke an agent’s registration entry in SPIRE, its existing SVID expires at the next TTL boundary (hourly, in the example above). For immediate revocation, SPIRE supports certificate revocation that takes effect within minutes.

NetFoundry’s MCP Gateway: Skip the Infrastructure Work

Building this stack yourself means deploying and operating SPIRE, configuring mTLS termination, writing authorization middleware, and building the audit pipeline. That’s weeks of work before your agents call their first tool.

NetFoundry’s MCP Gateway handles all of it. It gives every agent a cryptographic identity through the same authenticate-before-connect model that underlies NetFoundry’s Zero Trust AI Enclave. Agents discover and invoke only the tools their policy explicitly permits. No shared secrets. No open inbound ports. No firewall tickets.

The identity model is the same whether you’re connecting agents in Kubernetes, on cloud VMs, or at the edge. And because NetFoundry is built on OpenZiti, the networking layer is open source and auditable.

For teams that need a production MCP gateway today without building the identity infrastructure from scratch, this is the faster path. For teams that want to understand what they’re deploying first, the steps above give you the full picture.

Common Mistakes When Migrating Away from Shared Secrets

Rotating the shared key and calling it identity. Key rotation reduces the window of exposure but doesn’t solve the blast radius or attribution problem. Rotate to per-workload certificates, not to a newer shared key.

Issuing certificates with long TTLs. A certificate that expires in a year behaves like a long-lived password. Keep TTLs short (hours, not months) and let automation handle rotation. SPIRE does this by default.

Skipping the authorization layer. Authentication proves who the agent is. It doesn’t enforce what it can do. Many teams implement mTLS and then send every authenticated agent to the same tool endpoints. The SPIFFE ID in the certificate is only valuable if your gateway policy reads it.

Treating all MCP servers as equivalent trust zones. An MCP server that accesses your production database should require stricter identity requirements than one that calls a public web search API. Tier your trust requirements to match the sensitivity of what each tool touches. As covered in our overview of zero trust tools for cloud workloads, microsegmentation at the workload layer makes this practical without network redesign.

Conflating ZTNA for users with workload identity for agents. ZTNA products secure human access to applications. They don’t issue cryptographic identities to AI agents or enforce per-agent tool authorization. If you’ve deployed ZTNA and assumed your agents are covered, check again. They’re almost certainly not.

FAQ

What is the difference between workload identity and a service account?

A service account is typically a human-managed credential (password, API key, OAuth token) assigned to a non-human workload. Workload identity is a cryptographic credential issued by an attestation-based system directly to the running workload, with no human in the issuance path. Service accounts are static and shared. Workload identities are short-lived, automatically rotated, and bound to a specific deployment context. If the workload moves to a new node or is rescheduled, the identity attestation happens again automatically.

Can I use workload identity with existing MCP servers, or do I need to redeploy them?

Most MCP servers that support the Streamable HTTP transport can accept mTLS connections without code changes, provided your infrastructure layer handles TLS termination before traffic reaches the server. A gateway or sidecar proxy handles the identity verification; the MCP server receives authorized traffic and doesn’t need to implement identity logic itself. JWT-SVID validation does require the server (or a middleware layer in front of it) to parse the bearer token, but that’s typically a library call rather than a protocol change.

How does SPIFFE workload identity work in a serverless environment?

Standard SPIFFE/SPIRE requires a node-level agent that attests workloads based on their runtime context. Serverless functions don’t have persistent nodes. The alternative is workload identity federation: AWS Lambda can assume an IAM role with a short-lived STS token, and GCP Cloud Run can use GCP Workload Identity Federation to issue OIDC tokens. These aren’t SPIFFE SVIDs, but they’re cryptographic, short-lived, and attestation-based, which means they satisfy the same security properties at the gateway.

What happens to in-flight agent requests when a SVID expires?

SPIRE rotates SVIDs before expiry, not at expiry. The agent receives a renewed SVID while the current one is still valid, which means there’s no connection interruption during normal operation. If a SVID is revoked (because the agent was compromised or decommissioned), new connections are rejected immediately. Long-lived connections that were established before revocation continue until the TTL boundary, which is why short TTLs matter: a one-hour TTL limits the exposure window to at most one hour for any compromised session.

Does using workload identity require changes to how AI agents call MCP tools?

It depends on the approach. mTLS requires the agent runtime to present a client certificate, which means the TLS configuration for the agent’s HTTP client needs to be updated to load the SVID certificate. JWT-SVID authentication requires the agent to request a token from the SPIFFE Workload API and include it as a bearer token in its MCP requests. Neither requires changes to MCP protocol logic. The MCP specification is transport-agnostic, so authentication happens at the transport layer, not the protocol layer.

How do I scope tool access by agent without modifying the MCP server?

Apply policy at the gateway. The gateway reads the verified SPIFFE ID from the client certificate or JWT, looks up the agent’s allowed tool list in a policy store, and either proxies the tool call or returns a 403 before the request reaches the MCP server. The MCP server stays focused on tool execution; the gateway handles identity enforcement. This separation keeps tool servers simple and makes policy changes instant without redeploying tool servers.

What’s the minimum viable setup for testing workload identity with a local MCP server?

For a local test, SPIRE’s Docker quickstart gets a trust domain running in under 30 minutes. Register your agent process with a selector based on its Unix UID, issue a JWT-SVID, and have your MCP server validate the JWT using the SPIRE JWKS endpoint. It’s not a production setup, but it lets you validate the authentication flow end-to-end before building infrastructure. For production, the Kubernetes quickstart is the more realistic baseline.

Sources & References