diff --git a/infra/setup.ts b/infra/setup.ts index 801a299..4e3062e 100644 --- a/infra/setup.ts +++ b/infra/setup.ts @@ -145,10 +145,149 @@ export function generateSpireDockerCompose(): string { return `version: "3.8" services: + spire-init: + image: \${REG}/library/alpine:3.20 + restart: "no" + volumes: + - spire-server-conf:/opt/spire/server/conf + - spire-server-data:/opt/spire/server/data + - spire-agent-conf:/opt/spire/agent/conf + - spire-agent-data:/opt/spire/agent/data + entrypoint: + - /bin/sh + - -c + - | + mkdir -p /opt/spire/server/conf /opt/spire/server/data /opt/spire/agent/conf /opt/spire/agent/data + if [ ! -f /opt/spire/server/conf/server.conf ]; then + echo "Writing default SPIRE server.conf..." + cat << 'EOF' > /opt/spire/server/conf/server.conf + # ============================================================================== + # SPIRE Server Configuration + # Auth-Yes Identity & Access Management Fabric + # ============================================================================== + # This configuration defines the root SPIFFE trust authority for your cluster. + # You can customize trust domains, certificate TTLs, and datastore plugins below. + # ============================================================================== + + server { + # Network binding: 0.0.0.0 listens on all internal mesh interfaces. + bind_address = "0.0.0.0" + bind_port = "8081" + + # Trust Domain: Identifies the root cryptographic security domain. + # SPIFFE IDs will be generated in the format: spiffe:/// + trust_domain = "system.local" + + # Directory where SPIRE server persists runtime data, datastore, and keys. + data_dir = "/opt/spire/data" + + # Logging verbosity: DEBUG, INFO, WARN, ERROR + log_level = "INFO" + + # Certificate Authority (CA) Time-to-Live (default: 30 days) + ca_ttl = "720h" + + # Default Workload SVID Time-to-Live (default: 1 hour for high-security rotation) + default_x509_svid_ttl = "1h" + } + + plugins { + # ---------------------------------------------------------------------------- + # DataStore Plugin: Persists SPIFFE registrations, entries, and nodes. + # Default: Embedded SQLite3 datastore inside /opt/spire/data. + # ---------------------------------------------------------------------------- + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/opt/spire/data/datastore.sqlite3" + } + } + + # ---------------------------------------------------------------------------- + # NodeAttestor Plugin: Verifies identity of SPIRE agents joining the cluster. + # 'join_token' allows dynamic 1-time token enrollment for agents. + # ---------------------------------------------------------------------------- + NodeAttestor "join_token" { + plugin_data {} + } + + # ---------------------------------------------------------------------------- + # KeyManager Plugin: Securely stores the server CA private keys on disk. + # ---------------------------------------------------------------------------- + KeyManager "disk" { + plugin_data { + keys_path = "/opt/spire/data/keys.json" + } + } + } + EOF + fi + + if [ ! -f /opt/spire/agent/conf/agent.conf ]; then + echo "Writing default SPIRE agent.conf..." + cat << 'EOF' > /opt/spire/agent/conf/agent.conf + # ============================================================================== + # SPIRE Agent Configuration + # Auth-Yes Identity & Access Management Fabric + # ============================================================================== + # The SPIRE Agent runs as a local node daemon, attesting workloads (e.g. Docker + # containers) and serving the Workload API UNIX domain socket. + # ============================================================================== + + agent { + # Directory where the SPIRE agent caches SVIDs, bundles, and keys. + data_dir = "/opt/spire/data" + + # Logging verbosity: DEBUG, INFO, WARN, ERROR + log_level = "INFO" + + # Address and port of the SPIRE Server container within the internal network. + server_address = "spire-server" + server_port = "8081" + + # UNIX Domain Socket Path exposed to workloads for zero-trust identity fetching. + socket_path = "/var/run/spire/agent.sock" + + # Must match the SPIRE Server's trust_domain. + trust_domain = "system.local" + } + + plugins { + # ---------------------------------------------------------------------------- + # NodeAttestor Plugin: Authenticates this agent with the SPIRE Server. + # ---------------------------------------------------------------------------- + NodeAttestor "join_token" { + plugin_data {} + } + + # ---------------------------------------------------------------------------- + # KeyManager Plugin: Stores node-level private keys on disk. + # ---------------------------------------------------------------------------- + KeyManager "disk" { + plugin_data { + directory = "/opt/spire/data" + } + } + + # ---------------------------------------------------------------------------- + # WorkloadAttestor Plugin: Inspects running containers on Docker / Podman + # to grant SPIFFE SVIDs based on container image, labels, or names. + # ---------------------------------------------------------------------------- + WorkloadAttestor "docker" { + plugin_data {} + } + } + EOF + fi + echo "SPIRE bootstrap configuration initialized successfully." + spire-server: image: \${GHCR_REG}/spiffe/spire-server:1.9.3 container_name: spire-server hostname: spire-server + depends_on: + spire-init: + condition: service_completed_successfully networks: - auth-internal-net volumes: @@ -161,6 +300,11 @@ services: container_name: spire-agent hostname: spire-agent pid: host + depends_on: + spire-server: + condition: service_started + spire-init: + condition: service_completed_successfully networks: - auth-internal-net volumes: @@ -169,8 +313,6 @@ services: - spire-agent-conf:/opt/spire/conf:ro - /var/run/docker.sock:/var/run/docker.sock:ro command: ["-config", "/opt/spire/conf/agent.conf"] - depends_on: - - spire-server volumes: spire-server-data: