Skip to content

build(docker): переход runtime-образов на distroless и запуск от non-root - #64

Merged
avlllo merged 3 commits into
Runtime-Radar:mainfrom
dato-dev:feat/distroless-images
Oct 20, 2026
Merged

avlllo merged 3 commits into
Runtime-Radar:mainfrom
dato-dev:feat/distroless-images

Conversation

@dato-dev

Copy link
Copy Markdown
Contributor

Что сделано

Runtime-образы всех Go-сервисов собираются на debian:12.0-slim (самый первый релиз Debian 12, июнь 2023), запускаются от root и содержат CLI gops. Этот PR закрывает все три проблемы:

  • Runner-стадия всех 10 Go-сервисов переведена на gcr.io/distroless/static-debian13. Все сервисы собираются с CGO_ENABLED=0, поэтому статического базового образа достаточно.
  • 9 сервисов запускаются от UID 65532. UID указан числом, чтобы kubelet мог проверить runAsNonRoot.
  • Явно задан WORKDIR /. TLS- и DB-сертификаты загружаются по относительным путям, а Helm-чарт монтирует их с относительным mountPath (cert.pem, ca.pem, ...), который разрешается относительно рабочей директории образа. У distroless:nonroot она по умолчанию /home/nonroot, поэтому без этой строки TLS бы сломался.
  • runtime-monitor остаётся под root: он общается с Tetragon, который работает от root в том же поде. Это особенно важно, если fix(runtime-monitor): move Tetragon gRPC to a Unix socket (CVE-2026-65960) #61 переведёт связь на Unix-сокет.
  • Из образов удалён CLI gops. Это отдельный коммит, его легко откатить, если утилита вам нужна. Встроенный в сервисы gops-агент продолжает работать, а для отладки можно использовать kubectl debug с эфемерным контейнером.

Попутный фикс: системные CA-сертификаты

В debian:12.0-slim нет пакета ca-certificates, поэтому каталог /etc/ssl/certs отсутствует, а x509.SystemCertPool() (lib/security/tls.go) возвращает пустой пул. Из-за этого интеграции webhook и SMTP с включённой проверкой сертификата не могут проверить публичные TLS-эндпоинты. В distroless CA-бандл есть.

Результаты (notifier, Trivy)

До После
Уязвимости ОС 370 (6 critical, 89 high) 0
Уязвимости бинарника gops 46 0 (удалён)
Размер образа 137 МБ 37 МБ
Пользователь root 65532

Оставшиеся 56 находок относятся к самому бинарнику сервиса (stdlib Go и зависимости) и в этот PR не входят. Их я предлагаю закрыть отдельным PR через обновление GO_VERSION.

Как проверял

  • Все 10 образов собираются.
  • Чарт из install/helm установлен в kind-кластер с новыми образами (global.imageTag=dev): все поды в Running, включая notifier с podSecurityContext.runAsNonRoot=true.
  • POST /api/v1/signin через reverse-proxy возвращает токены, то есть цепочка сервисов работает по TLS.
  • Проверены пути, куда сервисы пишут при readOnlyRootFilesystem: GOPS_CONFIG_DIR=/tmp и /var/log/cs — это emptyDir. Лог-файлы создаются с правами 0644, поэтому sidecar логгера может их читать.

Заметки

  • Базовые образы закреплены только по тегу. Закрепление по digest вместе с Dependabot можно сделать отдельным PR.
  • Hardening securityContext в Helm (runAsNonRoot, capabilities.drop: [ALL]) опирается на этот PR и пойдёт отдельно.

dato-dev and others added 2 commits October 12, 2026 21:12
Replace the outdated debian:12.0-slim runner base with
gcr.io/distroless/static-debian13. All Go services are built with
CGO_ENABLED=0, so a static base is sufficient. Distroless also ships
the CA bundle that x509.SystemCertPool() relies on (debian slim does
not), plus tzdata and a nonroot user.

All services except runtime-monitor now run as UID 65532. The numeric
UID lets the kubelet verify runAsNonRoot. WORKDIR is set to / because
TLS and DB certificates are loaded by relative paths.

runtime-monitor stays root because it talks to Tetragon, which runs as
root in the same pod.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The gops binary was copied into every image only for interactive
debugging and added its own set of vulnerable dependencies. The gops
agent embedded in the services is unaffected; the CLI can still be used
from a workstation or an ephemeral debug container (kubectl debug).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@avlllo

avlllo commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

Спасибо за PR!

Я добавил наши undistro образы, собранные через apko (#65). Давайте заменим gcr.io/distroless/static-debian13:nonroot на ghcr.io/runtime-radar/runtime-radar-base:20261014

Switch the nine non-root services from gcr.io/distroless/static-debian13
to the project's apko-built Wolfi base image (Runtime-Radar#65), as suggested in
review. The base ships ca-certificates-bundle and tzdata and runs as
UID 65532, so the existing USER and WORKDIR directives stay valid.

runtime-monitor is unchanged: it must run as root, while the new base
defaults to the nonroot user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dato-dev

Copy link
Copy Markdown
Contributor Author

Спасибо за PR!

Я добавил наши undistro образы, собранные через apko (#65). Давайте заменим gcr.io/distroless/static-debian13:nonroot на ghcr.io/runtime-radar/runtime-radar-base:20261014

Привет! Готово.

@avlllo
avlllo merged commit 97e97a1 into Runtime-Radar:main Oct 20, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants