← Week 2: SPIRE Internals and Attestation

Day 10: Workload Attestation — Unix, Docker, Kubernetes

Phase 4 · August 14, 2026

← Week 2: SPIRE Internals and Attestation

Agenda (2–3 hours)

  • Read (45 min): SPIRE workload attestor docs (unix, docker, k8s)
  • Study (45 min): Understand selector syntax and registration entry matching
  • Challenge (60 min): Design registration entries for your provisioning service
← Week 2: SPIRE Internals and Attestation

What Workload Attestation Solves

Node attestation tells SPIRE: "this agent is on a legitimate node."
Workload attestation tells the agent: "this specific process should get this SVID."

Without workload attestation, all processes on a node would get the same SVID.
That's not workload identity — that's node identity with extra steps.

The question workload attestors answer:
"Which registration entry's selectors match the process connecting to this socket?"

← Week 2: SPIRE Internals and Attestation

Unix Workload Attestor

The simplest attestor: uses kernel-provided process metadata.

Available selectors:

unix:uid:<uid>           # effective user ID
unix:gid:<gid>           # effective group ID
unix:pid:<pid>           # process ID (not stable — use for debugging only)
unix:path:<path>         # /proc/<pid>/exe (the binary path, resolved)
unix:sha256:<hash>       # SHA-256 of the binary (prevents replacement attacks)

Registration entry example:

Parent: spiffe://leo.amazon.com/spire/agent/aws_iid/us-east-1/i-0abc123
SPIFFE ID: spiffe://leo.amazon.com/ns/prod/svc/provisioning
Selectors:
  unix:uid:1001
  unix:path:/opt/leo/provisioning-service/bin/server

The selector combination means: only a process with UID 1001 running that exact binary
gets this SVID.

← Week 2: SPIRE Internals and Attestation

Docker Workload Attestor

For containerized workloads — uses Docker API to inspect the container:

Available selectors:

docker:label:<key>:<value>   # container label
docker:image_id:<id>         # Docker image SHA
docker:env:<key>:<value>     # environment variable
docker:container_name:<name> # container name

Registration entry:

SPIFFE ID: spiffe://leo.amazon.com/ns/prod/svc/provisioning
Selectors:
  docker:label:team:securecomms
  docker:label:env:prod
  docker:label:service:provisioning

Note: labels are soft — anyone with Docker access can set them.
Combine with docker:image_id for stronger binding.

← Week 2: SPIRE Internals and Attestation

Kubernetes Workload Attestor

Most expressive for k8s deployments — uses the k8s API:

Available selectors:

k8s:ns:<namespace>
k8s:sa:<service-account>
k8s:pod-label:<key>:<value>
k8s:pod-name:<name>
k8s:container-name:<name>
k8s:node-name:<node>

Registration entry:

SPIFFE ID: spiffe://leo.amazon.com/ns/prod/svc/provisioning
Selectors:
  k8s:ns:prod
  k8s:sa:provisioning-service
  k8s:pod-label:app:provisioning

This binds the SVID to a specific k8s service account in a specific namespace —
a strong identity rooted in k8s RBAC.

← Week 2: SPIRE Internals and Attestation

Selector Matching Semantics

Selectors within a registration entry are AND-combined:

unix:uid:1001 AND unix:path:/opt/svc/server
→ both must match

Multiple registration entries are OR-combined:

Entry 1: unix:uid:1001 → spiffe://leo.amazon.com/svc/provisioning
Entry 2: unix:uid:1002 → spiffe://leo.amazon.com/svc/audit
→ either can match (different SVIDs issued)

One process can match multiple entries → receives multiple SVIDs.
This is useful when a service acts as both a server and a client
with different peer relationships.

← Week 2: SPIRE Internals and Attestation

Designing Registration Entries

Good entries are:

  • Specific: enough selectors that only the intended process matches
  • Stable: selectors that don't change on every deploy (avoid PID, avoid image hash in fast-deploy envs)
  • Auditable: comments explaining why this entry exists

Too permissive:

unix:uid:0   ← root gets any SVID? Never do this.

Too brittle:

docker:image_id:sha256:abc123...   ← breaks on every image rebuild

Just right:

unix:uid:1001
unix:path:/opt/leo/provisioning-service/bin/server
unix:sha256:<hash>   ← add this for high-assurance envs
← Week 2: SPIRE Internals and Attestation

Challenge Assignment

Design registration entries for a 3-service scenario:

Services:

  1. provisioning-service — the main Lambda/long-running service
  2. cert-validator — a sidecar that validates certs before they're issued
  3. audit-logger — writes to DynamoDB audit trail

For each service, write a registration entry block:

SPIFFE ID: spiffe://leo.amazon.com/ns/prod/svc/<name>
Parent: spiffe://leo.amazon.com/spire/agent/aws_iid/us-east-1/<instance-id>
Selectors:
  <list your selectors>
Rationale: <why these selectors>

Then answer: which selector type (unix / docker / k8s) makes the most sense
for a Lambda-based service, and what's the gap?

Save in spiffe-analysis.md under "Registration Entry Design."

← Week 2: SPIRE Internals and Attestation

Resources

  • Unix workload attestor: github.com/spiffe/spire/blob/main/doc/plugin_agent_workloadattestor_unix.md
  • Docker workload attestor: github.com/spiffe/spire/blob/main/doc/plugin_agent_workloadattestor_docker.md
  • k8s workload attestor: github.com/spiffe/spire/blob/main/doc/plugin_agent_workloadattestor_k8s.md
  • SPIRE registration entry API: spiffe.io/docs/latest/deploying/registering