Docs/ Bridge Human Identity with SPIFFE Workload Identity
View as .md

Bridge Human Identity with SPIFFE Workload Identity

Federate Vouch with SPIRE to bridge human and workload identity

SPIFFE gives every workload a cryptographic identity, but it does not address who deployed the workload or who authorized the action. Because Vouch is a standards-compliant OIDC provider, you can configure SPIRE (the SPIFFE reference implementation) to trust Vouch-issued tokens – bridging human and workload identity in a single architecture.

How it works

Vouch and SPIRE operate at different layers of the identity stack:

Human layer (Vouch)                    Workload layer (SPIFFE/SPIRE)
─────────────────────                  ─────────────────────────────
YubiKey tap                            Workload attestation
   Vouch OIDC ID token                  X.509-SVID or JWT-SVID
     kubectl, AWS, SSH, etc.               mTLS, service-to-service auth

The integration points:

  1. SPIRE trusts Vouch as an OIDC issuer — SPIRE validates Vouch tokens using the /.well-known/openid-configuration and JWKS endpoints to make authorization decisions based on hardware-verified human identity.
  2. Workloads get SPIFFE SVIDs — SPIRE issues short-lived X.509 or JWT credentials to workloads via the Workload API, independent of any human session.
  3. Both coexist in the same infrastructure — Humans authenticate with vouch login + YubiKey; services authenticate with SPIFFE SVIDs. Downstream systems (Kubernetes, AWS, databases) can accept both.

Prerequisites


Configure SPIRE to trust Vouch tokens

This is the integration itself: SPIRE validates Vouch OIDC tokens so that human identity can inform workload registration and authorization decisions.

Register Vouch as a federated trust domain

Add a federation block to your SPIRE Server config so SPIRE automatically fetches and refreshes Vouch’s signing keys:

# spire-server.conf
server {
  trust_domain = "example.org"
  # ...
}

plugins {
  # Existing plugins...

  KeyManager "disk" {
    plugin_data {
      keys_path = "/opt/spire/data/keys.json"
    }
  }
}

# Federation with Vouch OIDC provider
federation {
  bundle_endpoint {
    address = "0.0.0.0"
    port = 8443
  }

  federates_with "vouch.sh" {
    bundle_endpoint_url = "https://us.vouch.sh"
    bundle_endpoint_profile "https_web" {}
  }
}

The https_web profile tells SPIRE to authenticate the endpoint using its public TLS certificate (standard web PKI). SPIRE fetches the JWKS from https://us.vouch.sh/oauth/jwks and automatically refreshes it as keys rotate.

For air-gapped environments, fetch the keys manually and import them:

curl -s https://us.vouch.sh/oauth/jwks -o vouch-jwks.json

spire-server bundle set \
  -id spiffe://vouch.sh \
  -format jwks \
  -path vouch-jwks.json

Note: The manual approach requires re-running these commands whenever Vouch rotates its signing keys. Prefer the automatic federation config above unless your SPIRE Server cannot reach https://us.vouch.sh.

Create workload registration entries with deployer identity

With federation in place, you can register workloads and tag them with the Vouch-authenticated deployer’s identity. This creates an audit trail from the human who deployed a workload to the SPIFFE identity the workload runs with:

# Register a backend API workload
# The "deployer" selector records who authorized this registration
spire-server entry create \
  -spiffeID spiffe://example.org/backend-api \
  -parentID spiffe://example.org/spire-agent \
  -selector k8s:ns:production \
  -selector k8s:sa:backend-api \
  -metadata "deployer:alice@example.com"

Validate Vouch tokens in a custom attestor

For advanced use cases, you can write a custom workload attestor plugin that validates a Vouch OIDC token presented by a workload during attestation. This lets workloads bootstrap their SPIFFE identity using a short-lived Vouch token:

# A workload requests a Vouch token with a SPIFFE-specific audience
vouch credential k8s --audience spiffe://example.org

# The custom attestor validates the token against Vouch's JWKS
# and maps the `sub` claim to a SPIFFE ID
Vouch token claimSPIRE mapping
issMust match https://us.vouch.sh
subMaps to deployer identity metadata
audMust match the trust domain or a configured audience
expToken must not be expired
amrCan require ["hwk", "pin"] for hardware attestation

Patterns

Once SPIRE trusts Vouch tokens, the common architectures are standard SPIFFE/SPIRE deployments with Vouch supplying the human identity layer. The SPIRE mechanics are covered by the SPIRE documentation; what Vouch adds to each:

  • Kubernetes with human + service identity – Developers reach the API server with Vouch OIDC (see the Kubernetes guide); pods authenticate to each other with X.509-SVIDs issued by SPIRE. The layers are complementary: Vouch covers human-to-cluster, SPIRE covers pod-to-pod mTLS.
  • Multi-cloud service mesh – SPIRE servers in each cloud federate via bundle exchange so services authenticate across trust domains, while operators use the same vouch login session for access to every environment.
  • Zero-trust CI/CD with human approval – a self-hosted runner attests its own identity via SPIFFE SVID, and the deployment additionally requires a Vouch OIDC token minted by a human with a YubiKey – see CI/CD approval gates for the Vouch half of that pattern.

SPIFFE concepts reference

ConceptDescription
SPIFFE IDA URI that uniquely identifies a workload: spiffe://trust-domain/path
SVIDSPIFFE Verifiable Identity Document — an X.509 certificate or JWT that encodes a SPIFFE ID
Trust domainThe root of trust for a SPIFFE deployment (e.g., example.org)
Workload APILocal API (Unix socket) that workloads call to get their SVIDs and trust bundles
SPIRE ServerCentral component that manages identities and issues SVIDs
SPIRE AgentPer-node component that attests workloads and exposes the Workload API
FederationCross-trust-domain authentication via bundle exchange

For full details, see the SPIFFE specification and SPIRE documentation.


Troubleshooting

SPIRE cannot reach the Vouch OIDC discovery endpoint

  • Verify the SPIRE Server can make outbound HTTPS requests to https://us.vouch.sh/.well-known/openid-configuration.
  • Check network policies, firewall rules, and DNS resolution from the SPIRE Server pod or host.
  • Test connectivity: curl -s https://us.vouch.sh/.well-known/openid-configuration | jq .

SVID validation failures

  • Ensure the trust bundles are exchanged correctly between federated SPIRE servers. Check with spire-server bundle show.
  • Verify the workload registration entries match the actual pod selectors: spire-server entry show.
  • Check that the SPIRE Agent is running on the node where the workload is scheduled.

Token audience mismatch

  • The aud claim in Vouch tokens must match what SPIRE expects. When using vouch credential k8s, the default audience is kubernetes. For SPIFFE integration, specify a custom audience: vouch credential k8s --audience spiffe://example.org.
  • Verify with: vouch credential k8s --audience spiffe://example.org | jq -r '.status.token' | step crypto jwt inspect --insecure | jq '.payload.aud'

Clock skew causing JWT validation errors

  • SPIRE validates exp and nbf claims in Vouch tokens. Ensure clocks are synchronized across all nodes using NTP.
  • Vouch tokens are short-lived — even a few minutes of clock skew can cause validation failures.
  • Check the SPIRE Server logs: kubectl logs -n spire-system deployment/spire-server

“No identity issued” from Workload API

  • Confirm the SPIRE Agent is running: spire-agent healthcheck -socketPath /run/spire/sockets/agent.sock.
  • Verify that a registration entry exists for the workload: spire-server entry show -selector k8s:ns:YOUR_NAMESPACE -selector k8s:sa:YOUR_SERVICE_ACCOUNT.
  • Check that the workload’s service account and namespace match the registered selectors exactly.