The rig-backup image (rig-gitops#897, P3)¶
The Dell's backup CronJobs dump Postgres, encrypt each dump to an age recipient and upload the ciphertext to R2 (plan: rig-gitops#897). This image holds the tools for that and nothing else. Nothing references it yet; P5 does.
- Dockerfile:
deploy/backup-image/Dockerfile - Workflow:
.github/workflows/publish-backup-image.yml - Security review: claude-3
docs/ai-tooling-registry/backup/2026-10-03-security-review-rig-backup-age-jq-curl.md. Its conditions on how each tool may be called bind the scripts (P4), not just this image.
What is in it¶
| Component | Pin | Source |
|---|---|---|
| Base | docker.io/pgvector/pgvector:0.8.7-pg16-trixie@sha256:40d828eda66737aaacb934387a337babf1455ebd56e9bdd13fc08e211257c972 |
Docker Hub, by index digest. PostgreSQL 16.15 on Debian trixie |
| age | age=1.2.1-1+b5 |
Debian trixie |
| jq | jq=1.7.1-6+deb13u4, libjq1 at the same version |
Debian trixie-security |
| curl | curl=8.14.1-2+deb13u5, libcurl4t64 at the same version |
Debian trixie |
| ca-certificates | ca-certificates=20250419 |
Debian trixie. The base purges it, and curl needs it for TLS |
| openssl | openssl=3.5.7-1~deb13u3, libssl3t64 at the same version |
Debian trixie-security (DSA-6531-1). Already in the base through postgresql-common → ssl-cert, but unpinned; pinned for the openssl review's condition 6.1.1 (P3b), since it signs backup runs (P6) |
apt-get install --no-install-recommends adds those and their dependencies only. The build fails if any
age-plugin-* file exists, and prints every installed package with its version.
- User:
999:999, the base'spostgresuser. HOME=/nonexistent: jq imports~/.jqon every run, and curl, psql and libpq read~/.curlrc,~/.psqlrcand~/.pgpass. None can exist.- Nothing phones home. No health check, no telemetry and no baked-in URL. The only network access is apt at build.
- No script.
ENTRYPOINTis/usr/local/bin/rig-backup.sh, which P4 writes and P5 mounts from a ConfigMap, so a script fix needs no rebuild. Until then the container fails to start; it never runsdocker-entrypoint.shor the server.
Why PostgreSQL 16. pg_dump must be at least the server's major version. The rig's server is
pgvector/pgvector:pg16@sha256:7d400e34…, PostgreSQL 16.13 (deploy/k8s/postgres.yaml:42, deployment).
The backup base is a different, reviewed digest of the same family: 16.15, the same major. The review doesn't cover
the server's digest, so this image doesn't use it. Re-pinning the server to another major means re-pinning this base.
Publishing¶
| Event | What happens |
|---|---|
Pull request touching deploy/backup-image/** or the workflow |
Build, smoke test, package list. No push |
Push to main (same paths), or manual dispatch on main |
The same, then push ghcr.io/dashecorp/rig-backup:sha-<40-hex commit> and record the digest in the run summary |
- Tags: only
sha-<full commit SHA>, neverlatest. Manifests reference the image by tag and digest. - Actions:
actions/checkout,docker/login-actionanddocker/build-push-action, the three this repo already uses, each pinned to the commit its current major tag points to. Permissions arecontents: readandpackages: write, withGITHUB_TOKENfor GHCR. - Smoke test: runs
age --version,jq --version,curl -q --versionandpg_dump --versionin the built image, with the network off and the entrypoint overridden, and fails unless each shows the pinned upstream version. Debian's jq 1.7.1 printsjq-1.7, so it also checks every apt pin's exact Debian version withdpkg-query. - Package list: the run summary lists every package the image adds to the base. The review needs that list on the
image PR: anything outside curl's dependency closure plus
jq,libjq1,libonig5,age,ca-certificatesandopensslis a finding.
Known gaps¶
- No provenance or SBOM attestation. Both need an attestation-capable builder (
docker/setup-buildx-action, and BuildKit's SBOM scanner image), which have no security review. The build setsprovenance: falseandsbom: falseso the default docker driver works. Attestation tooling gets its own review in a follow-up issue. - The base digest was read from the Docker Hub API in the review, not checked against the registry.
Bumping a pin¶
Every pin is a row in the security review. A bump needs a new or updated registry entry in claude-3 first, then a PR here that changes the Dockerfile only.
| Change | What it needs |
|---|---|
New Debian revision of the same upstream version (+deb13uN, +bN) |
Row update after reading its changelog and any DSA. Debian keeps only the current version per suite, so the old pin stops resolving and the build fails: that failure is the trigger |
| New upstream version of age, jq or curl | A new security review |
| Base digest | Row update with the same check: layers 1 to 14 equal to the official postgres:16.x-trixie of that version, the rest equal to pgvector's Dockerfile at the tag, PG_MAJOR equal to the server's major. At least monthly, and on any DSA for a package in the image |
After the bump merges, take the new digest from the run summary and update the manifests that pin it.