SPIFFE (Secure Production Identity Framework For Everyone) is a specification. SPIRE (the SPIFFE Runtime Environment) is the reference implementation of that specification. This distinction matters more than it sounds, because understanding which layer you're working with determines what you can rely on across different environments and what you need to manage yourself.
Most explanations of SPIFFE start with the philosophy — "workload identity without passwords" — before getting to the mechanics. This one starts with the mechanics, because the philosophy becomes obvious once you understand what SVID issuance, attestation, and the Workload API actually do.
What SPIFFE Defines
SPIFFE is a set of specifications published at spiffe.io. The core deliverable is the SVID — SPIFFE Verifiable Identity Document. A SVID is proof that a particular workload has been attested by a SPIFFE implementation and assigned a specific identity. That identity is expressed as a SPIFFE ID: a URI in the form spiffe://trust-domain/path.
For example, a payment service running in your production Kubernetes cluster might have the SPIFFE ID:
spiffe://prod.example.com/ns/payments/sa/payment-processor
SVIDs come in two forms. The most common is an X.509 SVID: an X.509 certificate where the Subject Alternative Name (SAN) contains the SPIFFE ID URI. The second form is a JWT-SVID: a signed JWT where the sub claim contains the SPIFFE ID. X.509 SVIDs are used for mTLS connections between services. JWT-SVIDs are used when you need to convey workload identity through HTTP headers or across trust boundaries where mTLS isn't practical.
What SPIFFE specifies but does not implement: how workload attestation works, how the certificate authority is managed, how identity is federated across different trust domains. Those are implementation concerns.
What SPIRE Implements
SPIRE is the CNCF-graduated reference implementation of the SPIFFE specifications. Its architecture has two components:
SPIRE Server runs once per trust domain. It acts as the certificate authority for your SPIFFE trust domain — it signs SVIDs, manages the root of trust, and holds the registration entries that map attestation evidence to SPIFFE IDs. The server does not run on every node; it's a stateful component that you deploy once and configure carefully.
SPIRE Agent runs as a DaemonSet on every node where workloads run. It handles the local attestation of workloads and serves the Workload API. When a workload requests an SVID, it's talking to the SPIRE Agent on its local node via a Unix domain socket.
The attestation flow looks like this:
- A workload opens the Workload API socket (typically
/run/spire/sockets/agent.sock) and requests an SVID. - The SPIRE Agent inspects the calling process using node attestation information — in Kubernetes, this typically means pod UID, namespace, service account name, and node name, obtained via the Kubernetes API.
- The agent compares the observed attributes against registration entries in SPIRE Server. A registration entry looks like: "any workload with namespace=payments AND service-account=payment-processor gets identity spiffe://prod.example.com/ns/payments/sa/payment-processor".
- If a match is found, the agent requests a certificate from SPIRE Server and returns the SVID to the workload, along with the trust bundle needed to verify SVIDs from the same trust domain.
The issued SVID has a short TTL — typically one hour by default, though this is configurable. The SPIRE Agent automatically rotates SVIDs before they expire. Workloads that use the Workload API correctly don't manage certificate rotation; they just ask for a current SVID when they need one.
The Workload API
The Workload API is the gRPC interface between a workload and its SPIRE Agent. It's defined by SPIFFE and any compliant implementation must expose it. The two primary methods are:
FetchX509SVID— returns one or more X.509 SVIDs for the calling workload, along with the trust bundleFetchJWTSVID— returns a JWT-SVID for a specified audience
Both methods support streaming, which is how the SPIRE Agent pushes updated SVIDs to workloads before the current one expires. A workload that opens a streaming connection will receive new SVIDs without polling.
In practice, most applications don't call the Workload API directly. They use one of the client libraries — go-spiffe, java-spiffe, or the more generic spiffe-helper sidecar that writes certificate files to disk and reloads dependent processes when they rotate. The choice depends on whether you're willing to modify application code to use the SDK or prefer to keep the certificate management in a sidecar.
Registration Entries in Detail
Registration entries are where the policy lives. Each entry has:
- SPIFFE ID: the identity to issue if the entry matches
- Parent ID: the identity of the agent or intermediate authority that must attest the workload
- Selectors: the attestation attributes that must all match (AND logic by default)
- TTL: optional override for certificate lifetime
- DNS SANs: optional additional DNS names to include in the certificate
For a Kubernetes workload, a typical registration entry might look like this when expressed in SPIRE's API format:
spire-server entry create \
-spiffeID spiffe://prod.example.com/ns/payments/sa/payment-processor \
-parentID spiffe://prod.example.com/k8s-workload-registrar/node \
-selector k8s:ns:payments \
-selector k8s:sa:payment-processor \
-selector k8s:container-image:sha256:a3f9b...
The k8s:container-image selector is worth noting. If you include a specific image digest in the registration entry, then only a workload running that exact image version can get that identity. A newly deployed version with a different digest will not match the registration entry until the entry is updated. This gives you workload identity that's tied to a specific build artifact, not just a service account name — a meaningfully stronger guarantee than Kubernetes service accounts alone.
Trust Bundles and Federation
A trust bundle is the set of root CA certificates for a SPIFFE trust domain. Workloads use the trust bundle to verify SVIDs presented by other workloads. If a payment service gets an SVID from the inventory service, it validates the certificate against the trust bundle for the trust domain in that SVID's SPIFFE ID.
For most single-cluster or single-environment setups, trust bundle management is invisible — the SPIRE Agent delivers the trust bundle alongside the SVID, and everything in the same trust domain trusts each other automatically.
Federation becomes relevant when you have workloads in different trust domains that need to authenticate each other. A common pattern: production runs in one trust domain (spiffe://prod.example.com), and a partner's systems run in theirs (spiffe://api.partner.com). SPIFFE federation lets you establish trust across these trust domains without sharing root keys or setting up a joint PKI. Each side publishes its trust bundle endpoint, and the other side fetches and pins it. SVIDs from either trust domain can then be validated by workloads in the other.
We're not suggesting federation is straightforward to operate — it's one of the more complex parts of running SPIRE at scale, and it requires careful trust bundle refresh and revocation handling. But the mechanism is sound and it's a major advantage over per-integration credential exchange.
What Changes for Your Application
The practical question for an application developer: if your team adopts SPIFFE/SPIRE for service authentication, what changes in your code?
For mTLS between services, the answer is: not much, if you use the right libraries. Go's go-spiffe library provides a spiffe.TLSClientConfig() helper that creates a tls.Config populated from the Workload API. You swap your static certificate loading code for a Workload API call, and the rest of your mTLS setup stays the same:
import "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
import "github.com/spiffe/go-spiffe/v2/workloadapi"
ctx := context.Background()
source, _ := workloadapi.NewX509Source(ctx)
defer source.Close()
tlsConfig := tlsconfig.MTLSClientConfig(source, source, tlsconfig.AuthorizeAny())
client := &http.Client{
Transport: &http.Transport{TLSClientConfig: tlsConfig},
}
The X509Source handles SVID fetching and rotation. The AuthorizeAny() call is a placeholder — in production you'd replace it with tlsconfig.AuthorizeID(spiffeid.RequireIDFromString("spiffe://prod.example.com/ns/inventory/sa/inventory-api")) to pin the expected identity of the server you're connecting to.
For applications that can't be modified, spiffe-helper writes the SVID and trust bundle to disk files that your existing TLS configuration already knows how to read. You configure the paths, and spiffe-helper handles rotation and sends SIGHUP to your process when the files change.
Where Aembit Fits
SPIFFE/SPIRE gives you workload identity within your infrastructure. What it doesn't provide is a policy layer for controlling which workloads can reach which external resources — databases, SaaS APIs, third-party endpoints — using that identity as the authorization basis.
That's the gap we're focused on at Aembit. When a workload presents its SPIFFE ID as proof of identity, Aembit evaluates whether that specific workload, at that moment, is authorized to access a specific external resource. The SVID provides cryptographically attested identity. Aembit's policy layer provides the authorization decision and credential issuance — issuing a short-lived credential to the downstream resource on behalf of the workload, rather than requiring the workload to store a credential for that resource.
The result is that workloads don't carry secrets for external systems. They carry SPIFFE IDs, which they can prove are genuinely theirs. When they need to call something, they present their SPIFFE ID to Aembit, which checks the policy and hands back a just-in-time credential valid only for that call. The external system sees a valid credential and has no idea the workload never had a stored secret.
SPIFFE is a solid foundation for this model because the identity it issues is verifiable without trust in the workload itself — the identity is derived from attestation performed by a trusted authority (SPIRE), not from the workload claiming an identity. That's the property that makes ephemeral, policy-evaluated access viable: you need to know the identity is real before you can make meaningful authorization decisions.