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.

Odhadovaná délka studia: 50 minut · Stav: nehotovo

Technologie: Bezpečnost (DevSecOps)

Ú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í

  1. Skenování závislostí aplikace (SCA) — kontroluje seznam
    knihoven, které vaše aplikace přímo nebo tranzitivně používá
    (requirements.txt pro Python, package.json/package-lock.json
    pro Node.js, pom.xml pro Javu). Odhalí, že např. používáte
    requests==2.6.0, ve které je známá zranitelnost opravená až ve
    verzi 2.20.0.
  2. 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řes apt/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

  1. Jaký je rozdíl mezi skenováním aplikačních závislostí (SCA) a
    skenováním celého kontejnerového image?
  2. Proč se doporučuje skenovat image nejen při buildu, ale i
    periodicky po nasazení do produkce?
  3. K čemu slouží přepínač --ignore-unfixed v příkladu s Trivy a
    proč dává smysl ho použít v CI pipeline?
  4. 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í.