
Ahoj, Habr!
V moderní realitě, vzhledem k rostoucí roli kontejnerizace v procesních vývojích, není zanedbatelnou otázkou zajištění bezpečnosti různých fází a entit spojených s kontejnery. Provádění kontrol v manuálním režimu je časově náročný úkol, proto by bylo dobré učinit alespoň počáteční kroky k automatizaci tohoto procesu.
V tomto článku se podělím o hotové skripty pro implementaci několika nástrojů pro zajištění bezpečnosti Dockeru a o instrukce, jak nasadit malou demo platformu pro testování tohoto procesu. Tyto materiály lze využít k experimentování s organizací procesu testování bezpečnosti obrazů a instrukcí Dockerfile. Je jasné, že infrastruktura vývoje a nasazení se u každého liší, proto níže uvedu několik možných variant.
Nástroje pro kontrolu bezpečnosti
Existuje velké množství různých pomocných aplikací a skriptů, které provádějí kontroly různých aspektů Docker infrastruktury. Některé z nich byly již popsány v předchozím článku (), a v tomto materiálu bych se chtěl zaměřit na tři z nich, které pokrývají hlavní části požadavků na bezpečnost Docker obrazů, které se vytvářejí v procesu vývoje. Kromě toho také ukážu příklad, jak lze tyto tři nástroje spojit do jednoho pipeline pro provádění kontrol bezpečnosti.
Hadolint
Poměrně jednoduchý příkazový nástroj, který pomáhá v prvním přiblížení posoudit správnost a bezpečnost instrukcí Dockerfile (například používání pouze povolených registrů obrazů nebo používání sudo).

Dockle
Příkazový nástroj, který pracuje s obrazem (nebo se uloženým tar archivem obrazu), který kontroluje správnost a bezpečnost konkrétního obrazu tím, že analyzuje jeho vrstvy a konfiguraci – jaké uživatele vytvořil, jaké instrukce byly použity, jaké svazky jsou připojeny, přítomnost prázdného hesla atd. Zatím není počet kontrol příliš velký a vychází z několika vlastních kontrol a doporučení. pro Docker.

Trivy
Tento nástroj je zaměřen na hledání zranitelností dvou typů – problémy se sestaveními OS (podporovány Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu) a problémy v závislostech (Gemfile.lock, Pipfile.lock, composer.lock, package-lock.json, yarn.lock, Cargo.lock). Trivy dokáže skenovat jak obraz v repozitáři, tak lokální obraz, a také provádět skenování na základě předaného .tar souboru s Docker obrazem.

Možnosti implementace nástrojů
Abychom vyzkoušeli popsané aplikace v izolovaných podmínkách, poskytnu pokyny k instalaci všech nástrojů v rámci zjednodušeného procesu.
Hlavní myšlenkou je demonstrovat, jak je možné implementovat automatickou kontrolu obsahu Dockerfile a Docker obrazů, které se vytvářejí v průběhu vývoje.
Samotná kontrola se skládá z následujících kroků:
- Kontrola správnosti a bezpečnosti instrukcí Dockerfile – pomocí linteru Hadolint
- Kontrola správnosti a bezpečnosti finálních a mezilehlých obrazů – pomocí nástroje Dockle
- Kontrola přítomnosti známých zranitelností (CVE) v základním obrazu a řadě závislostí – pomocí nástroje Trivy
Dále v článku uvedu tři možnosti implementace těchto kroků:
První – prostřednictvím konfigurace CI/CD pipeline na příkladu GitLab (s popisem procesu zprovoznění testovacího instance).
Druhý – s použitím shell skriptu.
Třetí – s vytvořením Docker obrazu pro skenování Docker obrazů.
Můžete si vybrat variantu, která vám nejvíce vyhovuje, přenést ji do své infrastruktury a přizpůsobit svým potřebám.
Všechny potřebné soubory a další pokyny se také nacházejí v repozitáři:
Integrace do GitLab CI/CD
V první variantě se podíváme, jak lze implementovat bezpečnostní kontroly na příkladu systému repozitářů GitLab. Zde projdeme kroky a podrobně rozebere jak nainstalovat testovací prostředí s GitLab, vytvořit proces skenování a provést spuštění nástrojů pro kontrolu testovacího Dockerfile a náhodného obrazu – aplikace JuiceShop.
Instalace GitLab
1. Nainstalujte Docker:
sudo apt-get update && sudo apt-get install docker.io2. Přidejte aktuálního uživatele do skupiny docker, aby bylo možné pracovat s dockery bez sudo:
sudo addgroup docker3. Najděte svou IP adresu:
ip addr4. Nainstalujte a spusťte GitLab v kontejneru, nahraďte IP adresu v hostname svou:
docker run --detach
--hostname 192.168.1.112
--publish 443:443 --publish 80:80
--name gitlab
--restart always
--volume /srv/gitlab/config:/etc/gitlab
--volume /srv/gitlab/logs:/var/log/gitlab
--volume /srv/gitlab/data:/var/opt/gitlab
gitlab/gitlab-ce:latestČekáme, až GitLab provede všechny potřebné instalační procedury (můžete sledovat proces prostřednictvím výstupu log souboru: docker logs -f gitlab).
5. Otevřete ve svém prohlížeči svou místní IP a uvidíte stránku, která nabízí změnu hesla pro uživatele root:

Nastavte nové heslo a přihlaste se do GitLab.
6. Vytvořte nový projekt, například cicd-test a inicializujte ho startovním souborem README.md:

7. Nyní je třeba nainstalovat GitLab Runner: agenta, který na požádání spouští všechny potřebné operace.
Stáhněte nejnovější verzi (v tomto případě — pro Linux 64-bit):
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd648. Učiňte ho spustitelným:
sudo chmod +x /usr/local/bin/gitlab-runner9. Přidejte uživatele OS pro Runner-a a spusťte službu:
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner startVýsledek by měl vypadat zhruba takto:
local@osboxes:~$ sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
Runtime platform arch=amd64 os=linux pid=8438 revision=0e5417a3 version=12.0.1
local@osboxes:~$ sudo gitlab-runner start
Runtime platform arch=amd64 os=linux pid=8518 revision=0e5417a3 version=12.0.1 10. Nyní registrujeme Runner, aby mohl interagovat s naším instancí GitLab.
K tomu otevřete stránku Nastavení-CI/CD (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) a na kartě Runners najděte URL a registrační token:

11. Registrujeme Runner, vložením URL a registračního tokenu:
sudo gitlab-runner register
--non-interactive
--url "http:///"
--registration-token ""
--executor "docker"
--docker-privileged
--docker-image alpine:latest
--description "docker-runner"
--tag-list "docker,privileged"
--run-untagged="true"
--locked="false"
--access-level="not_protected"V důsledku toho získáme plně funkční GitLab, do kterého je třeba přidat instrukce pro spuštění našich utilit. V této demonstrační ukázce nemáme kroky pro sestavení aplikace a její kontejnerizaci, ale v reálném prostředí by předcházely krokům skenování a vytvářely by obrazy a Dockerfile pro analýzu.
Konfigurace pipeline
1. Přidejte do repozitáře soubory mydockerfile.df (to je testovací Dockerfile, který budeme ověřovat) a konfigurační soubor GitLab CI/CD procesu .gitlab-cicd.yml, který obsahuje instrukce pro skenery (všimněte si tečky v názvu souboru).
Konfigurační YAML soubor obsahuje pokyny pro spuštění tří utilit (Hadolint, Dockle a Trivy), které analyzují vybraný Dockerfile a obraz zadaný v proměnné DOCKERFILE. Všechny potřebné soubory lze získat z repozitáře:
Úryvek z mydockerfile.df (jedná se o abstraktní soubor s sadou libovolných pokynů pouze pro demonstraci fungování utilit). Přímý odkaz na soubor:
Obsah mydockerfile.df
FROM amd64/node:10.16.0-alpine@sha256:f59303fb3248e5d992586c76cc83e1d3700f641cbcd7c0067bc7ad5bb2e5b489 AS tsbuild
COPY package.json .
COPY yarn.lock .
RUN yarn install
COPY lib lib
COPY tsconfig.json tsconfig.json
COPY tsconfig.app.json tsconfig.app.json
RUN yarn build
FROM amd64/ubuntu:18.04@sha256:eb70667a801686f914408558660da753cde27192cd036148e58258819b927395
LABEL maintainer="Rhys Arkins "
LABEL name="renovate"
...
COPY php.ini /usr/local/etc/php/php.ini
RUN cp -a /tmp/piik/* /var/www/html/
RUN rm -rf /tmp/piwik
RUN chown -R www-data /var/www/html
ADD piwik-cli-setup /piwik-cli-setup
ADD reset.php /var/www/html/
## ENTRYPOINT ##
ADD entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
USER rootKonfigurace YAML vypadá takto (soubor lze získat přímým odkazem zde: ):
Obsah .gitlab-ci.yml
proměnné:
DOCKER_HOST: "tcp://docker:2375/"
DOCKERFILE: "mydockerfile.df" # název Dockerfile k analýze
DOCKERIMAGE: "bkimminich/juice-shop" # název Docker obrazu k analýze
# DOCKERIMAGE: "knqyf263/cve-2018-11235" # testovací Docker obraz s několika KRITICKÝMI CVE
SHOWSTOPPER_PRIORITY: "CRITICAL" # jaká úroveň kritičnosti způsobí selhání úlohy Trivy
TRIVYCACHE: "$CI_PROJECT_DIR/.cache" # kde ukládat databázi zranitelností Trivy pro rychlejší opětovné použití
ARTIFACT_FOLDER: "$CI_PROJECT_DIR"
služby:
- docker:dind # k umožnění vytváření docker obrazů uvnitř správce
stádia:
- skenování
- zpráva
- publikování
HadoLint:
# Základní analýza lintování instrukcí Dockerfile
stage: skenování
image: docker:git
po_scriptu:
- cat $ARTIFACT_FOLDER/hadolint_results.json
skript:
- export VERSION=$(wget -q -O - https://api.github.com/repos/hadolint/hadolint/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*//1/')
- wget https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64 && chmod +x hadolint-Linux-x86_64
# NB: hadolint vždy ukončí s kódem 0
- ./hadolint-Linux-x86_64 -f json $DOCKERFILE > $ARTIFACT_FOLDER/hadolint_results.json || exit 0
artefakty:
when: always # vrátit artefakty i po selhání úlohy
cesty:
- $ARTIFACT_FOLDER/hadolint_results.json
Dockle:
# Analýza nejlepších praktik týkajících se Docker obrazu (uživatelská oprávnění, dodržování pokynů při vytváření obrazu atd.)
stage: skenování
image: docker:git
po_scriptu:
- cat $ARTIFACT_FOLDER/dockle_results.json
skript:
- export VERSION=$(wget -q -O - https://api.github.com/repos/goodwithtech/dockle/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*//1/')
- wget https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz && tar zxf dockle_${VERSION}_Linux-64bit.tar.gz
- ./dockle --exit-code 1 -f json --output $ARTIFACT_FOLDER/dockle_results.json $DOCKERIMAGE
artefakty:
when: always # vrátit artefakty i po selhání úlohy
cesty:
- $ARTIFACT_FOLDER/dockle_results.json
Trivy:
# Analýza Docker obrazu a závislostí balíčku proti několika CVE databázím
stage: skenování
image: docker:git
skript:
# získání nejnovější verze Trivy
- apk add rpm
- export VERSION=$(wget -q -O - https://api.github.com/repos/knqyf263/trivy/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*//1')
- wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz && tar zxf trivy_${VERSION}_Linux-64bit.tar.gz
# zobrazení všech zranitelností bez selhání kompilace
- ./trivy -d --cache-dir $TRIVYCACHE -f json -o $ARTIFACT_FOLDER/trivy_results.json --exit-code 0 $DOCKERIMAGE
# zapište informace o zranitelnostech do stdout ve čitelném formátu (číst čistý json není zábava, že?). Tento příkaz můžete odstranit, pokud to nepotřebujete.
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 0 $DOCKERIMAGE
# selhání kompilace, pokud je nalezena priorita SHOWSTOPPER
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 1 --severity $SHOWSTOPPER_PRIORITY --quiet $DOCKERIMAGE
artefakty:
when: always # vrátit artefakty i po selhání úlohy
cesty:
- $ARTIFACT_FOLDER/trivy_results.json
cache:
cesty:
- .cache
Zpráva:
# kombinování výstupů nástrojů do jednoho HTML
stage: zpráva
when: always
image: python:3.5
skript:
- mkdir json
- cp $ARTIFACT_FOLDER/*.json ./json/
- pip install json2html
- wget https://raw.githubusercontent.com/shad0wrunner/docker_cicd/master/convert_json_results.py
- python ./convert_json_results.py
artefakty:
cesty:
- results.htmlV případě potřeby lze také skenovat a ukládat obrazy jako .tar archiv (bude však třeba v souboru YAML změnit vstupní parametry pro nástroje).
NB: Trivy vyžaduje pro svůj běh nainstalované rpm a git. Jinak bude vykazovat chyby při skenování obrazů založených na RedHat a získávání aktualizací databáze zranitelnosti.
2. Po přidání souborů do repozitáře GitLab automaticky spustí proces sestavení a skenování podle pokynů v našem konfiguračním souboru. Na kartě CI/CD → Pipelines bude možné vidět průběh vykonávání pokynů.
Naším výsledkem jsou čtyři úkoly. Tři z nich se zabývají přímo skenováním a poslední (Report) shromažďuje jednoduchou zprávu z rozptýlených souborů s výsledky skenování.

Ve výchozím nastavení Trivy zastavuje svůj běh, pokud byly nalezeny CRITICAL zranitelnosti v obraze nebo závislostech. Na druhou stranu Hadolint vždy vrací úspěšný kód provedení, protože jeho výsledkem je vždy nějaká poznámka, což vede k zastavení sestavení.
V závislosti na konkrétních požadavcích lze konfigurovat kód výstupu, aby tyto nástroje při nalezení problémů určité kritičnosti také zastavily proces sestavení. V našem případě sestavení zastaví pouze v případě, že Trivy nalezne zranitelnost s kritičností, kterou jsme uvedli ve vazbě SHOWSTOPPER v .gitlab-ci.yml.

Výsledek činnosti každého nástroje lze zobrazit v protokolu každého skenovacího úkolu, přímo v json souborech v sekci artefakty nebo v jednoduché HTML zprávě (o ní více níže):

3. Pro zobrazení zpráv nástrojů v mírně čitelnějším formátu se používá malý skript v Pythonu pro konverzi třech json souborů do jednoho HTML souboru s tabulkou defektů.
Tento skript je spuštěn jako samostatný úkol Report a jeho výstupním artefaktem je HTML soubor se zprávou. Zdrojový kód skriptu je také v repozitáři a může být přizpůsoben vašim potřebám, barvám atd.

Shell skript
Druhá varianta je vhodná pro případy, kdy je potřeba kontrolovat Docker obrazy mimo CI/CD systém nebo mít všechny instrukce v proveditelném formátu přímo na hostitelské platformě. Tato varianta je pokryta hotovým shell skriptem, který lze spustit na čistém virtuálním (nebo dokonce fyzickém) stroji. Skript provádí stejné instrukce jako výše uvedený gitlab-runner.
Pro úspěšné fungování skriptu musí být v systému nainstalován Docker a aktuální uživatel musí být ve skupině docker.
Samotný skript si můžete stáhnout zde:
Na začátku souboru jsou proměnné, který obraz je třeba skenovat a která úroveň závažnosti chyb způsobí ukončení utility Trivy s uvedeným kódem chyby.
Během vykonávání skriptu budou všechny utility staženy do adresáře docker_tools, výsledky jejich práce budou v adresáři docker_tools/json, a HTML report bude umístěn v souboru results.html.
Příklad výstupu skriptu
~\/docker_cicd$ .\/docker_sec_check.sh
[+] Nastavení proměnných prostředí
[+] Instalace požadovaných balíků
[+] Příprava potřebných adresářů
[+] Stahování vzorového Dockerfile
2020-10-20 10:40:00 (45.3 MB\/s) - ‘Dockerfile’ uloženo [8071\/8071]
[+] Stahování obrazu k analýze
latest: Tahání z bkimminich\/juice-shop
[+] Spuštění Hadolintu
...
Dockerfile:205 DL3015 Vyhněte se dalším balíkům specifikováním `--no-install-recommends`
Dockerfile:248 DL3002 Poslední uživatel by neměl být root
...
[+] Spuštění Dockle
...
WARN - DKL-DI-0006: Vyhněte se poslednímu tagu
* Vyhněte se tagu 'latest'
INFO - CIS-DI-0005: Aktivujte důvěru obsahu pro Docker
* export DOCKER_CONTENT_TRUST=1 před docker pull\/build
...
[+] Spuštění Trivy
juice-shop\/frontend\/package-lock.json
=====================================
Celkem: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 2, CRITICAL: 0)
+---------------------+------------------+----------+---------+-------------------------+
| KNIHOVNA | ID ZRANITELNOSTI | ZÁVAŽNOST| VERZE | NÁZEV |
+---------------------+------------------+----------+---------+-------------------------+
| object-path | CVE-2020-15256 | HIGH | 0.11.4 | Zneužití prototypu v |
| | | | | object-path |
+---------------------+------------------+ +---------+-------------------------+
| tree-kill | CVE-2019-15599 | | 1.2.2 | Vložení kódu |
+---------------------+------------------+----------+---------+-------------------------+
| webpack-subresource | CVE-2020-15262 | LOW | 1.4.1 | Nepřístupné dynamicky |
| | | | | načítané části |
+---------------------+------------------+----------+---------+-------------------------+
juice-shop\/package-lock.json
============================
Celkem: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
juice-shop\/package-lock.json
============================
Celkem: 5 (CRITICAL: 5)
...
[+] Odstranění zbytků
[+] Úprava výstupu pro lepší přehlednost
[+] Převod výsledků do JSONu
[+] Zápis výsledků do HTML
[+] Úspěšný konec ============================================================
[+] Vše je hotovo. Najděte výsledný HTML report v results.htmlDocker obrázek se všemi utilitami
Jako třetí alternativu jsem vytvořil dva jednoduché Dockerfile pro vytvoření obrazu s bezpečnostními utilitami. Jeden Dockerfile pomůže sestavit balíček pro skenování obrazu z repozitáře, druhý (Dockerfile_tar) – sestavit balíček pro skenování tar souboru s obrazem.
1. Vezměte odpovídající Docker soubor a skripty z repozitáře .
2. Spusťte jeho sestavení:
docker build -t dscan:image -f docker_security.df .
3. Po dokončení sestavení vytvořte kontejner z obrazu. Předáte proměnnou prostředí DOCKERIMAGE s názvem nás zajímajícího obrazu a namontujete Dockerfile, který chcete analyzovat, z našeho stroje na soubor. /Dockerfile (všimněte si, že je vyžadována absolutní cesta k tomuto souboru):
docker run --rm -v $(pwd)\/results:\/results -v $(pwd)\/docker_security.df:\/Dockerfile -e DOCKERIMAGE="bkimminich\/juice-shop" dscan:image
[+] Nastavení proměnných prostředí
[+] Spuštění Hadolintu
\/Dockerfile:3 DL3006 Vždy explicitně označte verzi obrazu
[+] Spuštění Dockle
VAROVÁNÍ - DKL-DI-0006: Vyhněte se značce latest
* Vyhněte se značce 'latest'
INFO - CIS-DI-0005: Aktivujte důvěru obsahu pro Docker
* export DOCKER_CONTENT_TRUST=1 před docker pull\/build
INFO - CIS-DI-0006: Přidejte instrukci HEALTHCHECK do kontejnerového obrazu
* nebyla nalezena instrukce HEALTHCHECK
INFO - DKL-LI-0003: Vložte pouze nezbytné soubory
* zbytečný soubor: juice-shop\/node_modules\/sqlite3\/Dockerfile
* zbytečný soubor: juice-shop\/node_modules\/sqlite3\/tools\/docker\/architecture\/linux-arm64\/Dockerfile
* zbytečný soubor: juice-shop\/node_modules\/sqlite3\/tools\/docker\/architecture\/linux-arm\/Dockerfile
[+] Spuštění Trivy
...
juice-shop\/package-lock.json
============================
Celkem: 20 (NEZNÁMO: 0, NÍZKÉ: 1, STŘEDNÍ: 6, VYSOKÉ: 8, KRITICKÉ: 5)
...
[+] Vytváření pěkného výstupu
[+] Spuštění hlavního modulu ============================================================
[+] Převod JSON výsledků
[+] Zapisování výsledků HTML
[+] Čistý odchod ============================================================
[+] Vše bylo hotovo. Výsledný HTML report naleznete v results.htmlVýsledky
Zvažovali jsme pouze jednu základní sadu utilit pro skenování artefaktů Docker, která, jak se domnívám, efektivně pokrývá značnou část bezpečnostních požadavků obrazů. Existuje ještě velké množství placených a bezplatných nástrojů, které mohou provádět stejné kontroly, vytvářet pěkné zprávy nebo fungovat čistě v konzolovém režimu, pokrývat systémy správy kontejnerů atd. Přehled těchto nástrojů a způsobů jejich integrace se možná objeví později.
Pozitivní stránkou sady nástrojů, které jsou popsány v článku, je to, že všechny jsou postaveny na otevřeném zdrojovém kódu, což vám umožňuje s nimi experimentovat a s dalšími podobnými nástroji, abyste našli to, co nejlépe vyhovuje vašim požadavkům a specifikům infrastruktury. Rozhodně by všechny zranitelnosti, které budou nalezeny, měly být prozkoumány na použitelnost v konkrétních podmínkách, ale to je téma pro budoucí obsáhlý článek.
Doufám, že tento návod, skripty a nástroje vám pomohou a stanou se výchozím bodem pro vytvoření bezpečnější infrastruktury v oblasti containerizace.
Zdroj: habr.com
