Zero trust for east‑west traffic — service-to-service calls inside your cloud or datacenter — depends on reliably asserting who a workload is, ensuring communications are encrypted and authenticated, and enforcing fine‑grained policies continuously. This guide walks an engineering team through a practical, vendor-neutral implementation that combines SPIFFE workload identities, short‑lived mTLS certificates and JSON Web Tokens (JWTs) for claims-based authorization. It focuses on concrete decisions, stepwise deployment, testing and operational concerns for 2026 environments (Kubernetes + VMs + multi‑cloud).
Why this pattern?
When services authenticate using long‑lived static keys or shared credentials, lateral compromise becomes easy. A zero‑trust service mesh built around strong, rotating workload identities and short‑lived credentials limits blast radius and makes continuous authorization feasible. SPIFFE provides a standard format for workload identities (SPIFFE IDs) and a reference implementation (SPIRE) for attestation and certificate issuance. Combining mTLS for transport authentication with JWTs for application claims creates a separation of duties: mTLS proves the workload identity, and JWTs encode authorization context (roles, intent, attributes).
Intended audience and prerequisites
- DevOps/SRE teams responsible for microservices and hybrid workloads.
- Infrastructure: Kubernetes clusters (any CNCF‑compliant distro), VMs, or a mix; network policy capabilities; access to a PKI or willingness to deploy SPIRE/cert-manager.
- Familiarity with TLS, OIDC/JWT basics and service mesh concepts (Envoy, Istio, Linkerd, or sidecar patterns).
- Goal: mutual authentication with short-lived certs, workload attestation, JWT-based policy decisions at service boundaries.
High-level architecture
The guide maps to this minimal architecture:
- Workload identity provider: SPIRE server (attestation policies) or cloud workload identity service.
- Workload agents: SPIRE agent or cloud agent in each node/pod to mint short‑lived X.509 certificates with SPIFFE IDs.
- mTLS termination/verification: Sidecar proxies (Envoy) or language TLS libraries using SPIFFE certs.
- JWT provider: short‑lived service tokens issued by a secure token service (STS) or an OIDC provider; signed or bound to mTLS by sender.
- Policy engine: Envoy + external authorization (ext_authz) or local library that validates JWT claims and SPIFFE identity against policy.
Step 1 — Decide identity model and SPIFFE IDs
Design SPIFFE IDs for your environment. A SPIFFE ID is a URN-like identifier: spiffe://
- spiffe://acme.example/services/payment
- spiffe://acme.example/namespace/frontend/pod-abc
Guidelines:
- Use a single trust domain per administrative boundary. Keep it stable when migrating clusters.
- Make paths human‑readable and mapable to service names or namespaces for policy rules.
- Reserve subpaths for dynamic attachments (e.g., instance IDs) where needed.
Step 2 — Select an attestation mechanism
Attestation proves that the workload requesting a certificate actually runs on an authorized host or in an approved runtime. Options:
- Node and workload attestation with SPIRE: use x509pop for Kubernetes pods, k8s SA tokens, or node-based attestors (AWS IAM, GCE, TPM/TPM2, vsphere, cloud instance metadata).
- Cloud native attestation: use cloud provider workload identity (GCP Workload Identity, AWS IAM Roles for Service Accounts, Azure AD Workload Identities) and bridge them to SPIFFE IDs with a connector.
- Hardware-backed attestation: TPM or Nitro Enclaves for high assurance.
Start with the simplest attestation for your environment (Kubernetes service account token) and plan upgrade paths to stricter attestation for high‑value services.
Step 3 — Deploy SPIRE (or equivalent) to issue short‑lived certs
SPIRE is the common open reference — it runs a server and agents. Key steps:
- Deploy SPIRE server in a hardened control plane (multi‑AZ, restricted network access).
- Deploy SPIRE agents on each node (Kubernetes DaemonSet or VM agent).
- Create registration entries that map node/workload selectors to SPIFFE IDs. For example, a Kubernetes registration might select on pod annotations or service account.
- Configure certificate TTLs. Start with short lifetimes: 10–60 minutes typical for east‑west certs. Ensure automated renewal is functional.
Operational tips:
- Monitor SPIRE server health and agent registration metrics.
- Test rotation by forcing renewal and observing TLS handshake behavior in canary namespaces.
- Back up SPIRE server state; secure server private keys.
Step 4 — Integrate mTLS into the data plane
Options:
- Sidecar proxies (recommended for zero trust): Envoy, Istio, or another proxy that can present X.509 certs provisioned by SPIRE and validate peer certificates against a trust bundle.
- Native library integration: instrument services to use SPIFFE certificates in their TLS stacks if you prefer no sidecars.
Implementation details:
- Configure proxies to accept only mTLS connections and to extract SPIFFE IDs from peer certificates for logging and policy evaluation.
- Use the SPIRE agent’s SDS (Secret Discovery Service) or filesystem sockets to make certs available to proxies securely.
- Ensure mutual trust: proxies must validate the entire trust chain (SPIRE CA bundle or external CA).
Step 5 — Issue and use JWTs for authorization claims
mTLS confirms identity; JWTs carry application-level attributes (roles, tenant, purpose). Design choices:
- Issuer: a local STS that mints short‑lived JWTs (minutes) after validating the caller’s mTLS SPIFFE identity. Alternatively, use an OIDC provider if you can map SPIFFE identity to OIDC sub claims.
- Claims model: include the SPIFFE ID, service role, tenant id, and freshness (iat/exp). Avoid embedding long‑lived secrets or overbroad claims.
- Binding: bind JWTs to the mTLS identity (holder-of-key) or to the presented certificate by including a public key thumbprint in the token to reduce token replay risk.
Flow example:
- Service A establishes mTLS to STS using its SPIFFE cert.
- STS validates SPIFFE ID and attestation, then returns a signed JWT (exp ≈ 1–5 minutes) bound to A.
- Service A calls Service B over mTLS, presents the JWT in Authorization header. Service B verifies: JWT signature, expiration, and that the mTLS peer’s SPIFFE ID matches the token's subject/thumbprint. Then policy engine evaluates claims.
Step 6 — Policy model and enforcement
Policy is where zero trust becomes enforceable. Keep policy evaluation externalizable and auditable.
- Define policies that reference both the SPIFFE ID (who) and JWT claims (what/why). Example rule: “Only services with role=payment-runner and tenant=acme may write to /payments.”
- Enforcement points: sidecar ext_authz, API gateway, or service libraries. Prefer central policy engines (OPA/Gatekeeper/managed) with local caches for performance.
- Implement deny-by-default and least privilege. Use gradual allowlists for rollout.
Step 7 — Testing, canary and rollout
- Start in a dev namespace: require mTLS but log failures instead of blocking. Validate SPIFFE IDs emitted and JWT binding behavior.
- Progress to a canary namespace where policy enforcement is enabled for a single business function.
- Use synthetic traffic and chaotic failover tests to ensure cert renewal and token minting survive node restarts and network partitions.
- Measure latency impact; caching of token validations and policy decisions reduces overhead.
Operational concerns and hardening
- Key protection: keep server CA keys offline where possible; use hardware keys or cloud KMS for SPIRE server signing keys.
- Audit trails: log mTLS handshakes, SPIFFE IDs, token issuance events and policy decisions to centralized observability (ELK, Datadog, etc.).
- Revocation: with short‑lived certs and tokens, revocation needs are limited. For emergency revocation, rotate trust bundles and increase cert TTLs conservatively.
- Scaling: ensure SPIRE server HA, relay shards, or federated trust domains for multi‑region deployments.
Common pitfalls and how to avoid them
- Overlong token/cert TTLs — increases exposure. Keep short and monitor renewals.
- Relying on opaque service accounts — map runtime identities to SPIFFE IDs so policies are readable and auditable.
- Mixing trust domains without cross‑domain mapping — define federation patterns (SPIFFE trust bundles) explicitly.
- Not binding tokens to mTLS — unbound tokens can be replayed from a stolen bearer token; use holder‑of‑key patterns or thumbprints.
Example checklist before production cutover
- SPIRE server HA is deployed; agents configured and registering expected workloads.
- Sidecar proxies present SPIFFE certs and enforce mTLS for inter‑service traffic.
- STS issues short‑lived JWTs after mTLS validation and includes SPIFFE ID claim or key binding.
- Policy engine can evaluate SPIFFE ID + JWT claims and is integrated with the data plane ext_authz or service libs.
- Observability: logs and metrics for issuance, renewal, handshake failures, and policy denials are operational.
- Emergency plan for CA/key rotation and for incidents where attestation must be revoked.
Case study vignette (typical rollout story)
A midsize online retailer starts by deploying SPIRE in dev and a canary cluster. They map Kubernetes service accounts to SPIFFE IDs and configure Envoy sidecars to require mTLS. An internal STS mints JWTs with 2‑minute TTLs bound to the client cert thumbprint. They initially run policy in audit mode, iterated to fix false positives, and then enforce policies for payment and inventory services first. Within 3 months, lateral attacks that previously exploited long‑lived credentials were blocked at the sidecar level and token misuse was reduced because tokens were short‑lived and bound.
When to consider vendor or managed options
If your team prefers managed control planes, many cloud and SaaS vendors offer workload identity and short‑lived cert services that integrate with SPIFFE concepts. Evaluate them against these criteria:
- Trust anchor portability — can you export trust bundles if you change vendors?
- Attestation fidelity — does the provider support strong hardware-backed attestation for sensitive workloads?
- Policy integration — can you inject your policy decisions and audit logs into your existing toolchain?
Conclusion
Service‑to‑service zero trust using SPIFFE identities, short‑lived mTLS certificates and JWTs is a practical, incremental path to dramatically reduce lateral attack surface. Start with clear identity naming, sane attestation, and short TTLs. Use mTLS for cryptographic identity proof and JWTs for intent and authorization claims. Roll out gradually with audit modes, and operationalize with observability, key management and documented emergency rotation procedures. With these building blocks, engineering teams can move from implicit trust to explicit, verifiable assertions at every call.
Appendix: Further reading and tools (non-exhaustive)
- SPIFFE and SPIRE project docs (CNCF)
- Envoy and sidecar ext_authz integrations
- Open Policy Agent (OPA) for claims-based policy
- Examples of STS implementations and holder-of-key JWT patterns