From 8f706f10ec279a2268a8f8231f6bf236808cf2ea Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Wed, 11 Mar 2026 14:47:07 -0700 Subject: [PATCH] =?UTF-8?q?Phase=208=20plan:=20add=20Dockerfile=20step=20(?= =?UTF-8?q?Step=208.6)=20-=20PROJECT=5FPLAN.md:=20insert=20Step=208.6=20(D?= =?UTF-8?q?ockerfile)=20before=20the=20=20=20documentation=20step=20(renum?= =?UTF-8?q?bered=20to=208.7);=20acceptance=20criteria=20cover=20=20=20mult?= =?UTF-8?q?i-stage=20build,=20non-root=20runtime=20user,=20EXPOSE=20ports,?= =?UTF-8?q?=20VOLUME=20/data,=20=20=20dist/mcias.conf.docker.example,=20Ma?= =?UTF-8?q?kefile=20docker=20target,=20and=20image=20=20=20size=20target?= =?UTF-8?q?=20(<50=20MB)=20-=20ARCHITECTURE.md=20=C2=A718:=20add=20Dockerf?= =?UTF-8?q?ile=20to=20artifact=20inventory=20table;=20=20=20add=20Dockerfi?= =?UTF-8?q?le=20Design=20section=20covering=20build=20stages,=20security?= =?UTF-8?q?=20=20=20properties=20(no=20shell,=20non-root=20uid=2010001,=20?= =?UTF-8?q?TLS=20inside=20container),=20=20=20operator=20workflow,=20and?= =?UTF-8?q?=20the=20new=20Makefile=20docker=20target?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ARCHITECTURE.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++- PROJECT_PLAN.md | 34 +++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 98e910f..51097cd 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -842,12 +842,14 @@ neither depends on the other. | Environment template | `dist/mcias.env.example` | Master key and other secrets | | Reference config | `dist/mcias.conf.example` | Annotated production config | | Dev config | `dist/mcias-dev.conf.example` | Local development defaults | +| Docker config | `dist/mcias.conf.docker.example` | Config template for container deployment | | Install script | `dist/install.sh` | First-time setup on a Linux host | +| Dockerfile | `Dockerfile` | Multi-stage image for container deployment | | Man page: mciassrv | `man/man1/mciassrv.1` | Server binary reference | | Man page: mciasctl | `man/man1/mciasctl.1` | Admin CLI reference | | Man page: mciasdb | `man/man1/mciasdb.1` | DB tool reference | | Man page: mciasgrpcctl | `man/man1/mciasgrpcctl.1` | gRPC CLI reference | -| Makefile | `Makefile` | Build, test, lint, install, release targets | +| Makefile | `Makefile` | Build, test, lint, install, release, docker targets | ### systemd Unit Design @@ -889,6 +891,57 @@ The unit does not start the service on install. Operators must run mciasgrpcctl.1.gz ``` +### Dockerfile Design + +The image uses a two-stage build to keep the runtime image small and free of +build toolchain: + +``` +# Stage 1 — build +FROM golang:1.26-bookworm AS builder + CGO_ENABLED=1 (SQLite requires cgo) + -trimpath -ldflags="-s -w" (strip DWARF and symbol table) + Builds: mciassrv, mciasctl, mciasdb, mciasgrpcctl + +# Stage 2 — runtime +FROM debian:bookworm-slim + Installs: ca-certificates, libc6 + Copies binaries from builder stage only + Creates uid/gid 10001 (mcias:mcias) + EXPOSE 8443 (REST/TLS) and 9443 (gRPC/TLS) + VOLUME /data (SQLite database mount point) + ENTRYPOINT ["mciassrv"] + CMD ["-config", "/etc/mcias/mcias.conf"] +``` + +Security properties of the runtime image: + +- No shell, no package manager, no Go toolchain — minimal attack surface +- Non-root user (`mcias`, uid 10001) — no escalation path +- TLS termination happens inside the container (same cert/key as bare-metal + deployment); the operator mounts `/etc/mcias/` as a read-only volume + containing the config file, TLS cert, and TLS key +- The SQLite database is on a named volume at `/data`; the operator is + responsible for backup; no network storage is assumed + +Operator workflow: + +``` +# Build image +docker build -t mcias:$(git describe --tags --always) . + +# Run (example) +docker run -d \ + --name mcias \ + -v /path/to/config:/etc/mcias:ro \ + -v mcias-data:/data \ + -p 8443:8443 \ + -p 9443:9443 \ + mcias:latest +``` + +The Makefile `docker` target automates the build step with the version tag. + ### Makefile Targets | Target | Action | @@ -899,6 +952,7 @@ The unit does not start the service on install. Operators must run | `generate` | `go generate ./...` (re-generates proto stubs) | | `man` | Build man pages; compress to `.gz` in `man/` | | `install` | Run `dist/install.sh` | +| `docker` | `docker build -t mcias:$(VERSION) .` | | `clean` | Remove `bin/`, `gen/`, compressed man pages | | `dist` | Cross-compile release tarballs for linux/amd64 and linux/arm64 | diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md index 3348398..cafea3e 100644 --- a/PROJECT_PLAN.md +++ b/PROJECT_PLAN.md @@ -458,12 +458,36 @@ See ARCHITECTURE.md §18 for full design rationale and artifact inventory. - `make build` works from a clean checkout after `go mod download` - Tests: `make build` produces binaries; `make test` passes; `make lint` passes -### Step 8.6: Documentation +### Step 8.6: Dockerfile **Acceptance criteria:** -- `README.md` updated with: quick-start section referencing the install script, - links to man pages, configuration walkthrough -- ARCHITECTURE.md §18 written (operational artifact inventory, file locations, - systemd integration notes) +- `Dockerfile` at repository root using a multi-stage build: + - Build stage: `golang:1.26-bookworm` — compiles all four binaries with + `CGO_ENABLED=1` (required for SQLite via `modernc.org/sqlite`) and + `-trimpath -ldflags="-s -w"` to strip debug info + - Runtime stage: `debian:bookworm-slim` — installs only `ca-certificates` + and `libc6`; copies binaries from the build stage + - Final image runs as a non-root user (`uid=10001`, `gid=10001`; named `mcias`) + - `EXPOSE 8443` (REST) and `EXPOSE 9443` (gRPC); both are overridable via env + - `VOLUME /data` — operator mounts the SQLite database here + - `ENTRYPOINT ["mciassrv"]` with `CMD ["-config", "/etc/mcias/mcias.conf"]` + - Image must not contain the Go toolchain, source code, or build cache +- `dist/mcias.conf.docker.example` — config template suitable for container + deployment: `listen_addr = "0.0.0.0:8443"`, `grpc_addr = "0.0.0.0:9443"`, + `db_path = "/data/mcias.db"`, TLS cert/key paths under `/etc/mcias/` +- `Makefile` gains a `docker` target: `docker build -t mcias:$(VERSION) .` + where `VERSION` defaults to the output of `git describe --tags --always` +- Tests: + - `docker build .` completes without error (run in CI if Docker available; + skip gracefully if not) + - `docker run --rm mcias:latest mciassrv --help` exits 0 + - Image size documented in PROGRESS.md (target: under 50 MB) + +### Step 8.7: Documentation +**Acceptance criteria:** +- `README.md` updated with: quick-start section referencing both the install + script and the Docker image, links to man pages, configuration walkthrough +- ARCHITECTURE.md §18 updated to include the Dockerfile in the artifact + inventory and document the container deployment model - `PROGRESS.md` updated to reflect Phase 8 complete ---