auth-yes/tasks/new/2026-0823.01.gem.feat.spire.smart-image-packaging-and-single-volume-bootstrap-0941.md

6.7 KiB

TASK METADATA

  • Target Files:
    • spire/Dockerfile.server
    • spire/Dockerfile.agent
    • spire/entrypoint.server.sh
    • spire/entrypoint.agent.sh
    • spire/templates/server.conf
    • spire/templates/agent.conf
    • infra/compose.spire.yml
    • infra/setup.ts
    • infra/.env
  • Core Objective: Package standalone, generic Smart SPIRE Server and Agent container images with self-seeding configuration entrypoints, and simplify the stack to a 1-host-volume persistent layout with a dedicated named socket volume for cross-stack zero-trust IPC.
  • Dependencies:
    • Upstream SPIRE binaries (ghcr.io/spiffe/spire-server:1.9.3 and ghcr.io/spiffe/spire-agent:1.9.3)
    • Minimal Alpine base image (${REG}/library/alpine:3.20)
  • Additional Important Notes:
    • SPIRE must remain 100% decoupled and generic (named spire-server and spire-agent, not prefixed with auth-yes).
    • No inline shell scripts, heredocs, or temporary init helper containers in compose.spire.yml.
    • Storing configuration files on the persistent host volume ensures full user editability while preventing upgrades from overwriting user customizations.

Architectural Considerations & Risks

Risks

  1. Root CA Private Key Exposure: If client workloads (e.g. auth-api) mount the entire host SPIRE storage volume to reach agent.sock, they could potentially read keys.json (server CA private keys) or SQLite databases.
    • Mitigation: The Workload API UNIX domain socket is written to and shared via a dedicated named volume (spire-socket), which only exposes agent.sock to client containers.
  2. Stale UNIX Socket on Unclean Shutdown: An abrupt host crash or power loss may leave a dead agent.sock file on disk.
    • Mitigation: entrypoint.agent.sh unconditionally runs rm -f /var/run/spire/agent.sock before launching spire-agent.
  3. Database File Locking over Network Mounts: SQLite datastores can suffer locking issues over NFS/CIFS.
    • Mitigation: SPIRE_DATA_PATH defaults to local filesystem /volume1/docker/spire (ext4/Btrfs).

Alternatives Considered

  • Inline Compose Scripting (spire-init helper container): Rejected. Putting multi-line heredocs and shell scripts inside compose.spire.yml is fragile across orchestrators (Portainer, Podman), pollutes compose files, and degrades developer experience.
  • Separate Conf/Data Volumes (4+ volume mounts): Rejected. Mounting individual subfolders (server/conf, server/data, agent/conf, agent/data) introduces unnecessary configuration complexity. A single host root volume (/volume1/docker/spire) containing server.conf, agent.conf, and data/ subdirectories provides the cleanest DX.

Proposed Implementation

Phase 1: Create Generic SPIRE Smart Container Module (spire/)

Create the decoupled spire/ directory with self-bootstrapping Dockerfiles, entrypoints, and master configuration templates:

spire/
├── Dockerfile.server             # Generic SPIRE Server Image
├── Dockerfile.agent              # Generic SPIRE Agent Image
├── entrypoint.server.sh          # Self-seeding bootstrap entrypoint
├── entrypoint.agent.sh           # Self-seeding bootstrap entrypoint & stale socket cleanup
└── templates/
    ├── server.conf               # Master commented configuration template
    └── agent.conf                # Master commented configuration template

1. spire/Dockerfile.server

  • Multi-stage build extracting spire-server binary from ghcr.io/spiffe/spire-server:1.9.3 into alpine:3.20.
  • Bakes master template into /etc/spire/templates/server.conf.
  • Sets ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] and CMD ["run", "-config", "/opt/spire/server.conf"].

2. spire/entrypoint.server.sh

  • Checks if /opt/spire/server.conf exists on the mounted volume.
  • If missing, copies /etc/spire/templates/server.conf to /opt/spire/server.conf with chmod 644.
  • Creates /opt/spire/data/server datastore directory.
  • exec /usr/local/bin/spire-server "$@".

3. spire/Dockerfile.agent

  • Multi-stage build extracting spire-agent binary from ghcr.io/spiffe/spire-agent:1.9.3 into alpine:3.20.
  • Bakes master template into /etc/spire/templates/agent.conf.
  • Sets ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] and CMD ["run", "-config", "/opt/spire/agent.conf"].

4. spire/entrypoint.agent.sh

  • Removes any stale /var/run/spire/agent.sock file.
  • Checks if /opt/spire/agent.conf exists on the mounted volume.
  • If missing, copies /etc/spire/templates/agent.conf to /opt/spire/agent.conf with chmod 644.
  • Creates /opt/spire/data/agent cache directory and /var/run/spire.
  • exec /usr/local/bin/spire-agent "$@".

5. spire/templates/server.conf & spire/templates/agent.conf

  • Heavily commented HCL templates configuring trust domain (system.local), SQLite datastore (/opt/spire/data/server/datastore.sqlite3), key storage, and Docker workload attestor.

Phase 2: Ultra-Clean Compose Configuration (infra/compose.spire.yml)

Update infra/compose.spire.yml to use the 1-volume host layout and named socket volume:

version: "3.8"

services:
  spire-server:
    image: ${REG}/library/spire-server:latest
    container_name: spire-server
    hostname: spire-server
    networks:
      - auth-internal-net
    volumes:
      - spire-data:/opt/spire

  spire-agent:
    image: ${REG}/library/spire-agent:latest
    container_name: spire-agent
    hostname: spire-agent
    pid: host
    depends_on:
      - spire-server
    networks:
      - auth-internal-net
    volumes:
      - spire-data:/opt/spire
      - spire-socket:/var/run/spire
      - /var/run/docker.sock:/var/run/docker.sock:ro

volumes:
  spire-data:
    driver: local
    driver_opts:
      type: none
      device: ${SPIRE_DATA_PATH}
      o: bind
  spire-socket:
    name: spire-socket

networks:
  auth-internal-net:
    external: true

Phase 3: Setup CLI & Build Pipeline Integration (infra/setup.ts)

Update generateBuildCommands in infra/setup.ts to build all stack images:

  1. auth-yes-api:latest (Dockerfile)
  2. spire-server:latest (spire/Dockerfile.server)
  3. spire-agent:latest (spire/Dockerfile.agent)

Update DEFAULT_AUTH_CONFIG:

  • dbDataPath: "/volume1/docker/auth-yes/data"
  • spireDataPath: "/volume1/docker/spire"

Phase 4: Quality Gates & Verification

  1. Run deno fmt and deno task lint.
  2. Run deno task check across all modules.
  3. Run deno test -A to verify unit and integration tests.
  4. Verify image build commands via podman build test.