Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker

Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker
Hola Habr!

En la realitat moderna, a causa del paper creixent de la contenidorització en els processos de desenvolupament, la qüestió de garantir la seguretat de les diferents etapes i entitats associades als contenidors no és la qüestió menys important. Fer comprovacions manuals requereix molt de temps, per la qual cosa seria una bona idea fer almenys els passos inicials per automatitzar aquest procés.

En aquest article, compartiré scripts ja preparats per implementar diverses utilitats de seguretat de Docker i instruccions sobre com desplegar un petit suport de demostració per provar aquest procés. Podeu utilitzar els materials per experimentar amb com organitzar el procés de prova de seguretat de les imatges i instruccions de Dockerfile. Està clar que la infraestructura de desenvolupament i implementació de cadascú és diferent, així que a continuació proporcionaré diverses opcions possibles.

Utilitats de control de seguretat

Hi ha un gran nombre d'aplicacions d'ajuda i scripts diferents que realitzen comprovacions en diversos aspectes de la infraestructura de Docker. Alguns d'ells ja s'han descrit a l'article anterior (https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security), i en aquest material m'agradaria centrar-me en tres d'ells, que cobreixen la major part dels requisits de seguretat per a les imatges de Docker construïdes durant el procés de desenvolupament. A més, també mostraré un exemple de com es poden connectar aquestes tres utilitats en una canonada per dur a terme comprovacions de seguretat.

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

Una utilitat de consola força senzilla que ajuda, com a primera aproximació, a avaluar la correcció i la seguretat de les instruccions de Dockerfile (per exemple, utilitzant només registres d'imatges autoritzats o utilitzant sudo).

Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker

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

Una utilitat de consola que funciona amb una imatge (o amb un arxiu tar desat d'una imatge), que comprova la correcció i la seguretat d'una imatge concreta com a tal, analitzant les seves capes i configuració: quins usuaris es creen, quines instruccions s'utilitzen, quines es munten volums, la presència d'una contrasenya buida, etc. d. Fins ara el nombre de comprovacions no és molt gran i es basa en diverses comprovacions i recomanacions nostres. Benchmark del CIS (Centre for Internet Security). per a Docker.
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker

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

Aquesta utilitat té com a objectiu trobar dos tipus de vulnerabilitats: problemes amb les compilacions del sistema operatiu (admesos per Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu) i problemes amb dependències (Gemfile.lock, Pipfile.lock, composer.lock, package). -lock.json , yarn.lock, cargo.lock). Trivy pot escanejar tant una imatge al dipòsit com una imatge local, i també pot escanejar en funció del fitxer .tar transferit amb la imatge de Docker.

Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker

Opcions per implementar utilitats

Per tal de provar les aplicacions descrites en un entorn aïllat, proporcionaré instruccions per instal·lar totes les utilitats en un procés una mica simplificat.

La idea principal és demostrar com podeu implementar la verificació automàtica del contingut dels fitxers Docker i les imatges de Docker que es creen durant el desenvolupament.

La comprovació en si consta dels passos següents:

  1. Comprovació de la correcció i seguretat de les instruccions de Dockerfile mitjançant una utilitat linter Hadolint
  2. Comprovació de la correcció i seguretat de les imatges finals i intermèdies mitjançant una utilitat Dockle
  3. Comprovació de la presència de vulnerabilitats conegudes públicament (CVE) a la imatge base i una sèrie de dependències, utilitzant la utilitat Trivy

Més endavant en l'article donaré tres opcions per implementar aquests passos:
El primer és configurant la canalització CI/CD utilitzant GitLab com a exemple (amb una descripció del procés de generació d'una instància de prova).
El segon és utilitzar un script de shell.
El tercer consisteix a crear una imatge de Docker per escanejar imatges de Docker.
Pots triar l'opció que més et convingui, traslladar-la a la teva infraestructura i adaptar-la a les teves necessitats.

Tots els fitxers necessaris i les instruccions addicionals també es troben al repositori: https://github.com/Swordfish-Security/docker_cicd

Integració a GitLab CI/CD

A la primera opció, veurem com podeu implementar comprovacions de seguretat utilitzant el sistema de dipòsit GitLab com a exemple. Aquí seguirem els passos i descobrirem com instal·lar un entorn de prova amb GitLab des de zero, crear un procés d'escaneig i llançar utilitats per comprovar el Dockerfile de prova i una imatge aleatòria: l'aplicació JuiceShop.

Instal·lant GitLab
1. Instal·leu Docker:

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

2. Afegiu l'usuari actual al grup docker perquè pugueu treballar amb docker sense utilitzar sudo:

sudo addgroup <username> docker

3. Trobeu la vostra IP:

ip addr

4. Instal·leu i inicieu GitLab al contenidor, substituint l'adreça IP del nom d'amfitrió per la vostra:

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

Esperem fins que GitLab completi tots els procediments d'instal·lació necessaris (podeu controlar el procés mitjançant la sortida del fitxer de registre: docker logs -f gitlab).

5. Obriu la vostra IP local al navegador i vegeu una pàgina que us demana que canvieu la contrasenya de l'usuari root:
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker
Establiu una contrasenya nova i aneu a GitLab.

6. Creeu un projecte nou, per exemple cicd-test i inicialitzeu-lo amb el fitxer d'inici LLEGIUME.md:
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker
7. Ara hem d'instal·lar GitLab Runner: un agent que executarà totes les operacions necessàries a petició.
Baixeu la darrera versió (en aquest cas, per a Linux de 64 bits):

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

8. Feu que sigui executable:

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

9. Afegiu un usuari del sistema operatiu per a Runner i inicieu el servei:

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

Hauria de semblar una cosa així:

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. Ara registrem el Runner perquè pugui interactuar amb la nostra instància de GitLab.
Per fer-ho, obriu la pàgina Configuració-CI/CD (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) i a la pestanya Corredors, cerqueu l'URL i el testimoni de registre:
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker
11. Registreu Runner substituint l'URL i el testimoni de registre:

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"

Com a resultat, obtenim un GitLab de treball ja fet, al qual hem d'afegir instruccions per iniciar les nostres utilitats. En aquesta demostració no tenim els passos per construir l'aplicació i contenidoritzar-la, però en un entorn real aquests precederien els passos d'escaneig i generarien imatges i un Dockerfile per a l'anàlisi.

configuració de la canonada

1. Afegiu fitxers al dipòsit mydockerfile.df (aquest és un Dockerfile de prova que comprovarem) i el fitxer de configuració del procés CI/CD de GitLab .gitlab-cicd.yml, que inclou instruccions per als escàners (tingueu en compte el punt al nom del fitxer).

El fitxer de configuració YAML conté instruccions per executar tres utilitats (Hadolint, Dockle i Trivy) que analitzaran el Dockerfile seleccionat i la imatge especificada a la variable DOCKERFILE. Tots els fitxers necessaris es poden extreure del repositori: https://github.com/Swordfish-Security/docker_cicd/

Extracte de mydockerfile.df (aquest és un fitxer abstracte amb un conjunt d'instruccions arbitràries només per demostrar el funcionament de la utilitat). Enllaç directe al fitxer: mydockerfile.df

Contingut de 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

La configuració YAML té aquest aspecte (el fitxer es pot trobar a través de l'enllaç directe aquí: .gitlab-ci.yml):

Contingut de .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

Si cal, també podeu escanejar imatges desades en forma d'arxiu .tar (no obstant això, haureu de canviar els paràmetres d'entrada de les utilitats al fitxer YAML)

NB: Trivy requereix instal·lació rpm и git. En cas contrari, generarà errors en escanejar imatges basades en RedHat i rebre actualitzacions a la base de dades de vulnerabilitats.

2. Després d'afegir fitxers al repositori, d'acord amb les instruccions del nostre fitxer de configuració, GitLab iniciarà automàticament el procés de compilació i exploració. A la pestanya CI/CD → Pipelines podeu veure el progrés de les instruccions.

Com a resultat, tenim quatre tasques. Tres d'ells s'ocupen directament de l'escaneig, i l'últim (Informe) recull un informe senzill a partir de fitxers dispersos amb els resultats de l'escaneig.
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker
De manera predeterminada, Trivy deixa d'executar-se si es detecten vulnerabilitats CRÍTICS a la imatge o dependències. Al mateix temps, Hadolint sempre retorna un codi d'èxit perquè sempre dóna lloc a comentaris, cosa que fa que la compilació s'aturi.

En funció dels vostres requisits específics, podeu configurar un codi de sortida de manera que quan aquestes utilitats detectin problemes d'una certa criticitat, també aturin el procés de creació. En el nostre cas, la compilació només s'aturarà si Trivy detecta una vulnerabilitat amb la criticitat que hem especificat a la variable SHOWSTOPPER a .gitlab-ci.yml.
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker

El resultat de cada utilitat es pot veure al registre de cada tasca d'escaneig, directament als fitxers json de la secció d'artefactes o en un informe HTML senzill (més informació a continuació):
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker

3. Per presentar els informes d'utilitat en una forma una mica més llegible pels humans, s'utilitza un petit script Python per convertir tres fitxers JSON en un fitxer HTML amb una taula de defectes.
Aquest script es llança mitjançant una tasca d'informe independent i el seu artefacte final és un fitxer HTML amb un informe. La font de l'script també es troba al repositori i es pot adaptar a les vostres necessitats, colors, etc.
Mètodes i exemples d'implementació de les utilitats de control de seguretat de Docker

Guió de Shell

La segona opció és adequada per als casos en què necessiteu comprovar les imatges de Docker fora del sistema CI/CD o necessiteu tenir totes les instruccions en un formulari que es pugui executar directament a l'amfitrió. Aquesta opció està coberta per un script de shell ja fet que es pot executar en una màquina virtual (o fins i tot real) neta. L'script executa les mateixes instruccions que el gitlab-runner descrit anteriorment.

Perquè l'script s'executi correctament, Docker ha d'estar instal·lat al sistema i l'usuari actual ha d'estar al grup docker.

El guió en si es pot trobar aquí: docker_sec_check.sh

Al principi del fitxer, les variables especifiquen quina imatge s'ha d'escanejar i quins defectes de criticitat faran que la utilitat Trivy surti amb el codi d'error especificat.

Durant l'execució de l'script, totes les utilitats es baixaran al directori docker_tools, els resultats del seu treball es troben al directori docker_tools/json, i l'HTML amb l'informe estarà al fitxer resultats.html.

Sortida d'script d'exemple

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

Imatge Docker amb totes les utilitats

Com a tercera alternativa, vaig compilar dos Dockerfiles senzills per crear una imatge amb utilitats de seguretat. Un Dockerfile ajudarà a crear un conjunt per escanejar una imatge des d'un dipòsit, el segon (Dockerfile_tar) ajudarà a crear un conjunt per escanejar un fitxer tar amb una imatge.

1. Agafeu el fitxer Docker i els scripts corresponents del dipòsit https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile.
2. El posem en marxa per al muntatge:

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

3. Un cop finalitzat el muntatge, creem un contenidor a partir de la imatge. Al mateix temps, passem la variable d'entorn DOCKERIMAGE amb el nom de la imatge que ens interessa i muntem el Dockerfile que volem analitzar des de la nostra màquina al fitxer. /Dockerfile (tingueu en compte que la ruta absoluta d'aquest fitxer és necessària):

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

Troballes

Només vam analitzar un conjunt bàsic d'utilitats per escanejar artefactes de Docker, que, al meu entendre, cobreix de manera molt efectiva una part decent dels requisits de seguretat de la imatge. També hi ha un gran nombre d'eines de pagament i gratuïtes que poden realitzar les mateixes comprovacions, dibuixar informes bonics o treballar exclusivament en mode consola, cobrir sistemes de gestió de contenidors, etc. Una visió general d'aquestes eines i com integrar-les pot aparèixer una mica més endavant. .

El millor del conjunt d'eines descrites en aquest article és que totes són de codi obert i podeu experimentar amb elles i altres eines similars per trobar la que s'adapti a les vostres necessitats i infraestructura. Per descomptat, totes les vulnerabilitats que es troben s'han d'estudiar per aplicar-les en condicions específiques, però aquest és un tema per a un futur gran article.

Espero que aquesta guia, scripts i utilitats us ajudin i esdevinguin un punt de partida per crear una infraestructura més segura en l'àmbit de la contenerització.

Font: www.habr.com

Afegeix comentari