SPIFFE and SPIRE in Kubernetes
2024-05-08
TL;DR
We’ll deploy SPIRE on a local kind cluster, generate SPIFFE IDs for workloads, and use mutual TLS between two pods. This is how to go from zero to zero trust in Kubernetes.
What is SPIFFE/SPIRE?
- SPIFFE (Secure Production Identity Framework For Everyone): defines a framework for workload identity.
- SPIRE (SPIFFE Runtime Environment): the production-ready implementation of SPIFFE.
Why You Should Care (Real World)
- Legacy apps don’t rotate secrets.
- TLS certs are static or manually managed.
- You can’t verify “who” a service is at runtime.
- SPIFFE solves this by issuing short-lived X.509 certificates tied to workload identity.
+---------------------+
| SPIRE Server (K8s) |
+---------------------+
|
| gRPC (registration, trust bundles)
v
+---------------------+ +----------------------+
| SPIRE Agent (DaemonSet) |<----->| Workload A (sidecarless) |
+---------------------+ +----------------------+
| |
| |
v v
/spire-agent.sock /spire-agent.sock
(Unix socket) (shared via volumeMount)
- SPIRE Server runs as a StatefulSet
- SPIRE Agents run as DaemonSet, connect securely to server
- Workloads use a Unix socket to get certs
What We’ll Build
- Setup kind cluster
- Install SPIRE Server and Agent
- Deploy two workloads: app-a and app-b
- Secure their communication using mTLS via SPIFFE
Pre-reqs:
brew install kind kubectl helm
Setup Kind:
cat <<EOF | kind create cluster --name spire --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: spire
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30443
hostPort: 443
EOF
Get the Spire repo
git clone https://github.com/spiffe/spire-examples.git
cd spire-examples/k8s/simple_psat
Deploy SPIRE Server and Agent
kubectl apply -k .
This applies:
- spire-server.yaml
- spire-agent.yaml
- RBAC and namespace (via kustomize)
Register workloads
Use spire-server running inside the cluster:
kubectl exec -n spire deploy/spire-server -- \
/opt/spire/bin/spire-server entry create \
-spiffeID spiffe://example.org/ns/default/sa/default \
-parentID spiffe://example.org/spire/agent/k8s_psat/my-cluster/node \
-selector k8s:ns:default \
-selector k8s:sa:default \
-selector k8s:pod-label:app:app-a \
-ttl 60
Repeat for app-b.
You’ll find more registration examples in:
examples/k8s/advanced/register-example.sh
Verify Secure Communication
You’ll see app-a sending requests with a SPIFFE cert, app-b validating it.
kubectl logs -l app=app-b
Output should show:
Verified SPIFFE ID: spiffe://example.org/ns/default/sa/default
Diagram – Simplified
+---------+ mTLS +---------+
| app-a |----------------->| app-b |
| | SPIFFE ID | |
| spiffe://.../app-a | spiffe://.../app-b
+---------+ +---------+
Real-World Use Cases
- Zero-trust networking with Linkerd/Istio (replace cert-manager)
- Secretless app deployments (SPIFFE cert as identity token)
- Automatic rotation of certs every few minutes
Bonus: Integrate with Istio or Linkerd
You can configure your mesh to trust SPIFFE identities instead of using static certs. Example (Istio):
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
Then use the SPIFFE trust domain in your AuthorizationPolicies.
Conclusion
- SPIRE gives you automated workload identity via X.509 or JWT-SVID
- SPIFFE ID is portable across clusters, clouds, workloads
- You no longer rely on long-lived secrets or static TLS certs