Als upstream niet herbouwt: geharde images in plaats van uitzonderingen
Een Trivy-gate in de pipeline blokkeerde twee keer op dezelfde soort bevinding: een officiële image met kritieke kwetsbaarheden in OS-pakketten, terwijl Debian de fix al had uitgebracht.
- Redis: drie CRITICAL's in
perl-base. Drie verschillende Redis-versies bevatten exact dezelfde bevindingen. - Gotenberg (HTML naar PDF met Chromium): 25 CRITICAL's in Chromium. Debian had al een nieuwere Chromium, en de nieuwste Gotenberg-release was nog niet herbouwd.
Upgraden hielp dus niet. Het probleem is dat officiële images niet opnieuw worden gebouwd zodra Debian een securityupdate uitbrengt.
Wat ik niet deed
- Een uitzondering in
.trivyignore. De CVE's hebben de statusfixed. Een uitzondering is dan uitstel zonder einddatum. In de bestaande uitzonderingslijsten stonden alleen bevindingen die "niet oplosbaar" of "niet van toepassing" waren, en dat patroon wilde ik niet doorbreken. - Overstappen naar alpine. De Redis-alpine-image scande schoon, maar mist
bash, en de Helm-chart roept bash aan in de preStop-hooks voor een gecontroleerde failover. Die herschrijven raakt de failoverlogica van een productiedatabase. - De gate verzachten. Dan staat de deur open voor elke toekomstige OS-CVE.
Wat ik wel deed
Een eigen herbouw van dezelfde officiële image, met precies één verschil: apt-get upgrade.
FROM redis:8.8.0@sha256:<gepinde basis>
RUN apt-get update && apt-get -y upgrade && rm -rf /var/lib/apt/lists/*
- Dezelfde entrypoint, dezelfde shells, dezelfde gebruiker, geen extra pakketten.
- Bewust gebaseerd op de versie die al draaide, zodat de enige wijziging bij uitrol de securitypatches zijn. Een versiebump is een aparte, zichtbare stap.
- Lokaal geverifieerd met dezelfde hardening als in productie: read-only, vaste uid,
--cap-drop ALL,no-new-privileges. Voor Gotenberg ook een echte HTML-naar-PDF-conversie.
Resultaat: van 3 en 25 CRITICAL's naar 0.
Onderhoudbaar houden
apt-get upgrade is niet reproduceerbaar: elke build levert een andere image op. Dat is hier precies de bedoeling. Wat het beheersbaar maakt:
- Een geplande pipeline, elke maandagochtend, die herbouwt en publiceert. Chromium krijgt vaker securityfixes dan bijna elk ander pakket; zonder schedule veroudert de image binnen weken. Dat bleek ook: twee weken later blokkeerde de gate opnieuw op Chromium.
- De consumenten pinnen de resulterende digest. Een nieuwe image komt alleen in productie via een merge request met die digest.
- De basis-digest staat in de Dockerfile en verandert alleen via een merge request, zodat elke bump in de geschiedenis zichtbaar is.
- Een eigen registry met authenticatie: pull-secrets van deploy tokens met alleen
read_registry, en een job-token-allowlist zodat andere pipelines de image mogen scannen.
Er blijven soms bevindingen over die niet met apt op te lossen zijn, bijvoorbeeld in een meegeleverde Go-binary. Die blokkeren de gate niet en staan in het rapport, tot een nieuwe upstream-release ze oplost.
De les
Een security-gate is pas nuttig als je hem niet omzeilt zodra hij lastig wordt. Zelf herbouwen kost een Dockerfile van drie regels en een schedule. Een uitzondering kost je het vertrouwen in de gate.