Szia Habr!
A modern valóságban a konténerezés fejlesztési folyamatokban betöltött szerepének növekedése miatt nem a legkevésbé fontos kérdés a konténerekhez kapcsolódó különböző szakaszok és entitások biztonságának biztosítása. A kézi ellenőrzések végrehajtása időigényes, ezért célszerű legalább a kezdeti lépéseket megtenni a folyamat automatizálása felé.
Ebben a cikkben kész szkripteket osztok meg számos Docker biztonsági segédprogram megvalósításához, valamint útmutatást adok egy kis bemutatóállvány telepítéséhez a folyamat tesztelésére. Az anyagok segítségével kísérletezhet azzal, hogyan szervezheti meg a Dockerfile-képek és utasítások biztonságának tesztelésének folyamatát. Nyilvánvaló, hogy mindenkinek más a fejlesztési és megvalósítási infrastruktúrája, ezért az alábbiakban több lehetséges lehetőséget ismertetek.
Biztonsági ellenőrzési segédprogramok
Számos különféle segédalkalmazás és szkript létezik, amelyek a Docker-infrastruktúra különféle aspektusait ellenőrzik. Néhányat már leírtunk az előző cikkben (
Hadolint
Egy meglehetősen egyszerű konzol-segédprogram, amely első közelítésként segít kiértékelni a Dockerfile utasításainak helyességét és biztonságosságát (például csak engedélyezett képregisztrációk vagy sudo használata esetén).
Dockle
Egy képpel (vagy egy kép mentett tararchívumával) működő konzol-segédprogram, amely ellenőrzi egy adott kép helyességét és biztonságát, elemezve annak rétegeit és konfigurációját – mely felhasználók jönnek létre, milyen utasításokat használnak, kötetek fel vannak szerelve, üres jelszó stb. d. Eddig az ellenőrzések száma nem túl nagy, és számos saját ellenőrzésünkön és ajánlásunkon alapul
Apróság
Ez a segédprogram kétféle sérülékenység felkutatását célozza: az operációs rendszer buildjeivel kapcsolatos problémákat (az Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu támogatja) és a függőségekkel kapcsolatos problémákat (Gemfile.lock, Pipfile.lock, composer.lock, csomag) -lock.json, yarn.lock, cargo.lock). A Trivy képes beolvasni a tárolóban lévő képet és a helyi képet is, és az átvitt .tar fájl alapján is képes a Docker-képpel.
A segédprogramok megvalósításának lehetőségei
Annak érdekében, hogy a leírt alkalmazásokat izolált környezetben próbálhassuk ki, egy kissé leegyszerűsített folyamatban adok utasításokat az összes segédprogram telepítéséhez.
A fő ötlet annak bemutatása, hogyan valósíthatja meg a fejlesztés során létrehozott Dockerfiles és Docker képek automatikus tartalomellenőrzését.
Maga az ellenőrzés a következő lépésekből áll:
- A Dockerfile utasítások helyességének és biztonságosságának ellenőrzése egy linter segédprogram segítségével Hadolint
- A végső és köztes képek helyességének és biztonságosságának ellenőrzése segédprogram segítségével Dockle
- Nyilvánosan ismert sebezhetőségek (CVE) meglétének ellenőrzése az alapképben és számos függőség – a segédprogram segítségével Apróság
A cikk későbbi részében három lehetőséget adok a lépések végrehajtására:
Az első a CI/CD folyamat konfigurálása a GitLab példájával (a tesztpéldány létrehozásának folyamatának leírásával).
A második egy shell script használata.
A harmadik egy Docker-kép létrehozása a Docker-képek beolvasásához.
Kiválaszthatja az Önnek legmegfelelőbb lehetőséget, átviheti infrastruktúrájába, és az igényeihez igazíthatja.
Az összes szükséges fájl és további utasítások szintén a tárolóban találhatók:
Integráció GitLab CI/CD-be
Az első lehetőségnél azt nézzük meg, hogyan lehet végrehajtani a biztonsági ellenőrzéseket a GitLab tárolórendszer példaként való felhasználásával. Itt végigmegyünk a lépéseken, és kitaláljuk, hogyan telepítsünk tesztkörnyezetet a GitLab segítségével a semmiből, hozzunk létre egy szkennelési folyamatot, és indítsunk el segédprogramokat a teszt Dockerfile és egy véletlenszerű kép ellenőrzéséhez - a JuiceShop alkalmazás.
A GitLab telepítése
1. Telepítse a Dockert:
sudo apt-get update && sudo apt-get install docker.io
2. Adja hozzá az aktuális felhasználót a docker csoporthoz, hogy a dockerrel a sudo használata nélkül dolgozhasson:
sudo addgroup <username> docker
3. Keresse meg IP-címét:
ip addr
4. Telepítse és indítsa el a GitLabot a tárolóban, cserélje le a gazdagépnévben szereplő IP-címet a sajátjára:
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
Megvárjuk, amíg a GitLab elvégzi az összes szükséges telepítési eljárást (a folyamatot a naplófájl kimenetén keresztül figyelheti meg: docker logs -f gitlab).
5. Nyissa meg helyi IP-címét a böngészőben, és jelenjen meg egy oldal, amely a root felhasználó jelszavának megváltoztatását kéri:
Állítson be új jelszót, és lépjen a GitLab oldalára.
6. Hozzon létre egy új projektet, például cicd-test, és inicializálja a kezdőfájllal README.md:
7. Most telepítenünk kell a GitLab Runner-t: egy ügynököt, amely kérésre minden szükséges műveletet lefuttat.
Töltse le a legújabb verziót (ebben az esetben 64 bites Linuxhoz):
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
8. Tegye végrehajthatóvá:
sudo chmod +x /usr/local/bin/gitlab-runner
9. Adjon hozzá egy operációs rendszer-felhasználót a Runnerhez, és indítsa el a szolgáltatást:
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 start
Valahogy így kell kinéznie:
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. Most regisztráljuk a Runnert, hogy interakcióba lépjen a GitLab példányunkkal.
Ehhez nyissa meg a Settings-CI/CD oldalt (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd), és a Runners lapon keresse meg az URL-t és a regisztrációs tokent:
11. Regisztráljon futót az URL és a regisztrációs token helyettesítésével:
sudo gitlab-runner register
--non-interactive
--url "http://<URL>/"
--registration-token "<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"
Ennek eredményeként egy kész működő GitLabot kapunk, amelybe utasításokat kell hozzáadnunk a segédprogramok elindításához. Ebben a bemutatóban nincsenek lépéseink az alkalmazás felépítéséhez és konténerbe helyezéséhez, de valós környezetben ezek megelőzik a szkennelési lépéseket, és képeket és egy Docker-fájlt generálnak elemzésre.
csővezeték konfiguráció
1. Adjon hozzá fájlokat a tárhoz mydockerfile.df (ez egy teszt Docker-fájl, amelyet ellenőrizni fogunk) és a GitLab CI/CD folyamat konfigurációs fájlja .gitlab-cicd.yml, amely a lapolvasókra vonatkozó utasításokat tartalmazza (figyelje meg a pontot a fájl nevében).
A YAML konfigurációs fájl utasításokat tartalmaz három segédprogram (Hadolint, Dockle és Trivy) futtatására, amelyek elemzik a kiválasztott Dockerfile-t és a DOCKERFILE változóban megadott képet. Minden szükséges fájl letölthető a tárolóból:
Kivonat a mydockerfile.df (ez egy absztrakt fájl tetszőleges utasításokkal, csak a segédprogram működésének bemutatására). Közvetlen link a fájlhoz:
A mydockerfile.df tartalma
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 <[email protected]>"
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 root
A YAML konfigurációja így néz ki (maga a fájl az alábbi közvetlen hivatkozáson keresztül érhető el:
A .gitlab-ci.yml tartalma
variables:
DOCKER_HOST: "tcp://docker:2375/"
DOCKERFILE: "mydockerfile.df" # name of the Dockerfile to analyse
DOCKERIMAGE: "bkimminich/juice-shop" # name of the Docker image to analyse
# DOCKERIMAGE: "knqyf263/cve-2018-11235" # test Docker image with several CRITICAL CVE
SHOWSTOPPER_PRIORITY: "CRITICAL" # what level of criticality will fail Trivy job
TRIVYCACHE: "$CI_PROJECT_DIR/.cache" # where to cache Trivy database of vulnerabilities for faster reuse
ARTIFACT_FOLDER: "$CI_PROJECT_DIR"
services:
- docker:dind # to be able to build docker images inside the Runner
stages:
- scan
- report
- publish
HadoLint:
# Basic lint analysis of Dockerfile instructions
stage: scan
image: docker:git
after_script:
- cat $ARTIFACT_FOLDER/hadolint_results.json
script:
- 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 will always exit with 0 exit code
- ./hadolint-Linux-x86_64 -f json $DOCKERFILE > $ARTIFACT_FOLDER/hadolint_results.json || exit 0
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/hadolint_results.json
Dockle:
# Analysing best practices about docker image (users permissions, instructions followed when image was built, etc.)
stage: scan
image: docker:git
after_script:
- cat $ARTIFACT_FOLDER/dockle_results.json
script:
- 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
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/dockle_results.json
Trivy:
# Analysing docker image and package dependencies against several CVE bases
stage: scan
image: docker:git
script:
# getting the latest 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
# displaying all vulnerabilities w/o failing the build
- ./trivy -d --cache-dir $TRIVYCACHE -f json -o $ARTIFACT_FOLDER/trivy_results.json --exit-code 0 $DOCKERIMAGE
# write vulnerabilities info to stdout in human readable format (reading pure json is not fun, eh?). You can remove this if you don't need this.
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 0 $DOCKERIMAGE
# failing the build if the SHOWSTOPPER priority is found
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 1 --severity $SHOWSTOPPER_PRIORITY --quiet $DOCKERIMAGE
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/trivy_results.json
cache:
paths:
- .cache
Report:
# combining tools outputs into one HTML
stage: report
when: always
image: python:3.5
script:
- 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
artifacts:
paths:
- results.html
Szükség esetén a mentett képeket .tar archívum formájában is beszkennelheti (azonban a YAML fájlban módosítania kell a segédprogramok bemeneti paramétereit)
Megjegyzés: A Trivy telepítése szükséges fordulat и csoportos it. Ellenkező esetben hibákat generál a RedHat-alapú képek vizsgálatakor és a sebezhetőségi adatbázis frissítéseinek fogadásakor.
2. Miután hozzáadta a fájlokat a tárolóhoz, a konfigurációs fájlunk utasításai szerint, a GitLab automatikusan elindítja az összeállítási és vizsgálati folyamatot. A CI/CD → Csővezetékek lapon láthatja az utasítások folyamatát.
Ennek eredményeként négy feladatunk van. Közülük három közvetlenül a szkenneléssel foglalkozik, az utolsó pedig (Jelentés) egy egyszerű jelentést gyűjt szétszórt fájlokból a vizsgálati eredményekkel.
Alapértelmezés szerint a Trivy leáll, ha KRITIKUS sérülékenységet észlel a képben vagy a függőségekben. Ugyanakkor a Hadolint mindig sikerkódot ad vissza, mert az mindig megjegyzéseket eredményez, ami miatt a build leáll.
A speciális követelményektől függően beállíthat egy kilépési kódot, hogy amikor ezek a segédprogramok bizonyos kritikus problémákat észlelnek, leállítsák a felépítési folyamatot is. Esetünkben a build csak akkor áll le, ha a Trivy olyan kritikusságú sebezhetőséget észlel, amelyet a SHOWSTOPPER változóban adtunk meg .gitlab-ci.yml.
Az egyes segédprogramok eredménye megtekinthető az egyes szkennelési feladatok naplójában, közvetlenül a json-fájlokban a műtermékek részben, vagy egy egyszerű HTML jelentésben (erről lentebb olvashat bővebben):
3. A segédprogram-jelentések ember által is olvashatóbb formában történő megjelenítéséhez egy kis Python-szkriptet használnak, amely három JSON-fájlt egyetlen HTML-fájllá alakít át a hibákat tartalmazó táblázattal.
Ezt a szkriptet egy külön Jelentés feladat indítja el, a végső mellékterméke pedig egy jelentést tartalmazó HTML-fájl. A szkript forrása szintén a tárolóban található, és az igényeinek, színeinek stb.
Shell szkript
A második lehetőség azokra az esetekre alkalmas, amikor a Docker-képeket a CI/CD-rendszeren kívül kell ellenőriznie, vagy az összes utasítást olyan formában kell megadnia, amely közvetlenül a gazdagépen végrehajtható. Ezt az opciót egy kész shell script fedi le, amely tiszta virtuális (vagy akár valós) gépen is futtatható. A szkript ugyanazokat az utasításokat hajtja végre, mint a fent leírt gitlab-runner.
A szkript sikeres futtatásához a Dockert telepíteni kell a rendszerre, és az aktuális felhasználónak a docker csoportban kell lennie.
Maga a szkript itt található:
A fájl elején változók határozzák meg, hogy melyik képet kell vizsgálni, és mely kritikussági hibák miatt a Trivy segédprogram a megadott hibakóddal lép ki.
A szkript végrehajtása során az összes segédprogram letöltődik a könyvtárba docker_tools, munkájuk eredménye a címtárban található docker_tools/json, és a jelentést tartalmazó HTML a fájlban lesz results.html.
Példa script kimenetre
~/docker_cicd$ ./docker_sec_check.sh
[+] Setting environment variables
[+] Installing required packages
[+] Preparing necessary directories
[+] Fetching sample Dockerfile
2020-10-20 10:40:00 (45.3 MB/s) - ‘Dockerfile’ saved [8071/8071]
[+] Pulling image to scan
latest: Pulling from bkimminich/juice-shop
[+] Running Hadolint
...
Dockerfile:205 DL3015 Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:248 DL3002 Last USER should not be root
...
[+] Running Dockle
...
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
...
[+] Running Trivy
juice-shop/frontend/package-lock.json
=====================================
Total: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 2, CRITICAL: 0)
+---------------------+------------------+----------+---------+-------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | VERSION | TITLE |
+---------------------+------------------+----------+---------+-------------------------+
| object-path | CVE-2020-15256 | HIGH | 0.11.4 | Prototype pollution in |
| | | | | object-path |
+---------------------+------------------+ +---------+-------------------------+
| tree-kill | CVE-2019-15599 | | 1.2.2 | Code Injection |
+---------------------+------------------+----------+---------+-------------------------+
| webpack-subresource | CVE-2020-15262 | LOW | 1.4.1 | Unprotected dynamically |
| | | | | loaded chunks |
+---------------------+------------------+----------+---------+-------------------------+
juice-shop/package-lock.json
============================
Total: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
juice-shop/package-lock.json
============================
Total: 5 (CRITICAL: 5)
...
[+] Removing left-overs
[+] Making the output look pretty
[+] Converting JSON results
[+] Writing results HTML
[+] Clean exit ============================================================
[+] Everything is done. Find the resulting HTML report in results.html
Docker kép minden segédprogrammal
Harmadik alternatívaként összeállítottam két egyszerű Docker-fájlt, hogy létrehozzak egy képet biztonsági segédprogramokkal. Az egyik Dockerfile segít összeállítani egy készletet egy kép lerakatból történő beolvasásához, a második (Dockerfile_tar) pedig egy tar-fájl képpel történő szkenneléséhez.
1. Vegye ki a megfelelő Docker-fájlt és a szkripteket a tárolóból
2. Elindítjuk összeszerelésre:
docker build -t dscan:image -f docker_security.df .
3. Az összeállítás befejezése után a képből tárolót készítünk. Ezzel egyidejűleg átadjuk a minket érdeklő kép nevével a DOCKERIMAGE környezeti változót, és csatoljuk az elemezni kívánt Dockerfile-t a gépünkről a fájlba. /Dockerfile (vegye figyelembe, hogy a fájl abszolút elérési útja kötelező):
docker run --rm -v $(pwd)/results:/results -v $(pwd)/docker_security.df:/Dockerfile -e DOCKERIMAGE="bkimminich/juice-shop" dscan:image
[+] Setting environment variables
[+] Running Hadolint
/Dockerfile:3 DL3006 Always tag the version of an image explicitly
[+] Running Dockle
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
INFO - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
* not found HEALTHCHECK statement
INFO - DKL-LI-0003: Only put necessary files
* unnecessary file : juice-shop/node_modules/sqlite3/Dockerfile
* unnecessary file : juice-shop/node_modules/sqlite3/tools/docker/architecture/linux-arm64/Dockerfile
* unnecessary file : juice-shop/node_modules/sqlite3/tools/docker/architecture/linux-arm/Dockerfile
[+] Running Trivy
...
juice-shop/package-lock.json
============================
Total: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
[+] Making the output look pretty
[+] Starting the main module ============================================================
[+] Converting JSON results
[+] Writing results HTML
[+] Clean exit ============================================================
[+] Everything is done. Find the resulting HTML report in results.html
Álláspontja
Csak egy alapvető segédprogramot vizsgáltunk a Docker műtermékek beolvasásához, amely véleményem szerint nagyon hatékonyan lefedi a képbiztonsági követelmények megfelelő részét. Számos fizetős és ingyenes eszköz is létezik, amelyek ugyanazokat az ellenőrzéseket hajthatják végre, gyönyörű jelentéseket készíthetnek, vagy pusztán konzol módban dolgozhatnak, lefedhetik a konténerkezelő rendszereket stb. Ezekről az eszközökről és integrálásukról egy kicsit később olvashat. .
Az ebben a cikkben ismertetett eszközkészletben az a jó, hogy mindegyik nyílt forráskódú, és kísérletezhet velük és más hasonló eszközökkel, hogy megtalálja az igényeinek és infrastruktúrájának megfelelőt. Természetesen minden talált sebezhetőséget meg kell vizsgálni, hogy konkrét körülmények között alkalmazhatók-e, de ez egy jövőbeli nagy cikk témája.
Remélem, hogy ez az útmutató, a szkriptek és segédprogramok segítenek Önnek, és kiindulóponttá válnak egy biztonságosabb infrastruktúra létrehozásához a konténerezés területén.
Forrás: will.com