콘텐츠로 이동

SPIFFE/SPIRE Cheat Sheet

Overview

SPIFFE (Secure Production Identity Framework for Everyone) is a set of open standards for securely identifying and authenticating software services (workloads) in dynamic, heterogeneous environments. SPIRE (the SPIFFE Runtime Environment) is the production-ready reference implementation that manages and issues SPIFFE identities in the form of X.509 certificates (SVIDs - SPIFFE Verifiable Identity Documents) and JWT tokens. Together, SPIFFE/SPIRE enable zero-trust networking by providing strong, cryptographic workload identity without relying on network-level controls like IP addresses or firewalls.

SPIRE operates through a server-agent architecture. The SPIRE Server acts as a certificate authority and registration API, maintaining a registry of workload identities and the attestation policies that map infrastructure properties to SPIFFE IDs. SPIRE Agents run on each node, attest the identity of the node to the SPIRE Server, and provide the Workload API through which workloads obtain their SVIDs. Workloads authenticate to the agent through kernel-level attestation (PID, UID, Docker labels, Kubernetes pod identity). SPIFFE/SPIRE is used by major platforms including Istio, Consul Connect, and NGINX Service Mesh for service-to-service authentication and is a CNCF graduated project.

Installation

SPIRE Server

# Download SPIRE release
wget https://github.com/spiffe/spire/releases/latest/download/spire-1.10.0-linux-amd64-musl.tar.gz
tar xzf spire-1.10.0-linux-amd64-musl.tar.gz
cd spire-1.10.0

# Install binaries
sudo cp bin/spire-server /usr/local/bin/
sudo cp bin/spire-agent /usr/local/bin/

# Verify
spire-server --version
spire-agent --version

Kubernetes (Helm)

# Add SPIRE Helm repository
helm repo add spire https://spiffe.github.io/helm-charts-hardened/
helm repo update

# Install SPIRE
helm install spire spire/spire \
  --namespace spire-system \
  --create-namespace \
  --set global.spire.clusterName=my-cluster \
  --set global.spire.trustDomain=example.org

# Verify installation
kubectl get pods -n spire-system

Docker

# Run SPIRE Server
docker run -d --name spire-server \
  -p 8081:8081 \
  -v /opt/spire/server:/opt/spire/conf \
  ghcr.io/spiffe/spire-server:latest

# Run SPIRE Agent
docker run -d --name spire-agent \
  -v /opt/spire/agent:/opt/spire/conf \
  -v /run/spire/sockets:/run/spire/sockets \
  --pid host \
  ghcr.io/spiffe/spire-agent:latest

Configuration

SPIRE Server Configuration

# /etc/spire/server/server.conf
server {
    bind_address = "0.0.0.0"
    bind_port = "8081"
    trust_domain = "example.org"
    data_dir = "/opt/spire/data/server"
    log_level = "INFO"
    log_file = "/var/log/spire/server.log"

    ca_ttl = "24h"
    default_x509_svid_ttl = "1h"
    default_jwt_svid_ttl = "5m"

    ca_subject {
        country = ["US"]
        organization = ["Example Corp"]
        common_name = "SPIRE CA"
    }
}

plugins {
    DataStore "sql" {
        plugin_data {
            database_type = "sqlite3"
            connection_string = "/opt/spire/data/server/datastore.sqlite3"
        }
    }

    NodeAttestor "join_token" {
        plugin_data {}
    }

    NodeAttestor "x509pop" {
        plugin_data {}
    }

    KeyManager "disk" {
        plugin_data {
            keys_path = "/opt/spire/data/server/keys.json"
        }
    }
}

SPIRE Agent Configuration

# /etc/spire/agent/agent.conf
agent {
    data_dir = "/opt/spire/data/agent"
    log_level = "INFO"
    log_file = "/var/log/spire/agent.log"
    server_address = "spire-server"
    server_port = "8081"
    trust_domain = "example.org"
    trust_bundle_path = "/opt/spire/conf/agent/bootstrap.crt"

    socket_path = "/run/spire/sockets/agent.sock"
}

plugins {
    NodeAttestor "join_token" {
        plugin_data {}
    }

    KeyManager "disk" {
        plugin_data {
            directory = "/opt/spire/data/agent"
        }
    }

    WorkloadAttestor "unix" {
        plugin_data {}
    }

    WorkloadAttestor "docker" {
        plugin_data {
            docker_socket_path = "/var/run/docker.sock"
        }
    }
}

Kubernetes Agent Configuration

# Kubernetes-specific agent configuration
plugins {
    NodeAttestor "k8s_sat" {
        plugin_data {
            cluster = "my-cluster"
        }
    }

    WorkloadAttestor "k8s" {
        plugin_data {
            skip_kubelet_verification = true
        }
    }
}

Core Commands

Server Management

CommandDescription
spire-server runStart SPIRE server
spire-server healthcheckCheck server health
spire-server entry createRegister a workload identity
spire-server entry showList registered entries
spire-server entry deleteRemove a registration entry
spire-server agent listList attested agents
spire-server token generateGenerate join token
spire-server bundle showShow trust bundle
# Start SPIRE server
spire-server run -config /etc/spire/server/server.conf &

# Check server health
spire-server healthcheck

# Generate join token for agent
spire-server token generate -spiffeID spiffe://example.org/agent/node1

# Show trust bundle
spire-server bundle show

# List all agents
spire-server agent list

# Evict an agent
spire-server agent evict -spiffeID spiffe://example.org/agent/node1

Agent Management

# Start SPIRE agent with join token
spire-agent run -config /etc/spire/agent/agent.conf \
  -joinToken <token>

# Check agent health
spire-agent healthcheck

# API to fetch SVIDs (used by workloads)
spire-agent api fetch x509 -write /tmp/
spire-agent api fetch jwt -audience myservice

Registration Entries

# Register a workload identity (SPIFFE ID)
spire-server entry create \
  -spiffeID spiffe://example.org/myservice \
  -parentID spiffe://example.org/agent/node1 \
  -selector unix:uid:1000

# Register by Docker label
spire-server entry create \
  -spiffeID spiffe://example.org/frontend \
  -parentID spiffe://example.org/agent/node1 \
  -selector docker:label:app:frontend

# Register Kubernetes workload
spire-server entry create \
  -spiffeID spiffe://example.org/ns/default/sa/myapp \
  -parentID spiffe://example.org/k8s-node \
  -selector k8s:ns:default \
  -selector k8s:sa:myapp

# Register with DNS names (for X.509 SAN)
spire-server entry create \
  -spiffeID spiffe://example.org/api-server \
  -parentID spiffe://example.org/agent/node1 \
  -selector unix:uid:1000 \
  -dns api.example.com \
  -dns api.internal

# Register with TTL
spire-server entry create \
  -spiffeID spiffe://example.org/myservice \
  -parentID spiffe://example.org/agent/node1 \
  -selector unix:uid:1000 \
  -x509SVIDTTL 3600 \
  -jwtSVIDTTL 300

# Show all registration entries
spire-server entry show

# Show entries for specific SPIFFE ID
spire-server entry show -spiffeID spiffe://example.org/myservice

# Delete entry
spire-server entry delete -entryID <entry-id>

Advanced Usage

Workload API Integration (Go)

package main

import (
    "context"
    "log"

    "github.com/spiffe/go-spiffe/v2/workloadapi"
)

func main() {
    ctx := context.Background()

    // Create X509Source
    source, err := workloadapi.NewX509Source(ctx,
        workloadapi.WithClientOptions(
            workloadapi.WithAddr("unix:///run/spire/sockets/agent.sock"),
        ),
    )
    if err != nil {
        log.Fatalf("Unable to create X509Source: %v", err)
    }
    defer source.Close()

    // Get SVID
    svid, err := source.GetX509SVID()
    if err != nil {
        log.Fatalf("Unable to get SVID: %v", err)
    }

    log.Printf("SPIFFE ID: %s", svid.ID)
    log.Printf("Certificate: %v", svid.Certificates[0].Subject)
}

Federation

# Configure federation between two trust domains
# On server for example.org:
spire-server bundle show -format spiffe > example-org-bundle.json

# On server for partner.com:
spire-server bundle show -format spiffe > partner-com-bundle.json

# Set federated bundle on example.org server
spire-server bundle set -format spiffe \
  -id spiffe://partner.com \
  -path partner-com-bundle.json

# Set federated bundle on partner.com server
spire-server bundle set -format spiffe \
  -id spiffe://example.org \
  -path example-org-bundle.json

# Register federated entry
spire-server entry create \
  -spiffeID spiffe://example.org/federated-service \
  -parentID spiffe://example.org/agent/node1 \
  -selector unix:uid:1000 \
  -federatesWith spiffe://partner.com

Upstream Authority

# Use external CA as upstream authority
# server.conf
plugins {
    UpstreamAuthority "disk" {
        plugin_data {
            key_file_path = "/opt/spire/conf/upstream-ca.key"
            cert_file_path = "/opt/spire/conf/upstream-ca.crt"
        }
    }

    # Or use AWS PCA
    UpstreamAuthority "aws_pca" {
        plugin_data {
            region = "us-east-1"
            certificate_authority_arn = "arn:aws:acm-pca:..."
        }
    }

    # Or use Vault
    UpstreamAuthority "vault" {
        plugin_data {
            vault_addr = "https://vault.example.com:8200"
            pki_mount_point = "pki"
            token = "s.xxxxx"
        }
    }
}

Monitoring

# Health check endpoints
curl -s http://localhost:8081/health
curl -s http://localhost:8081/ready

# Prometheus metrics
# Add to server.conf:
# telemetry {
#     Prometheus {
#         host = "0.0.0.0"
#         port = 9988
#     }
# }

# Key metrics to monitor:
# spire_server_ca_manager_x509_ca_rotate_ttl
# spire_server_datastore_bundle_count
# spire_agent_workload_api_connection_count
# spire_agent_svid_rotations

Troubleshooting

IssueSolution
Agent cannot attestVerify join token or node attestor configuration
Workload cannot get SVIDCheck selectors match workload properties: spire-server entry show
Trust bundle mismatchRe-bootstrap agent with correct server bundle
Certificate rotation failingCheck agent connectivity to server, verify SVID TTL settings
Federation not workingEnsure both servers have each other’s bundles, check entry federatesWith
High latency on SVID fetchIncrease agent cache size, check server load and database performance
Socket permission deniedVerify workload can access /run/spire/sockets/agent.sock
Server database lockedStop concurrent writes, check disk space, consider PostgreSQL for production