From 4360d67064873226e3fe7f1b510a65170d4900e1 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 23 Aug 2026 17:20:11 +0000 Subject: [PATCH] feat: Package generic SPIRE images and simplify compose volume This implements custom Alpine-based Smart SPIRE Server and Agent Docker images with self-seeding configuration entrypoints. It also updates the docker-compose configuration to utilize a single host storage volume and a dedicated named socket volume. Setup build pipelines are expanded to compile and push these custom SPIRE images. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com> --- infra/setup.ts | 190 +----------------- spire/Dockerfile.agent | 13 ++ spire/Dockerfile.server | 13 ++ spire/entrypoint.agent.sh | 17 ++ spire/entrypoint.server.sh | 13 ++ spire/templates/agent.conf | 51 +++++ spire/templates/server.conf | 59 ++++++ ...kaging-and-single-volume-bootstrap-0941.md | 0 8 files changed, 177 insertions(+), 179 deletions(-) create mode 100644 spire/Dockerfile.agent create mode 100644 spire/Dockerfile.server create mode 100755 spire/entrypoint.agent.sh create mode 100755 spire/entrypoint.server.sh create mode 100644 spire/templates/agent.conf create mode 100644 spire/templates/server.conf rename tasks/{new => complete}/2026-0823.01.gem.feat.spire.smart-image-packaging-and-single-volume-bootstrap-0941.md (100%) diff --git a/infra/setup.ts b/infra/setup.ts index 4e3062e..ea02b90 100644 --- a/infra/setup.ts +++ b/infra/setup.ts @@ -145,199 +145,35 @@ 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 + image: \${REG}/library/spire-server:latest container_name: spire-server hostname: spire-server - depends_on: - spire-init: - condition: service_completed_successfully networks: - auth-internal-net volumes: - - spire-server-data:/opt/spire/data - - spire-server-conf:/opt/spire/conf:ro - command: ["-config", "/opt/spire/conf/server.conf"] + - spire-data:/opt/spire spire-agent: - image: \${GHCR_REG}/spiffe/spire-agent:1.9.3 + image: \${REG}/library/spire-agent:latest container_name: spire-agent hostname: spire-agent pid: host depends_on: - spire-server: - condition: service_started - spire-init: - condition: service_completed_successfully + - spire-server networks: - auth-internal-net volumes: + - spire-data:/opt/spire - spire-socket:/var/run/spire - - spire-agent-data:/opt/spire/data - - spire-agent-conf:/opt/spire/conf:ro - /var/run/docker.sock:/var/run/docker.sock:ro - command: ["-config", "/opt/spire/conf/agent.conf"] volumes: - spire-server-data: + spire-data: driver: local driver_opts: type: none - device: \${SPIRE_DATA_PATH}/server/data - o: bind - spire-server-conf: - driver: local - driver_opts: - type: none - device: \${SPIRE_DATA_PATH}/server/conf - o: bind - spire-agent-data: - driver: local - driver_opts: - type: none - device: \${SPIRE_DATA_PATH}/agent/data - o: bind - spire-agent-conf: - driver: local - driver_opts: - type: none - device: \${SPIRE_DATA_PATH}/agent/conf + device: \${SPIRE_DATA_PATH} o: bind spire-socket: name: spire-socket @@ -394,6 +230,10 @@ export function generateBuildCommands(reg: string): string[] { return [ `podman build -t ${reg}/library/auth-yes-api:latest -f Dockerfile .`, `podman push ${reg}/library/auth-yes-api:latest`, + `podman build -t ${reg}/library/spire-server:latest -f spire/Dockerfile.server spire/`, + `podman push ${reg}/library/spire-server:latest`, + `podman build -t ${reg}/library/spire-agent:latest -f spire/Dockerfile.agent spire/`, + `podman push ${reg}/library/spire-agent:latest`, ]; } @@ -428,14 +268,6 @@ export async function generateAuthSetupFiles( const spireComposeContent = generateSpireDockerCompose(); await Deno.writeTextFile(SPIRE_COMPOSE_PATH, spireComposeContent); - // Ensure default SPIRE directories exist - await Deno.mkdir(path.join("infra", "spire", "server", "conf"), { - recursive: true, - }); - await Deno.mkdir(path.join("infra", "spire", "agent", "conf"), { - recursive: true, - }); - console.log( colors.green( `\n✓ Successfully generated ${ENV_PATH}, ${COMPOSE_PATH}, and ${SPIRE_COMPOSE_PATH}!`, diff --git a/spire/Dockerfile.agent b/spire/Dockerfile.agent new file mode 100644 index 0000000..23abe07 --- /dev/null +++ b/spire/Dockerfile.agent @@ -0,0 +1,13 @@ +ARG SPIRE_VERSION=1.9.3 +FROM ghcr.io/spiffe/spire-agent:${SPIRE_VERSION} AS upstream +FROM alpine:3.20 + +RUN apk add --no-cache ca-certificates tzdata + +COPY --from=upstream /opt/spire/bin/spire-agent /usr/local/bin/spire-agent +COPY templates/agent.conf /etc/spire/templates/agent.conf +COPY entrypoint.agent.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] +CMD ["run", "-config", "/opt/spire/agent.conf"] diff --git a/spire/Dockerfile.server b/spire/Dockerfile.server new file mode 100644 index 0000000..2239951 --- /dev/null +++ b/spire/Dockerfile.server @@ -0,0 +1,13 @@ +ARG SPIRE_VERSION=1.9.3 +FROM ghcr.io/spiffe/spire-server:${SPIRE_VERSION} AS upstream +FROM alpine:3.20 + +RUN apk add --no-cache ca-certificates tzdata + +COPY --from=upstream /opt/spire/bin/spire-server /usr/local/bin/spire-server +COPY templates/server.conf /etc/spire/templates/server.conf +COPY entrypoint.server.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] +CMD ["run", "-config", "/opt/spire/server.conf"] diff --git a/spire/entrypoint.agent.sh b/spire/entrypoint.agent.sh new file mode 100755 index 0000000..c37a885 --- /dev/null +++ b/spire/entrypoint.agent.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +# Mitigation for Risk 2: Stale UNIX Socket on Unclean Shutdown +rm -f /var/run/spire/agent.sock + +mkdir -p /opt/spire/data/agent +mkdir -p /var/run/spire + +if [ ! -f /opt/spire/agent.conf ]; then + echo "Writing default SPIRE agent.conf..." + cp /etc/spire/templates/agent.conf /opt/spire/agent.conf + chmod 644 /opt/spire/agent.conf +fi + +exec /usr/local/bin/spire-agent "$@" diff --git a/spire/entrypoint.server.sh b/spire/entrypoint.server.sh new file mode 100755 index 0000000..865fd58 --- /dev/null +++ b/spire/entrypoint.server.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +mkdir -p /opt/spire/data/server + +if [ ! -f /opt/spire/server.conf ]; then + echo "Writing default SPIRE server.conf..." + cp /etc/spire/templates/server.conf /opt/spire/server.conf + chmod 644 /opt/spire/server.conf +fi + +exec /usr/local/bin/spire-server "$@" diff --git a/spire/templates/agent.conf b/spire/templates/agent.conf new file mode 100644 index 0000000..1f802c3 --- /dev/null +++ b/spire/templates/agent.conf @@ -0,0 +1,51 @@ +# ============================================================================== +# 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/agent" + + # 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/agent" + } + } + + # ---------------------------------------------------------------------------- + # WorkloadAttestor Plugin: Inspects running containers on Docker / Podman + # to grant SPIFFE SVIDs based on container image, labels, or names. + # ---------------------------------------------------------------------------- + WorkloadAttestor "docker" { + plugin_data {} + } +} diff --git a/spire/templates/server.conf b/spire/templates/server.conf new file mode 100644 index 0000000..1144d76 --- /dev/null +++ b/spire/templates/server.conf @@ -0,0 +1,59 @@ +# ============================================================================== +# 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/server" + + # 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/server. + # ---------------------------------------------------------------------------- + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/opt/spire/data/server/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/server/keys.json" + } + } +} diff --git a/tasks/new/2026-0823.01.gem.feat.spire.smart-image-packaging-and-single-volume-bootstrap-0941.md b/tasks/complete/2026-0823.01.gem.feat.spire.smart-image-packaging-and-single-volume-bootstrap-0941.md similarity index 100% rename from tasks/new/2026-0823.01.gem.feat.spire.smart-image-packaging-and-single-volume-bootstrap-0941.md rename to tasks/complete/2026-0823.01.gem.feat.spire.smart-image-packaging-and-single-volume-bootstrap-0941.md