Workload identity with SPIFFE and SPIRE
What are SPIFFE and SPIRE?
SPIFFE (Secure Production Identity Framework For Everyone) is an open standard for workload identity: the same role OAuth plays for human identity, but built for systems that come and go at machine speed instead of human speed. A SPIFFE identity is a URI (a SPIFFE ID, like spiffe://edera.dev/zone/<uuid>) bound to a short-lived credential like an X.509 certificate. That document is called an SVID (SPIFFE Verifiable Identity Document). A workload uses it to authenticate itself to other workloads and services.
SPIRE is the reference implementation of SPIFFE: an identity provider that attests workloads and issues them SVIDs. SPIRE is deliberately unopinionated about what “attestation” means; it ships plugins for AWS, GCP, Kubernetes, and more, each answering the same question in a different environment: “do you know this workload, and can you prove it’s who it claims to be?” Both projects are CNCF-graduated.
Edera integrates with SPIRE rather than inventing its own identity format, so that workloads running in Edera zones can carry the same kind of identity as workloads anywhere else in your infrastructure, and so Edera can plug into whatever SPIFFE-based system you already run, like a service mesh, an existing SPIRE deployment, or an internal PKI.
Why zones need their own attestation
A typical SPIRE deployment runs one agent per node, and that agent attests every workload scheduled to it. Edera zones break that assumption: each zone is a strongly isolated virtual machine, not a process sharing a node’s kernel with its neighbors, so a single node-wide SPIRE agent can’t see inside it.
Edera resolves this by running a SPIRE agent inside each SPIRE-enabled zone rather than once per node. That agent needs its own way to prove it is legitimate before the SPIRE server will talk to it, which is what the edera-hypervisor node attestor plugin is for: it lets the SPIRE server ask Edera’s daemon, not the zone itself, whether a given zone is one Edera actually launched. The daemon answers over an object capability (dev.edera/spire/attestation) rather than a socket the zone could spoof. It includes the content digests of the zone’s kernel and initrd so a registration entry can require an exact boot image, not just a claimed identity.
Architecture
Getting workload identity running has three layers, each a separate protect-ctl operation:
- A SPIRE server, launched as an Edera zone:
protect-ctl host spire-start. The daemon runs this like any other zone-hosted workload, using the[spire]server image and config fromdaemon.toml. - A SPIRE-enabled zone, launched with
protect-ctl zone launch --with-spire. This is an ordinary Edera zone, but with a SPIRE agent running alongside the workloads inside it. The agent authenticates itself to the server using theedera-hypervisornode attestor, and registers itself as the parent for any workload identities issued inside that zone. - Workloads, launched normally inside that zone, optionally requesting identity.
Because every zone gets its own agent, a deployment with many zones has many more SPIRE agents than a typical node-per-agent setup. Selectors (below) are what let a single SPIRE server tell them apart.
Delivering identity to a workload
Edera doesn’t assume a workload wants an identity just because its zone can issue one, so a SPIRE-enabled zone get nothing SPIFFE-related by default. protect-ctl workload launch exposes two independent grants:
--enable-identity: the zone agent fetches an SVID on the workload’s behalf and mounts it read-only at/run/spire/identity(svid.<n>.pem,svid.<n>.key,bundle.<trust-domain>.pem). This is for workloads that have no idea what SPIFFE is. The identity just shows up as files.--enable-spire-access: the zone agent’s SPIRE Workload API socket is mounted read-only at/shared/zone/sockets/agent.sock. This is for workloads that already speak SPIFFE and want to fetch, watch, and rotate their own SVID directly.
A workload can request either, both, or neither. Requesting --enable-spire-access alone means Edera does not auto-register the workload. Since the workload manages its own identity, it (or an operator) has to create its own SPIRE registration entry, using ordinary spire-server entry create, against the zone agent as parent.
Workload selectors
SPIRE grants an identity only when a workload matches every selector on its registration entry. Edera’s attestation plugins expose these:
| Selector | Applies to | Rough Kubernetes equivalent |
|---|---|---|
edera:zone-id:<uuid> | Every caller in the zone | none |
edera:zone-name:<name> | Every caller in the zone | k8s:pod-name |
edera:zone-image:<digest> | Every caller, once per running workload image | k8s:pod-image |
edera:zone-image-count:<n> | Every caller in the zone | k8s:pod-image-count |
edera:workload-id:<uuid> | A single workload in the zone | none |
edera:workload-name:<name> | A single workload in the zone | k8s:container-name |
edera:workload-image:<digest> | A single workload in the zone | k8s:container-image |
edera:principal:zone-agent | The zone’s own agent process | none |
An entry that only names zone-level selectors is matched by every workload in that zone. This is a deliberate choice to give a whole zone one shared identity. Add a workload-id (or workload-name) selector to narrow the same entry to a single workload instead. Selector matching is by subset, so image selectors alone can’t express “these images and no others.” You need to combine them with zone-image-count to pin the exact set of running images.
Bringing your own SPIRE
Edera currently launches and owns a single SPIRE server per deployment; there’s no support yet for pointing Edera at a SPIRE server you already run. You can, however, chain the Edera-launched server to your existing infrastructure: configure an UpstreamAuthority plugin in the server’s config so it becomes subordinate to a root you already trust. Identities issued inside Edera zones then verify against the same trust anchor as the rest of your deployment.
Full SPIRE nesting and federation topologies, and integrating minted identities into service mesh mTLS (Istio, Linkerd, Cilium) without Edera taking over mesh policy enforcement, are on the roadmap but not yet implemented.
Enabling SPIRE
Workload identity depends on two alpha feature flags in daemon.toml, both disabled by default:
[features]
spire-v0 = "enabled"
object-capabilities-v0 = "enabled"object-capabilities-v0 has to be enabled alongside spire-v0. Attestation reaches the daemon as an object capability, so SPIRE doesn’t work without it. Restart the daemon after changing either flag.
See also
daemon.tomlreference:[spire]and feature flags: image references, ports, trust domain, and every[spire]default.- CLI reference: full flags for
host spire-start,zone launch --with-spire, andworkload launch --enable-identity/--enable-spire-access. - Edera zones: what a zone is and how it differs from a container.
- Zone security model: how zone isolation and capability grants fit together.