Skip to main content

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

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:

Security Best Practices →

Or explore the SDK for easier integration:

AuthSec SDK Documentation →