Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker

Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker
Ola Habr!

Na realidade actual, debido ao crecente papel da contenerización nos procesos de desenvolvemento, a cuestión de garantir a seguridade das distintas etapas e entidades asociadas aos contedores non está no último lugar. Realizar comprobacións manualmente é unha tarefa laboriosa, polo que sería bo dar polo menos os pasos iniciais para automatizar este proceso.

Neste artigo, compartirei scripts preparados para implementar varias utilidades de seguridade de Docker e instrucións sobre como configurar un pequeno soporte de demostración para probar este proceso. Podes usar os materiais para probar como organizar o proceso de proba da seguridade das imaxes e instrucións de Dockerfile. Está claro que a infraestrutura de desenvolvemento e implementación é diferente para todos, polo que a continuación vou dar varias opcións posibles.

Utilidades de verificación de seguridade

Hai un gran número de diferentes aplicacións de axuda e scripts que realizan comprobacións en varios aspectos da infraestrutura Docker. Algúns deles xa foron descritos nun artigo anterior (https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security), e neste artigo gustaríame centrarme en tres deles, que cobren a maior parte dos requisitos de seguridade para as imaxes de Docker que se crean durante o proceso de desenvolvemento. Ademais, mostrarei tamén un exemplo de como se poden combinar estas tres utilidades nunha soa canalización para realizar comprobacións de seguridade.

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

Unha utilidade de consola bastante sinxela que axuda, como primeira aproximación, a avaliar a corrección e seguridade das instrucións de Dockerfile (por exemplo, usando só rexistros de imaxes autorizados ou usando sudo).

Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker

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

Unha utilidade de consola que funciona nunha imaxe (ou nun tarball de imaxe gardada) que comproba a corrección e a seguridade dunha imaxe concreta como tal analizando as súas capas e configuración: que usuarios se crean, que instrucións están en uso, que volumes se montan. , a presenza dun contrasinal en branco, etc. e. Aínda que o número de comprobacións non é moi grande e baséase en varias comprobacións e recomendacións propias CIS (Centro de Seguridade en Internet) Benchmark para docker.
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker

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

Esta utilidade ten como obxectivo atopar dous tipos de vulnerabilidades: problemas de compilación do SO (Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu son compatibles) e problemas de dependencia (Gemfile.lock, Pipfile.lock, composer.lock, package-lock). .json , yarn.lock, Cargo.lock). Trivy pode dixitalizar tanto a imaxe no repositorio como a imaxe local, e tamén dixitalizar en función do ficheiro .tar transferido coa imaxe de Docker.

Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker

Opcións de implementación de utilidades

Para probar as aplicacións descritas nun ambiente illado, proporcionarei instrucións para instalar todas as utilidades nun proceso algo simplificado.

A idea principal é demostrar como se pode implementar a comprobación automática de contido para os ficheiros Docker e as imaxes de Docker que se crean durante o desenvolvemento.

A verificación en si consta dos seguintes pasos:

  1. Comprobando a corrección e seguridade das instrucións de Dockerfile cunha utilidade linter Hadolint
  2. Comprobación da corrección e seguridade das imaxes finais e intermedias mediante unha utilidade Dockle
  3. Comprobando vulnerabilidades comúnmente coñecidas (CVE) na imaxe base e unha serie de dependencias - pola utilidade Trivy

Máis adiante no artigo darei tres opcións para implementar estes pasos:
O primeiro é configurando a canalización CI/CD usando o exemplo de GitLab (cunha descrición do proceso de creación dunha instancia de proba).
O segundo é usar un script de shell.
O terceiro é a construción dunha imaxe de Docker para escanear imaxes de Docker.
Podes escoller a opción que máis che conveña, trasladala á túa infraestrutura e adaptala ás túas necesidades.

Todos os ficheiros necesarios e instrucións adicionais tamén se atopan no repositorio: https://github.com/Swordfish-Security/docker_cicd

Integración GitLab CI/CD

Na primeira opción, veremos como se poden implementar as comprobacións de seguridade usando o sistema de repositorio de GitLab como exemplo. Aquí imos seguir os pasos e ver como configurar un ambiente de proba con GitLab desde cero, crear un proceso de dixitalización e executar utilidades para probar un Dockerfile de proba e unha imaxe aleatoria: a aplicación JuiceShop.

Instalando GitLab
1. Instala Docker:

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

2. Engade o usuario actual ao grupo docker para que poidas traballar con docker sen usar sudo:

sudo addgroup <username> docker

3. Busca a túa IP:

ip addr

4. Instale e execute GitLab no contedor, substituíndo o enderezo IP no nome de host polo seu propio:

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

Estamos á espera de que GitLab complete todos os procedementos de instalación necesarios (podes seguir o proceso a través da saída do ficheiro de rexistro: docker logs -f gitlab).

5. Abre a túa IP local no navegador e mira unha páxina que ofrece cambiar o contrasinal para o usuario root:
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker
Establece un novo contrasinal e vai a GitLab.

6. Crea un proxecto novo, por exemplo cicd-test e iníciao cun ficheiro de inicio Léame.md:
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker
7. Agora necesitamos instalar o GitLab Runner: un axente que executará todas as operacións necesarias baixo petición.
Descarga a última versión (neste caso, para 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. Faino executable:

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

9. Engade un usuario do sistema operativo para o Runner e inicia o servizo:

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

Debería parecer algo así:

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. Agora rexistramos o Runner para que poida interactuar coa nosa instancia de GitLab.
Para iso, abra a páxina Configuración-CI/CD (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) e na pestana Corredores busque o URL e o token de rexistro:
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker
11. Rexistra o corredor substituíndo o URL e o token de rexistro:

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"

Como resultado, obtemos un GitLab listo para funcionar, no que necesitamos engadir instrucións para iniciar as nosas utilidades. Nesta demostración, non temos pasos de compilación e contenerización de aplicacións, pero nun ambiente real precederán aos pasos de dixitalización e xerarán imaxes e un ficheiro Docker para a súa análise.

configuración de canalización

1. Engade ficheiros ao repositorio mydockerfile.df (este é un Dockerfile de proba que comprobaremos) e o ficheiro de configuración do proceso CI/CD de GitLab .gitlab-cicd.yml, que enumera instrucións para os escáneres (nótese no punto no nome do ficheiro).

O ficheiro de configuración .yaml contén instrucións para executar tres utilidades (Hadolint, Dockle e Trivy) que analizarán o ficheiro Dockerfile seleccionado e a imaxe especificada na variable DOCKERFILE. Todos os ficheiros necesarios pódense sacar do repositorio: https://github.com/Swordfish-Security/docker_cicd/

Extracto de mydockerfile.df (este é un ficheiro abstracto cun conxunto de instrucións arbitrarias só para demostrar o funcionamento da utilidade). Ligazón directa ao ficheiro: mydockerfile.df

Contido 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

A configuración YAML ten o seguinte aspecto (o ficheiro en si pódese tomar da ligazón directa aquí: .gitlab-ci.yml):

Contido 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

Se é necesario, tamén pode escanear imaxes gardadas como arquivo .tar (non obstante, terá que cambiar os parámetros de entrada para as utilidades no ficheiro YAML)

NB: Trivy require instalación rpm и ir. En caso contrario, xerará erros ao escanear imaxes baseadas en RedHat e obter actualizacións na base de datos de vulnerabilidades.

2. Despois de engadir os ficheiros ao repositorio, segundo as instrucións do noso ficheiro de configuración, GitLab iniciará automaticamente o proceso de compilación e dixitalización. Na pestana CI / CD → Pipelines, podes ver o progreso das instrucións.

Como resultado, temos catro tarefas. Tres deles están directamente implicados na dixitalización, e o último (Informe) recolle un informe sinxelo a partir de ficheiros espallados cos resultados da exploración.
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker
Por defecto, Trivy detén a súa execución se se atopan vulnerabilidades CRÍTICAS na imaxe ou nas dependencias. Ao mesmo tempo, Hadolint sempre devolve Éxito no código de execución, xa que a súa execución sempre ten observacións, o que fai que se deteña a compilación.

Dependendo dos seus requisitos específicos, pode configurar un código de saída para que, cando estas utilidades detecten problemas de certa criticidade, tamén deteñan o proceso de compilación. No noso caso, a compilación deterase só se Trivy detecta unha vulnerabilidade coa criticidade que especificamos na variable SHOWSTOPPER en .gitlab-ci.yml.
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker

O resultado do funcionamento de cada utilidade pódese ver no rexistro de cada tarefa de dixitalización, directamente en ficheiros json na sección de artefactos ou nun simple informe HTML (máis información a continuación):
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker

3. Para presentar informes de utilidade nunha forma lixeiramente máis lexible polos humanos, utilízase un pequeno script Python para converter tres ficheiros JSON nun ficheiro HTML cunha táboa de defectos.
Este script é lanzado por unha tarefa de Informe separada e o seu artefacto final é un ficheiro HTML cun informe. A fonte do script tamén está no repositorio e pódese adaptar ás túas necesidades, cores, etc.
Métodos e exemplos de implementación das utilidades de comprobación de seguridade de Docker

Guión Shell

A segunda opción é axeitada para os casos nos que necesite comprobar as imaxes de Docker que non están dentro do sistema CI/CD, ou precisa ter todas as instrucións nun formulario que se pode executar directamente no servidor. Esta opción está cuberta por un script de shell preparado que se pode executar nunha máquina virtual (ou incluso real) limpa. O script segue as mesmas instrucións que o gitlab-runner anterior.

Para que o script funcione correctamente, Docker debe estar instalado no sistema e o usuario actual debe estar no grupo docker.

O propio guión pódese atopar aquí: docker_sec_check.sh

Ao comezo do ficheiro, as variables especifican que imaxe debe ser dixitalizada e que gravidade dos defectos fará que a utilidade Trivy saia co código de erro especificado.

Durante a execución do script, todas as utilidades descargaranse no directorio docker_tools, os resultados do seu traballo están no directorio docker_tools/json, e o HTML co informe estará no ficheiro resultados.html.

Saída de script de exemplo

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

Imaxe Docker con todas as utilidades

Como terceira alternativa, compilei dous sinxelos Dockerfiles para crear unha imaxe con utilidades de seguridade. Un Dockerfile axudará a crear un conxunto para escanear a imaxe desde o repositorio, o segundo (Dockerfile_tar) creará un conxunto para escanear o ficheiro tar coa imaxe.

1. Tome o ficheiro e os scripts de Docker correspondentes do repositorio https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile.
2. Execútao para a montaxe:

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

3. Despois de completar a compilación, crea un contedor a partir da imaxe. Ao mesmo tempo, pasamos a variable de ambiente DOCKERIMAGE co nome da imaxe que nos interesa e montamos o Dockerfile que queremos analizar dende a nosa máquina ao ficheiro /Dockerfile (ten en conta que é necesaria unha ruta absoluta a este ficheiro):

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

Descubrimentos

Cubrimos só un conxunto básico de utilidades de dixitalización de artefactos de Docker, que creo que cobre unha boa parte dos requisitos de seguridade da imaxe de forma bastante eficaz. Hai moitas outras ferramentas de pago e gratuítas que poden realizar as mesmas comprobacións, elaborar informes bonitos ou traballar puramente en modo consola, cubrir sistemas de xestión de contedores, etc. Pode que un pouco máis tarde apareza unha visión xeral destas ferramentas e de como integralas.

O bo do conxunto de ferramentas descritas no artigo é que están construídas en código aberto e podes probar con elas e outras ferramentas similares para atopar o que se adapte aos teus requisitos e funcións de infraestrutura. Por suposto, todas as vulnerabilidades que se atopen deben ser estudadas para a súa aplicabilidade en condicións específicas, pero este é un tema para un futuro artigo grande.

Espero que estas instrucións, scripts e utilidades che axuden e se convertan nun punto de partida para crear unha infraestrutura máis segura no campo da contenerización.

Fonte: www.habr.com

Engadir un comentario