Task(docker): harden kongctl image with distroless
- Dominant language
- Go
- Stars
- 17
- Forks
- 24
- Avg merge
- 8h 13m
- Merged PRs (30d)
- 196
Description
## Context
deck moved its runtime container from Alpine to
`gcr.io/distroless/static-debian12:nonroot` to reduce inherited packages and
security findings: Kong/deck#2164.
kongctl also uses Alpine as its final runtime image. Its released Linux binaries
are built with `CGO_ENABLED=0` and are statically linked, so the core CLI is a
good fit for a distroless static image. Distroless provides the CA certificate
bundle, timezone data, `/tmp`, non-root account data, and writable non-root home
directory needed by the core CLI.
This is not completely drop-in compatible with all currently documented
container behavior. kongctl supports executable extensions, documents universal
shell-script extensions, and includes an example using `#!/bin/sh`. A normal
distroless image has no shell or common utilities. Distroless static also cannot
run dynamically linked extension binaries.
Other external executable paths include declarative `_deck` operations and the
Git-based extension source fallback. The current published Alpine image does not
bundle either `deck` or `git`, so those paths already require additional tooling.
## Proposed approach
- Make a digest-pinned
`gcr.io/distroless/static-debian13:nonroot` image the default runtime image.
Debian 13 is preferred because the distroless Debian 12 image line approaches
end of life in September 2026.
- Set `HOME=/home/nonroot` explicitly. kongctl resolves its default configuration
directory with `os.UserHomeDir()`, while the distroless static image does not
set `HOME`.
- Define the official distroless container contract as supporting self-contained,
statically linked extension executables.
- If shell-script or broader executable compatibility must remain supported,
publish a separately named Alpine/tools image rather than adding a shell to the
hardened production image.
- Document the non-root UID (`65532`), home path, lack of shell, and static-only
external executable requirement.
The expected Dockerfile shape is:
```dockerfile
FROM gcr.io/distroless/static-debian13:nonroot@sha256:
ARG TARGETPLATFORM
ENV HOME=/home/nonroot
COPY --chown=nonroot:nonroot $TARGETPLATFORM/kongctl /kongctl
USER nonroot
ENTRYPOINT ["/kongctl"]
```
## Acceptance criteria
- [ ] Decide and document the supported extension contract for the official
container image.
- [ ] Replace the final Alpine runtime with a digest-pinned distroless static
Debian 13 non-root image.
- [ ] Preserve multi-platform publication for `linux/amd64` and `linux/arm64`.
- [ ] Set and verify a writable home directory for configuration, logs, tokens,
and extension state.
- [ ] Add container smoke coverage for version/help output, non-root execution,
configuration persistence, HTTPS/CA validation, `/tmp`, file I/O, and the
detached audit-log listener.
- [ ] Test a statically linked extension and document or test the expected
behavior for shell-script and dynamically linked extensions.
- [ ] Test supplied `deck` and `git` executables if those workflows are part of
the supported official-container contract.
- [ ] Compare the Alpine and distroless images using the same vulnerability
scanner, SBOM generator, and compressed-size measurement.
- [ ] Document debugging guidance using the corresponding `debug-nonroot` image
without publishing it as the production default.
## References
- Kong/deck#2164
- https://github.com/GoogleContainerTools/distroless
- https://github.com/GoogleContainerTools/distroless/blob/main/SUPPORT_POLICY.md
- `Dockerfile`
- `.goreleaser.yml`
- `docs/extensions.md`
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with Dockerfile, .goreleaser.yml, and docs/extensions.md to understand the current image, platform publication, and extension contract. Review existing container checks before adding coverage for non-root execution, configuration persistence, HTTPS, /tmp, file I/O, and extension behavior. Done means the digest-pinned distroless image is published for both Linux platforms with documented supported behavior and verification results.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, go
- Domain
- cli, devops, infrastructure
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100