# 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: ```text 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`](file:///home/tylerg/p/data/auth-yes/infra/compose.spire.yml) to use the 1-volume host layout and named socket volume: ```yaml 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`](file:///home/tylerg/p/data/auth-yes/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.