Metode și exemple de implementare a utilitarelor de verificare a securității Docker

Metode și exemple de implementare a utilitarelor de verificare a securității Docker
Hei Habr!

În realitatea de astăzi, din cauza rolului tot mai mare al containerizării în procesele de dezvoltare, problema asigurării securității diverselor etape și entități asociate containerelor nu se află pe ultimul loc. Efectuarea manuală a verificărilor este o sarcină laborioasă, așa că ar fi bine să faceți cel puțin pașii inițiali pentru automatizarea acestui proces.

În acest articol, voi împărtăși scripturi gata făcute pentru implementarea mai multor utilitare de securitate Docker și instrucțiuni despre cum să configurați un mic stand demonstrativ pentru a testa acest proces. Puteți folosi materialele pentru a experimenta cum să organizați procesul de testare a securității imaginilor și instrucțiunilor Dockerfile. Este clar că infrastructura de dezvoltare și implementare este diferită pentru fiecare, așa că mai jos voi da mai multe opțiuni posibile.

Utilitare de verificare a securității

Există un număr mare de aplicații și scripturi de ajutor diferite care efectuează verificări asupra diferitelor aspecte ale infrastructurii Docker. Unele dintre ele au fost deja descrise într-un articol anterior (https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security), iar în acest articol aș dori să mă concentrez pe trei dintre ele, care acoperă cea mai mare parte a cerințelor de securitate pentru imaginile Docker care sunt construite în timpul procesului de dezvoltare. În plus, voi arăta și un exemplu despre cum aceste trei utilități pot fi combinate într-o singură conductă pentru a efectua verificări de securitate.

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

Un utilitar de consolă destul de simplu, care ajută la evaluarea mai întâi a corectitudinii și siguranței instrucțiunilor Dockerfile (de exemplu, folosind numai registre de imagini permise sau folosind sudo).

Metode și exemple de implementare a utilitarelor de verificare a securității Docker

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

Un utilitar de consolă care funcționează pe o imagine (sau pe un tarball de imagine salvat) care verifică corectitudinea și securitatea unei anumite imagini ca atare analizând straturile și configurația acesteia - ce utilizatori sunt creați, ce instrucțiuni sunt în uz, ce volume sunt montate , prezența unei parole goale etc. e. În timp ce numărul de verificări nu este foarte mare și se bazează pe mai multe verificări și recomandări proprii Benchmark CIS (Center for Internet Security). pentru docker.
Metode și exemple de implementare a utilitarelor de verificare a securității Docker

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

Acest utilitar are ca scop găsirea a două tipuri de vulnerabilități - probleme de construcție a sistemului de operare (Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu sunt acceptate) și probleme de dependență (Gemfile.lock, Pipfile.lock, composer.lock, package-lock). .json , yarn.lock, Cargo.lock). Trivy poate scana atât imaginea din depozit, cât și imaginea locală și, de asemenea, poate scana pe baza fișierului .tar transferat cu imaginea Docker.

Metode și exemple de implementare a utilitarelor de verificare a securității Docker

Opțiuni de implementare a utilităților

Pentru a încerca aplicațiile descrise în condiții izolate, voi oferi instrucțiuni pentru instalarea tuturor utilităților ca parte a unui proces simplificat.

Ideea principală este de a demonstra cum puteți implementa verificarea automată a conținutului pentru fișierele Docker și imaginile Docker care sunt create în timpul dezvoltării.

Verificarea în sine constă în următorii pași:

  1. Verificarea corectitudinii și siguranței instrucțiunilor Dockerfile cu un utilitar linter Hadolint
  2. Verificarea corectitudinii și securității imaginilor finale și intermediare - un utilitar Dockle
  3. Verificarea vulnerabilităților comune cunoscute (CVE) în imaginea de bază și a unui număr de dependențe - de către utilitar Trivy

Mai târziu în articol voi oferi trei opțiuni pentru implementarea acestor pași:
Primul este prin configurarea conductei CI/CD folosind exemplul GitLab (cu o descriere a procesului de ridicare a unei instanțe de testare).
Al doilea este folosirea unui script shell.
Al treilea este construirea unei imagini Docker pentru a scana imagini Docker.
Puteți alege opțiunea care vi se potrivește cel mai bine, să o transferați în infrastructura dvs. și să o adaptați nevoilor dumneavoastră.

Toate fișierele necesare și instrucțiunile suplimentare sunt, de asemenea, în depozit: https://github.com/Swordfish-Security/docker_cicd

Integrare GitLab CI/CD

În prima opțiune, ne vom uita la modul în care verificările de securitate pot fi implementate folosind sistemul de depozitare GitLab ca exemplu. Aici vom parcurge pașii și vom vedea cum să configurați un mediu de testare cu GitLab de la zero, să creăm un proces de scanare și să rulăm utilitare pentru a testa un Dockerfile de testare și o imagine aleatorie - aplicația JuiceShop.

Instalarea GitLab
1. Instalați Docker:

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

2. Adăugați utilizatorul curent la grupul docker, astfel încât să puteți lucra cu docker fără a utiliza sudo:

sudo addgroup <username> docker

3. Găsiți IP-ul dvs.:

ip addr

4. Instalați și rulați GitLab în container, înlocuind adresa IP din numele gazdei cu propria dvs.:

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

Așteptăm ca GitLab să finalizeze toate procedurile de instalare necesare (puteți urmări procesul prin ieșirea fișierului jurnal: docker logs -f gitlab).

5. Deschideți IP-ul local în browser și vedeți o pagină care oferă schimbarea parolei utilizatorului root:
Metode și exemple de implementare a utilitarelor de verificare a securității Docker
Setați o nouă parolă și accesați GitLab.

6. Creați un nou proiect, de exemplu cicd-test și inițializați-l cu un fișier de pornire README.md:
Metode și exemple de implementare a utilitarelor de verificare a securității Docker
7. Acum trebuie să instalăm GitLab Runner: un agent care va rula toate operațiunile necesare la cerere.
Descărcați cea mai recentă versiune (în acest caz, sub Linux pe 64 de biți):

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

8. Faceți-l executabil:

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

9. Adăugați un utilizator de sistem de operare pentru Runner și porniți serviciul:

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

Ar trebui să arate cam așa:

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. Acum înregistrăm Runner-ul astfel încât să poată interacționa cu instanța noastră GitLab.
Pentru a face acest lucru, deschideți pagina Setări-CI/CD (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) și în fila Runners găsiți adresa URL și jetonul de înregistrare:
Metode și exemple de implementare a utilitarelor de verificare a securității Docker
11. Înregistrați alergătorul înlocuind adresa URL și simbolul de înregistrare:

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"

Ca rezultat, obținem un GitLab funcțional gata făcut, în care trebuie să adăugăm instrucțiuni pentru a ne porni utilitățile. În această demonstrație, nu avem pași de construire a aplicației și de containerizare, dar într-un mediu real, aceștia vor precede pașii de scanare și vor genera imagini și un fișier Docker pentru analiză.

configurația conductei

1. Adăugați fișiere în depozit mydockerfile.df (acesta este un fișier Dockerfile de testare pe care îl vom testa) și fișierul de configurare a procesului GitLab CI/CD .gitlab-cicd.yml, care listează instrucțiuni pentru scanere (rețineți punctul din numele fișierului).

Fișierul de configurare .yaml conține instrucțiuni pentru rularea a trei utilitare (Hadolint, Dockle și Trivy) care vor analiza fișierul Dockerfile selectat și imaginea specificată în variabila DOCKERFILE. Toate fișierele necesare pot fi preluate din depozit: https://github.com/Swordfish-Security/docker_cicd/

Extrage din mydockerfile.df (acesta este un fișier abstract cu un set de instrucțiuni arbitrare doar pentru a demonstra cum funcționează utilitarul). Link direct la fisier: mydockerfile.df

Conținutul 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 <[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

Configurația YAML arată astfel (fișierul în sine poate fi preluat din linkul direct de aici: .gitlab-ci.yml):

Conținutul .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

Dacă este necesar, puteți scana și imaginile salvate ca arhivă .tar (cu toate acestea, va trebui să modificați parametrii de intrare pentru utilitarele din fișierul YAML)

NB: Trivy necesită instalarea rpm и merge. În caz contrar, va genera erori la scanarea imaginilor bazate pe RedHat și la obținerea de actualizări ale bazei de date de vulnerabilități.

2. După adăugarea fișierelor în depozit, conform instrucțiunilor din fișierul nostru de configurare, GitLab va porni automat procesul de construire și scanare. Pe fila CI / CD → Pipelines, puteți vedea progresul instrucțiunilor.

Drept urmare, avem patru sarcini. Trei dintre ei sunt direct implicați în scanare, iar ultimul (Raport) colectează un raport simplu din fișiere împrăștiate cu rezultatele scanării.
Metode și exemple de implementare a utilitarelor de verificare a securității Docker
În mod implicit, Trivy își oprește execuția dacă se găsesc vulnerabilități CRITICE în imagine sau dependențe. În același timp, Hadolint returnează întotdeauna un cod de succes, deoarece execuția acestuia are întotdeauna observații, ceea ce duce la o oprire a construirii.

În funcție de cerințele dvs. specifice, puteți configura un cod de ieșire, astfel încât aceste utilitare să oprească și procesul de construire atunci când sunt detectate probleme cu o anumită criticitate. În cazul nostru, build-ul se va opri numai dacă Trivy detectează o vulnerabilitate cu o gravitate pe care am specificat-o în variabila SHOWSTOPPER în .gitlab-ci.yml.
Metode și exemple de implementare a utilitarelor de verificare a securității Docker

Rezultatul funcționării fiecărui utilitar poate fi vizualizat în jurnalul fiecărei sarcini de scanare, direct în fișierele json din secțiunea artefacte sau într-un simplu raport HTML (mai multe despre asta mai jos):
Metode și exemple de implementare a utilitarelor de verificare a securității Docker

3. Pentru a prezenta rapoartele de utilitate într-o formă puțin mai citită de om, se folosește un mic script Python pentru a converti trei fișiere json într-un fișier HTML cu un tabel de defecte.
Acest script este lansat de o sarcină separată Raport, iar artefactul său final este un fișier HTML cu un raport. Sursa de script este, de asemenea, în depozit și poate fi adaptată nevoilor, culorilor, etc.
Metode și exemple de implementare a utilitarelor de verificare a securității Docker

Script Shell

A doua opțiune este potrivită pentru cazurile în care trebuie să verificați imaginile Docker care nu sunt în sistemul CI/CD sau trebuie să aveți toate instrucțiunile într-o formă care poate fi executată direct pe gazdă. Această opțiune este acoperită de un script shell gata făcut, care poate fi rulat pe o mașină virtuală curată (sau chiar reală). Scriptul urmează aceleași instrucțiuni ca și gitlab-runner de mai sus.

Pentru ca scriptul să funcționeze cu succes, Docker trebuie să fie instalat pe sistem, iar utilizatorul curent trebuie să fie în grupul docker.

Scriptul în sine poate fi găsit aici: docker_sec_check.sh

La începutul fișierului, variabilele specifică ce imagine trebuie scanată și ce severitate a defectelor va determina închiderea utilitarului Trivy cu codul de eroare specificat.

În timpul execuției scriptului, toate utilitățile vor fi descărcate în director docker_tools, rezultatele muncii lor - în director docker_tools/json, iar codul HTML cu raportul va fi în fișier rezultate.html.

Exemplu de ieșire de script

~/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

Imagine Docker cu toate utilitățile

Ca a treia alternativă, am compilat două Dockerfile simple pentru a crea o imagine cu utilități de securitate. Un Dockerfile va ajuta la construirea unui set pentru a scana imaginea din depozit, al doilea (Dockerfile_tar) va construi un set pentru a scana fișierul tar cu imaginea.

1. Luăm fișierul Docker și scripturile corespunzătoare din depozit https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile.
2. Rulați-l pentru asamblare:

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

3. După ce construirea este completă, creați un container din imagine. În același timp, trecem variabila de mediu DOCKERIMAGE cu numele imaginii care ne interesează și montăm fișierul Dockerfile pe care dorim să-l analizăm de pe mașina noastră în fișier /Dockerfile (rețineți că este necesară o cale absolută către acest fișier):

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

Constatări

Am acoperit doar un set de bază de instrumente de scanare a artefactelor Docker, care cred că acoperă destul de eficient o cantitate suficientă de cerințe de securitate a imaginii. Există multe alte instrumente plătite și gratuite care pot efectua aceleași verificări, pot crea rapoarte frumoase sau pot lucra exclusiv în modul consolă, pot acoperi sistemele de gestionare a containerelor etc. O prezentare generală a acestor instrumente și a modului de integrare a acestora poate apărea puțin mai târziu.

Partea pozitivă a setului de instrumente descrise în articol este că toate sunt construite pe sursă deschisă și puteți experimenta cu ele și alte instrumente similare pentru a găsi ceea ce se potrivește exact cerințelor și caracteristicilor dvs. de infrastructură. Desigur, toate vulnerabilitățile care se găsesc ar trebui studiate pentru aplicabilitate în condiții specifice, dar acesta este un subiect pentru un viitor articol mare.

Sper că aceste instrucțiuni, scripturi și utilități vă vor ajuta și să devină un punct de plecare pentru crearea unei infrastructuri mai sigure în domeniul containerizării.

Sursa: www.habr.com

Adauga un comentariu