fix(release): run the release image as nonroot - #66
Conversation
The final stage used gcr.io/distroless/static-debian12, which defaults to root. Gatekeeper needs no root privilege -- it binds a high port, reads config and keys from mounts, and writes nothing to the image filesystem -- and an orchestrator enforcing runAsNonRoot rejects the image at container start unless every deployment pins an explicit runAsUser. The :nonroot variant declares UID/GID 65532 in the image, where the invariant belongs.
📦 Previous Review (superseded by newer review)Claude finished @andybons's task in 1m 10s —— View job Review complete
SummaryThe change itself — switching the final stage from Finding: this PR breaks the repo's own documented CA setup
chmod 0600 ca.keyThat key is owned by whatever host user ran the script. The docker-deployment guide's own Compose example ( volumes:
- ./ca.key:/etc/gatekeeper/ca.key:roDocker bind mounts preserve host UID/ownership and permission bits — they aren't remapped to the container user. Before this PR the container ran as root, so it could always read the This doesn't need to block a minimal Dockerfile fix, but it should be tracked — either:
Given this PR's stated scope is just the Dockerfile fix + changelog, I'd suggest filing this as a fast follow-up rather than expanding this PR — happy to open that PR if wanted. No other issues found — no security, race-condition, or logic problems in the two changed files. |
The :nonroot base cannot read the 0600 ca.key gen-ca.sh generates under the invoking host user, because a bind mount preserves host ownership. Running the container as that user keeps the key private and the container non-root; loosening the key's mode would leave the interception CA readable to every local user. Reported by the automated review on the pull request.
|
Good catch — the documented flow really would have failed at startup, and the changelog claim did not cover it. Taken in this PR rather than as a follow-up, in 1145057, but with the other remedy than the two suggested. Relaxing |
📦 Previous Review (superseded by newer review)Claude finished @andybons's task in 1m 40s —— View job Reviewing PR #66
SummaryThis is a small, well-scoped fix: switching the release image's final stage to One small doc inaccuracy, left as an inline comment: the Compose example's |
Reported by the automated review on the pull request.
|
Claude finished @andybons's task in 1m 4s —— View job Review complete
SummaryRe-reviewed the current state of the branch (3 commits: the Dockerfile fix, the The overall approach in 1145057 is sound and is the better of the two remedies the earlier review suggested: keeping One minor note (non-blocking)
# Your host uid:gid, so the container can read the 0600 ca.key it
# bind-mounts -- see the note above.
user: "1000:1000"Unlike the two No security, race-condition, or logic issues in the three changed files — the base-image switch is correct and minimal, and the permission fix correctly targets the actual failure mode (host-owned bind mount vs. UID 65532) rather than the previous review's suggested alternative of relaxing the key's mode. |
The final stage used
gcr.io/distroless/static-debian12, which defaults to root. Gatekeeper needs no root privilege — it binds a high port, reads config and key material from mounts, and writes nothing to the image filesystem.The cost shows up under orchestrators that enforce
runAsNonRoot: the pod policy rejects the image at container start (container has runAsNonRoot and image will run as root), and every consumer has to pin an explicitrunAsUserin their deployment — which the boxes chart just had to do (meetneptune/boxes#637). An image-level default is the right home for an invariant every consumer wants.The
:nonrootvariant declares UID/GID 65532 in the image. Deployments already pinning 65532 keep working unchanged, since that is the identity the image now declares.Changelog entry for v0.22.1 rides in this PR, so the release tag lands on a tree that carries it.