Metoder och exempel på implementering av Docker säkerhetskontrollverktyg

Metoder och exempel på implementering av Docker säkerhetskontrollverktyg
Hej Habr!

I den moderna verkligheten, på grund av containeriseringens växande roll i utvecklingsprocesser, är frågan om att säkerställa säkerheten för olika stadier och enheter förknippade med containrar inte den minst viktiga frågan. Att utföra manuella kontroller är tidskrävande, så det skulle vara en bra idé att åtminstone ta de första stegen för att automatisera denna process.

I den här artikeln kommer jag att dela färdiga skript för att implementera flera Docker-säkerhetsverktyg och instruktioner om hur man distribuerar ett litet demoställ för att testa denna process. Du kan använda materialet för att experimentera med hur du organiserar processen för att testa säkerheten för Dockerfile-bilder och instruktioner. Det är tydligt att allas utvecklings- och implementeringsinfrastruktur är olika, så nedan kommer jag att ge flera möjliga alternativ.

Verktyg för säkerhetskontroll

Det finns ett stort antal olika hjälpprogram och skript som utför kontroller av olika aspekter av Docker-infrastrukturen. Några av dem har redan beskrivits i föregående artikel (https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security), och i det här materialet skulle jag vilja fokusera på tre av dem, som täcker huvuddelen av säkerhetskraven för Docker-bilder byggda under utvecklingsprocessen. Dessutom kommer jag också att visa ett exempel på hur dessa tre verktyg kan kopplas till en pipeline för att utföra säkerhetskontroller.

Hadolint
https://github.com/hadolint/hadolint

Ett ganska enkelt konsolverktyg som hjälper, som en första uppskattning, att utvärdera riktigheten och säkerheten hos Dockerfile-instruktioner (till exempel genom att endast använda auktoriserade bildregister eller använda sudo).

Metoder och exempel på implementering av Docker säkerhetskontrollverktyg

Dockle
https://github.com/goodwithtech/dockle

Ett konsolverktyg som fungerar med en bild (eller med ett sparat tar-arkiv av en bild), som kontrollerar riktigheten och säkerheten för en viss bild som sådan, analyserar dess lager och konfiguration - vilka användare som skapas, vilka instruktioner som används, vilka volymer är monterade, förekomsten av ett tomt lösenord etc. d. Hittills är antalet kontroller inte särskilt stort och bygger på flera av våra egna kontroller och rekommendationer CIS (Center for Internet Security) Benchmark för Docker.
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg

Trivy
https://github.com/aquasecurity/trivy

Det här verktyget syftar till att hitta två typer av sårbarheter - problem med OS-byggen (stöds av Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu) och problem med beroenden (Gemfile.lock, Pipfile.lock, composer.lock, paket -lock.json , garn.lås, last.lås). Trivy kan skanna både en bild i arkivet och en lokal bild, och kan även skanna baserat på den överförda .tar-filen med Docker-bilden.

Metoder och exempel på implementering av Docker säkerhetskontrollverktyg

Alternativ för att implementera verktyg

För att prova de beskrivna applikationerna i en isolerad miljö kommer jag att ge instruktioner för att installera alla verktyg i en något förenklad process.

Huvudidén är att demonstrera hur du kan implementera automatisk innehållsverifiering av Dockerfiler och Docker-bilder som skapas under utveckling.

Själva kontrollen består av följande steg:

  1. Kontrollera korrektheten och säkerheten för Dockerfile-instruktionerna med hjälp av ett linter-verktyg Hadolint
  2. Kontrollera korrektheten och säkerheten för de slutliga och mellanliggande bilderna med hjälp av ett verktyg Dockle
  3. Kontrollera om det finns offentligt kända sårbarheter (CVE) i basbilden och ett antal beroenden - med hjälp av verktyget Trivy

Senare i artikeln kommer jag att ge tre alternativ för att implementera dessa steg:
Den första är genom att konfigurera CI/CD-pipelinen med GitLab som exempel (med en beskrivning av processen för att ta upp en testinstans).
Den andra använder ett skalskript.
Den tredje handlar om att bygga en Docker-bild för att skanna Docker-bilder.
Du kan välja det alternativ som passar dig bäst, överföra det till din infrastruktur och anpassa det efter dina behov.

Alla nödvändiga filer och ytterligare instruktioner finns också i förvaret: https://github.com/Swordfish-Security/docker_cicd

Integration i GitLab CI/CD

I det första alternativet kommer vi att titta på hur du kan implementera säkerhetskontroller med hjälp av GitLabs förvarssystem som exempel. Här kommer vi att gå igenom stegen och ta reda på hur man installerar en testmiljö med GitLab från början, skapar en skanningsprocess och startar verktyg för att kontrollera test Dockerfile och en slumpmässig bild - JuiceShop-applikationen.

Installerar GitLab
1. Installera Docker:

sudo apt-get update && sudo apt-get install docker.io

2. Lägg till den aktuella användaren i dockergruppen så att du kan arbeta med docker utan att använda sudo:

sudo addgroup <username> docker

3. Hitta din IP:

ip addr

4. Installera och starta GitLab i behållaren, ersätt IP-adressen i värdnamnet med din egen:

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

Vi väntar tills GitLab har slutfört alla nödvändiga installationsprocedurer (du kan övervaka processen genom loggfilens utdata: docker logs -f gitlab).

5. Öppna din lokala IP i webbläsaren och se en sida som ber dig ändra lösenordet för root-användaren:
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg
Sätt ett nytt lösenord och gå till GitLab.

6. Skapa ett nytt projekt, till exempel cicd-test och initiera det med startfilen README.md:
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg
7. Nu måste vi installera GitLab Runner: en agent som kör alla nödvändiga operationer på begäran.
Ladda ner den senaste versionen (i det här fallet för Linux 64-bit):

sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

8. Gör det körbart:

sudo chmod +x /usr/local/bin/gitlab-runner

9. Lägg till en OS-användare för Runner och starta tjänsten:

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

Det borde se ut ungefär så här:

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. Nu registrerar vi löparen så att den kan interagera med vår GitLab-instans.
För att göra detta, öppna sidan Inställningar-CI/CD (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) och på fliken Löpare hittar du URL:en och registreringstoken:
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg
11. Registrera Runner genom att ersätta URL:en och registreringstoken:

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"

Som ett resultat får vi ett färdigt fungerande GitLab, i vilket vi måste lägga till instruktioner för att starta våra verktyg. I den här demon har vi inte stegen för att bygga applikationen och behålla den, men i en verklig miljö skulle dessa föregå skanningsstegen och generera bilder och en Dockerfil för analys.

rörledningskonfiguration

1. Lägg till filer i arkivet mydockerfile.df (detta är en test Dockerfil som vi kommer att kontrollera) och GitLab CI/CD-processkonfigurationsfilen .gitlab-cicd.yml, som listar instruktioner för skannrar (notera punkten i filnamnet).

YAML-konfigurationsfilen innehåller instruktioner för att köra tre verktyg (Hadolint, Dockle och Trivy) som kommer att analysera den valda Dockerfilen och bilden som anges i DOCKERFILE-variabeln. Alla nödvändiga filer kan hämtas från förvaret: https://github.com/Swordfish-Security/docker_cicd/

Extrahera från mydockerfile.df (detta är en abstrakt fil med en uppsättning godtyckliga instruktioner endast för att demonstrera funktionen av verktyget). Direktlänk till filen: mydockerfile.df

Innehållet i mydockerple.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 <[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

Konfigurationen YAML ser ut så här (filen i sig kan hittas via direktlänken här: .gitlab-ci.yml):

Innehållet i .gitlab-ci.yml

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

Vid behov kan du även skanna sparade bilder i form av ett .tar-arkiv (du måste dock ändra inmatningsparametrarna för verktygen i YAML-filen)

OBS: Trivy kräver installerad rpm и . Annars kommer det att generera fel när RedHat-baserade bilder skannas och uppdateringar till sårbarhetsdatabasen tas emot.

2. Efter att ha lagt till filer till förvaret, enligt instruktionerna i vår konfigurationsfil, kommer GitLab automatiskt att börja bygga och skanna. På fliken CI/CD → Pipelines kan du se instruktionernas förlopp.

Som ett resultat har vi fyra uppgifter. Tre av dem handlar direkt om skanning, och den sista (Rapport) samlar in en enkel rapport från spridda filer med skanningsresultat.
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg
Som standard slutar Trivy att köras om KRITISKA sårbarheter upptäcks i bilden eller beroenden. Samtidigt returnerar Hadolint alltid en framgångskod eftersom den alltid resulterar i kommentarer, vilket gör att bygget stoppas.

Beroende på dina specifika krav kan du konfigurera en utgångskod så att när dessa verktyg upptäcker problem av en viss kriticitet, stoppar de också byggprocessen. I vårt fall kommer konstruktionen att stoppas endast om Trivy upptäcker en sårbarhet med den kritikalitet som vi angav i SHOWSTOPPER-variabeln i .gitlab-ci.yml.
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg

Resultatet av varje verktyg kan ses i loggen för varje skanningsuppgift, direkt i json-filerna i artefaktersektionen eller i en enkel HTML-rapport (mer om det nedan):
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg

3. För att presentera verktygsrapporter i en något mer läsbar form används ett litet Python-skript för att konvertera tre JSON-filer till en HTML-fil med en tabell över defekter.
Det här skriptet startas av en separat rapportuppgift, och dess sista artefakt är en HTML-fil med en rapport. Skriptkällan finns också i arkivet och kan anpassas för att passa dina behov, färger etc.
Metoder och exempel på implementering av Docker säkerhetskontrollverktyg

Skalskript

Det andra alternativet är lämpligt för fall när du behöver kontrollera Docker-bilder utanför CI/CD-systemet eller du behöver ha alla instruktioner i ett formulär som kan köras direkt på värden. Det här alternativet täcks av ett färdigt skalskript som kan köras på en ren virtuell (eller till och med riktig) maskin. Skriptet kör samma instruktioner som gitlab-runnern som beskrivs ovan.

För att skriptet ska köras måste Docker vara installerat på systemet och den aktuella användaren måste vara i dockergruppen.

Själva skriptet hittar du här: docker_sec_check.sh

I början av filen anger variabler vilken bild som behöver skannas och vilka kritiska defekter som gör att Trivy-verktyget avslutas med den angivna felkoden.

Under skriptkörning kommer alla verktyg att laddas ner till katalogen docker_tools, resultaten av deras arbete finns i katalogen docker_tools/json, och HTML-koden med rapporten kommer att finnas i filen results.html.

Exempel på skriptutdata

~/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-bild med alla verktyg

Som ett tredje alternativ kompilerade jag två enkla Dockerfiler för att skapa en bild med säkerhetsverktyg. En Dockerfile hjälper till att bygga en uppsättning för att skanna en bild från ett arkiv, den andra (Dockerfile_tar) hjälper till att bygga en uppsättning för att skanna en tar-fil med en bild.

1. Ta motsvarande Docker-fil och skript från förvaret https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile.
2. Vi lanserar den för montering:

docker build -t dscan:image -f docker_security.df .

3. Efter att monteringen är klar skapar vi en behållare från bilden. Samtidigt skickar vi DOCKERIMAGE miljövariabeln med namnet på bilden vi är intresserade av och monterar Dockerfilen som vi vill analysera från vår maskin till filen /Dockerfil (observera att den absoluta sökvägen till denna fil krävs):

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

Resultat

Vi tittade på endast en grundläggande uppsättning verktyg för att skanna Docker-artefakter, som, enligt min mening, mycket effektivt täcker en anständig del av bildsäkerhetskraven. Det finns också ett stort antal betalda och gratis verktyg som kan utföra samma kontroller, rita vackra rapporter eller arbeta rent i konsolläge, täcka containerhanteringssystem etc. En översikt över dessa verktyg och hur man integrerar dem kan dyka upp lite senare .

Det som är bra med uppsättningen verktyg som beskrivs i den här artikeln är att de alla är öppen källkod och du kan experimentera med dem och andra liknande verktyg för att hitta det som passar dina behov och infrastruktur. Naturligtvis bör alla sårbarheter som hittas studeras för tillämpbarhet i specifika förhållanden, men detta är ett ämne för en framtida stor artikel.

Jag hoppas att denna guide, skript och verktyg kommer att hjälpa dig och bli en startpunkt för att skapa en säkrare infrastruktur inom containeriseringsområdet.

Källa: will.com

Lägg en kommentar