Integrate SPIRE
Learn how to integrate SPIRE (SPIFFE Runtime Environment) with AuthSec for automatic workload identity management and certificate rotation.
What is SPIRE?
SPIRE is the production-ready implementation of SPIFFE (Secure Production Identity Framework For Everyone).
Key Features
Automatic Identity Issuance
Workloads receive cryptographic identities on startup
Zero-Trust Attestation
Verifies workload authenticity before issuing credentials
Continuous Rotation
Certificates automatically renew before expiration
Platform Agnostic
Works across Kubernetes, VMs, containers, and cloud platforms
Architecture Overview
┌─────────────────┐
│ SPIRE Server │ ← Central identity authority
└────────┬────────┘
│
│ Issues SVIDs (certificates)
│
┌────┴────┐
│ │
┌───▼───┐ ┌──▼────┐
│ Agent │ │ Agent │ ← Runs on each node
└───┬───┘ └──┬────┘
│ │
│ │ Distributes identities
│ │
┌───▼───┐ ┌──▼────┐
│Worker │ │Worker │ ← Your workloads
│load 1 │ │load 2 │
└───────┘ └───────┘
SPIRE Server: Central authority that issues identities
SPIRE Agent: Runs on each node, attests and delivers credentials
Workloads: Your services/agents receive automatic identities
Prerequisites
Before integrating SPIRE:
- Kubernetes cluster (v1.19+) or VM infrastructure
- kubectl access with cluster-admin permissions
- AuthSec workspace created
- Admin access to AuthSec dashboard
Installation
Option 1: Kubernetes (Recommended)
Step 1: Install SPIRE Server
Create namespace:
kubectl create namespace spire
Deploy SPIRE server:
kubectl apply -f https://raw.githubusercontent.com/spiffe/spire/main/support/k8s/server/spire-server.yaml
Verify installation:
kubectl get pods -n spire
Expected output:
NAME READY STATUS RESTARTS AGE
spire-server-0 1/1 Running 0 1m
Step 2: Install SPIRE Agent
Deploy agent as DaemonSet:
kubectl apply -f https://raw.githubusercontent.com/spiffe/spire/main/support/k8s/agent/spire-agent.yaml
Verify agents are running:
kubectl get daemonset spire-agent -n spire
Expected output:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE
spire-agent 3 3 3 3 3
Option 2: Docker Compose
docker-compose.yml:
version: "3.8"
services:
spire-server:
image: ghcr.io/spiffe/spire-server:latest
hostname: spire-server
volumes:
- ./server:/opt/spire/conf/server
- spire-server-data:/opt/spire/data/server
command: ["-config", "/opt/spire/conf/server/server.conf"]
ports:
- "8081:8081"
networks:
- spire
spire-agent:
image: ghcr.io/spiffe/spire-agent:latest
depends_on:
- spire-server
hostname: spire-agent
volumes:
- ./agent:/opt/spire/conf/agent
- /var/run/docker.sock:/var/run/docker.sock
command: ["-config", "/opt/spire/conf/agent/agent.conf"]
networks:
- spire
volumes:
spire-server-data:
networks:
spire:
Start SPIRE:
docker-compose up -d
Configuration
Step 1: Configure Trust Domain
The trust domain defines your identity namespace.
Example: authsec.example.com
All SPIFFE IDs will follow this pattern:
spiffe://authsec.example.com/production/api-gateway
spiffe://authsec.example.com/production/ml-agent
SPIRE Server Config (server.conf):
server {
bind_address = "0.0.0.0"
bind_port = "8081"
trust_domain = "authsec.example.com"
data_dir = "/opt/spire/data/server"
}
plugins {
DataStore "sql" {
plugin_data {
database_type = "sqlite3"
connection_string = "/opt/spire/data/server/datastore.sqlite3"
}
}
KeyManager "disk" {
plugin_data {
keys_path = "/opt/spire/data/server/keys.json"
}
}
NodeAttestor "k8s_psat" {
plugin_data {
clusters = {
"production" = {
service_account_allow_list = ["spire:spire-agent"]
}
}
}
}
}
Step 2: Register Workloads
Define which workloads can receive identities.
Register a workload:
kubectl exec -n spire spire-server-0 -- \
/opt/spire/bin/spire-server entry create \
-spiffeID spiffe://authsec.example.com/production/ml-agent \
-parentID spiffe://authsec.example.com/spire/agent/k8s_psat/production/default \
-selector k8s:ns:default \
-selector k8s:sa:ml-agent-service-account \
-selector k8s:pod-label:app:ml-agent
Parameters explained:
- spiffeID: Identity assigned to this workload
- parentID: SPIRE agent identity (auto-generated)
- selector: Criteria to identify the workload
- Kubernetes namespace
- Service account
- Pod labels
Step 3: Connect to AuthSec
Configure SPIRE to work with AuthSec for authorization.
Add OIDC Discovery (optional):
oidc_discovery {
domain = "auth.authsec.ai"
}
This allows AuthSec to verify SPIRE-issued JWTs.
Using SPIRE in Your Application
Step 1: Obtain SVID
Your workload requests its identity from the local SPIRE agent:
Python Example:
import grpc
from spiffe import WorkloadApiClient
# Connect to local SPIRE agent
client = WorkloadApiClient()
# Fetch X.509 SVID (certificate)
svid = client.fetch_x509_svid()
print(f"My SPIFFE ID: {svid.spiffe_id}")
print(f"Certificate: {svid.cert}")
print(f"Private Key: {svid.private_key}")
Go Example:
package main
import (
"context"
"fmt"
"github.com/spiffe/go-spiffe/v2/workloadapi"
)
func main() {
ctx := context.Background()
// Connect to SPIRE agent
source, err := workloadapi.NewX509Source(ctx)
if err != nil {
panic(err)
}
defer source.Close()
// Get SVID
svid, err := source.GetX509SVID()
if err != nil {
panic(err)
}
fmt.Printf("My SPIFFE ID: %s\n", svid.ID)
}
Step 2: Mutual TLS Communication
Use SPIRE-issued certificates for mTLS between services:
Go Server Example:
package main
import (
"context"
"log"
"net/http"
"github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
"github.com/spiffe/go-spiffe/v2/workloadapi"
)
func main() {
ctx := context.Background()
// Get X.509 source from SPIRE
source, err := workloadapi.NewX509Source(ctx)
if err != nil {
log.Fatal(err)
}
defer source.Close()
// Configure TLS with SPIRE certificates
tlsConfig := tlsconfig.MTLSServerConfig(source, source, tlsconfig.AuthorizeAny())
server := &http.Server{
Addr: ":8443",
TLSConfig: tlsConfig,
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Authenticated via mTLS!"))
})
log.Println("Server listening on :8443")
log.Fatal(server.ListenAndServeTLS("", ""))
}
Go Client Example:
package main
import (
"context"
"fmt"
"io"
"net/http"
"github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
"github.com/spiffe/go-spiffe/v2/workloadapi"
)
func main() {
ctx := context.Background()
source, err := workloadapi.NewX509Source(ctx)
if err != nil {
panic(err)
}
defer source.Close()
// Create HTTP client with mTLS
tlsConfig := tlsconfig.MTLSClientConfig(source, source, tlsconfig.AuthorizeAny())
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
}
resp, err := client.Get("https://api-service:8443/")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Verification
Check SPIRE is Running
View registered entries:
kubectl exec -n spire spire-server-0 -- \
/opt/spire/bin/spire-server entry show
Verify agent health:
kubectl exec -n spire spire-agent-XXXXX -- \
/opt/spire/bin/spire-agent healthcheck
Test SVID fetch:
kubectl exec -n spire spire-agent-XXXXX -- \
/opt/spire/bin/spire-agent api fetch x509
Production Best Practices
Use Hardware Security Modules (HSM)
Store SPIRE server keys in HSM for maximum security
Enable High Availability
Run multiple SPIRE servers with shared database
Monitor Certificate Rotation
Alert if SVIDs fail to rotate
Restrict Agent Access
Use network policies to limit agent communication
Audit Registration Entries
Regularly review which workloads have identities
Troubleshooting
Workload can't fetch SVID
Check agent is running:
kubectl get pods -n spire -l app=spire-agent
Verify workload registration:
kubectl exec -n spire spire-server-0 -- \
/opt/spire/bin/spire-server entry show
Check selectors match:
kubectl get pod YOUR_POD -o yaml | grep labels -A 5
Certificate expired
SPIRE should auto-rotate. Check agent logs:
kubectl logs -n spire spire-agent-XXXXX
mTLS connection fails
Verify both services have valid SVIDs:
kubectl exec YOUR_POD -- curl -v https://api-service:8443/
Next Steps
SPIRE is now integrated! Learn advanced security patterns:
Or explore the SDK for easier integration: