Modul 13 — Bezpečnost (DevSecOps)
63. Bezpečnostní skenování kontejnerů a závislostí
Jak najít známé zranitelnosti v base image, nainstalovaných balíčcích a knihovnách vaší aplikace dřív, než je najde útočník, pomocí nástrojů jako Trivy a Grype.
Úvod a kontext
Moderní aplikace zřídka vzniká od nuly — staví na desítkách až
stovkách závislostí (knihoven) a Docker image staví na base image
s celým operačním systémem uvnitř. Každá z těchto vrstev může
obsahovat známou zranitelnost (CVE — Common Vulnerabilities and
Exposures), o které svět už ví, jen vy jste image nebo závislost
dlouho neaktualizovali. Podle řady studií pochází velká část
skutečných úniků dat právě ze známých, dlouho neopravených
zranitelností ve třetích stranách, ne z chyb v samotném aplikačním
kódu. Skenování kontejnerů a závislostí je automatizovaná obrana
proti tomuto riziku.
Teorie
Co je CVE a jak funguje databáze zranitelností
Když bezpečnostní výzkumník nebo dodavatel objeví zranitelnost
v nějakém softwaru (např. v konkrétní verzi knihovny openssl),
zranitelnost dostane unikátní identifikátor ve formátu
CVE-2023-12345 a je zveřejněna ve veřejných databázích (NVD —
National Vulnerability Database, a další). Ke každé CVE existuje
hodnocení závažnosti (CVSS skóre, typicky nízká/střední/vysoká/
kritická) a často i informace o tom, od které opravené verze je
zranitelnost odstraněná. Scannery pravidelně stahují tyto databáze
a porovnávají je se skutečným obsahem vašeho image nebo
requirements.txt/package.json.
Dvě roviny skenování
- Skenování závislostí aplikace (SCA) — kontroluje seznam
knihoven, které vaše aplikace přímo nebo tranzitivně používá
(requirements.txtpro Python,package.json/package-lock.json
pro Node.js,pom.xmlpro Javu). Odhalí, že např. používáte
requests==2.6.0, ve které je známá zranitelnost opravená až ve
verzi 2.20.0. - Skenování kontejnerového image — jde hlouběji: kontroluje
nejen aplikační závislosti, ale i celý base image — balíčky
operačního systému nainstalované přesapt/apk/yum, sdílené
knihovny, i zapomenuté nástroje, které v image zůstaly, přestože
je aplikace nepotřebuje.
Kdy skenovat
Podobně jako u ostatních DevSecOps kontrol platí "shift-left":
- Při vývoji — vývojář může spustit scanner lokálně před
commitem. - V CI pipeline při každém buildu — nejdůležitější bod, protože
chytí problém dřív, než image doputuje do registru. Build s
kritickou zranitelností může pipeline zastavit. - Pravidelně nad již nasazenými image — i image, který byl
v pořádku v den buildu, se může stát zranitelným později, když
vyjde nová CVE pro balíček, který v něm je. Proto se doporučuje
i periodické přeskenování image v registru, ne jen jednorázově
při buildu.
Jak reagovat na nález
Ne každá nalezená CVE vyžaduje okamžitou akci. Praxe je stanovit
politiku podle závažnosti — např. "kritické a vysoké zranitelnosti
blokují merge/deploy, střední se řeší do týdne, nízké se sledují,
ale neblokují". Důležité je také rozlišit skutečně vykonatelnou
zranitelnost (balíček je v image přítomný a používaný) od
zranitelnosti v kódu, který se nikdy nespustí — moderní scannery se
snaží tuto tzv. "reachability" analýzu částečně dělat, ale základní
skenery hlásí přítomnost balíčku bez ohledu na to, zda je v runtime
skutečně využit.
Praktický příklad
Skenování Docker image nástrojem Trivy (jeden z nejrozšířenějších
open-source scannerů, umí kontejnery, souborové systémy i
IaC konfigurace) — v CI kroku, který selže při nálezu kritické nebo
vysoké zranitelnosti:
# Sestavení image
docker build -t registry.interni/objednavky:1.4.0 .
# Sken image, jen kritické a vysoké závažnosti, exit kód 1 při nálezu
trivy image \
--severity CRITICAL,HIGH \
--exit-code 1 \
--ignore-unfixed \
registry.interni/objednavky:1.4.0
--ignore-unfixed vynechá zranitelnosti, na které zatím neexistuje
oprava (nemá smysl blokovat build kvůli něčemu, co nejde opravit).
Výstup ukazuje balíček, nainstalovanou verzi, opravenou verzi a CVE:
objednavky:1.4.0 (debian 12.4)
=================================
Total: 2 (CRITICAL: 1, HIGH: 1)
┌──────────┬────────────────┬──────────┬───────────────┬───────────────┐
│ Library │ Vulnerability │ Severity │ Installed Ver │ Fixed Version │
├──────────┼────────────────┼──────────┼───────────────┼───────────────┤
│ libssl3 │ CVE-2023-5678 │ CRITICAL │ 3.0.11-1 │ 3.0.13-1 │
│ zlib1g │ CVE-2022-37434 │ HIGH │ 1:1.2.13.dfsg │ 1:1.2.13.dfsg │
│ │ │ │ │ -1+deb12u1 │
└──────────┴────────────────┴──────────┴───────────────┴───────────────┘
Skenování aplikačních závislostí nástrojem Grype nebo pip-audit
přímo nad manifestem, ještě před buildem image:
pip install pip-audit
pip-audit -r requirements.txt
Integrace do GitHub Actions, která zastaví pipeline při nálezu:
- name: Sken image nástrojem Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'registry.interni/objednavky:${{ github.sha }}'
severity: 'CRITICAL,HIGH'
exit-code: '1'
ignore-unfixed: true
Shrnutí
Skenování kontejnerů a závislostí automaticky porovnává obsah vašeho
image a seznam knihoven se známými databázemi zranitelností (CVE) —
na dvou rovinách: aplikační závislosti (SCA) a celý obsah base image.
Mělo by probíhat opakovaně: při vývoji, v CI při každém buildu, i
periodicky nad již nasazenými image, protože nové CVE vycházejí
průběžně. Politika reakce na nález (co blokuje pipeline, co se jen
sleduje) by měla odpovídat závažnosti a měla by být definovaná
předem, ne ad hoc při každém nálezu.
Kontrolní otázky
- Jaký je rozdíl mezi skenováním aplikačních závislostí (SCA) a
skenováním celého kontejnerového image? - Proč se doporučuje skenovat image nejen při buildu, ale i
periodicky po nasazení do produkce? - K čemu slouží přepínač
--ignore-unfixedv příkladu s Trivy a
proč dává smysl ho použít v CI pipeline? - Mini cvičení: navrhněte politiku, která CVE závažnosti blokují
merge pull requestu, které jen generují varování, a zdůvodněte
svou volbu.
Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.