Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker

Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker
Oi, Habr!

Na realidade atual, devido ao crescente papel da conteinerização nos processos de desenvolvimento, a questão de garantir a segurança das diversas etapas e entidades associadas aos containers não está em último lugar. Realizar verificações manualmente é uma tarefa trabalhosa, por isso seria bom dar pelo menos os passos iniciais para automatizar esse processo.

Neste artigo, compartilharei scripts prontos para implementar vários utilitários de segurança do Docker e instruções sobre como configurar um pequeno estande de demonstração para testar esse processo. Você pode usar os materiais para experimentar como organizar o processo de teste de segurança das imagens e instruções do Dockerfile. É claro que a infraestrutura de desenvolvimento e implementação é diferente para cada pessoa, então abaixo darei várias opções possíveis.

Utilitários de verificação de segurança

Há um grande número de diferentes aplicativos auxiliares e scripts que executam verificações em vários aspectos da infraestrutura do Docker. Algumas delas já foram descritas em artigo anterior (https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security), e neste artigo gostaria de focar em três deles, que cobrem a parte principal dos requisitos de segurança para imagens do Docker construídas durante o processo de desenvolvimento. Além disso, também mostrarei um exemplo de como esses três utilitários podem ser combinados em um pipeline para realizar verificações de segurança.

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

Um utilitário de console bastante simples que ajuda a avaliar primeiro a exatidão e a segurança das instruções do Dockerfile (por exemplo, usando apenas registros de imagem permitidos ou usando sudo).

Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker

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

Um utilitário de console que funciona em uma imagem (ou em um tarball de imagem salva) que verifica a correção e a segurança de uma imagem específica analisando suas camadas e configuração - quais usuários são criados, quais instruções estão em uso, quais volumes são montados , a presença de uma senha em branco, etc. e. Embora o número de verificações não seja muito grande e seja baseado em várias verificações e recomendações próprias Referência CIS (Centro de Segurança na Internet) para docker.
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker

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

Esta ferramenta tem como objetivo encontrar dois tipos de vulnerabilidades: problemas de compilação do sistema operacional (Alpine e RedHat (EL) são suportados), CentOS, Debian gnu, Ubuntu) e problemas de dependência (Gemfile.lock, Pipfile.lock, composer.lock, package-lock.json, yarn.lock, Cargo.lock). O Trivy pode analisar tanto a imagem do repositório quanto a imagem local, além de realizar análises com base no arquivo .tar fornecido que contém a imagem do Docker.

Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker

Opções de Implementação de Utilitários

Para experimentar os aplicativos descritos em condições isoladas, fornecerei instruções para instalar todos os utilitários como parte de um processo simplificado.

A ideia principal é demonstrar como você pode implementar a verificação automática de conteúdo para Dockerfiles e imagens Docker que são criadas durante o desenvolvimento.

A verificação em si consiste nas seguintes etapas:

  1. Verificando a exatidão e a segurança das instruções do Dockerfile com um utilitário linter Hadolint
  2. Verificando a exatidão e segurança das imagens finais e intermediárias - um utilitário Docker
  3. Verificação de Vulnerabilidades Comumente Conhecidas (CVE) na imagem base e várias dependências - pelo utilitário Trivial

Mais adiante no artigo, darei três opções para implementar essas etapas:
A primeira é configurando o pipeline CI/CD usando o exemplo do GitLab (com a descrição do processo de levantamento de uma instância de teste).
A segunda é usar um script de shell.
A terceira é com a construção de uma imagem do Docker para escanear imagens do Docker.
Você pode escolher a opção que mais lhe convém, transferi-la para sua infraestrutura e adaptá-la às suas necessidades.

Todos os arquivos necessários e instruções adicionais também estão no repositório: https://github.com/Swordfish-Security/docker_cicd

Integração de CI/CD do GitLab

Na primeira opção, veremos como as verificações de segurança podem ser implementadas usando o sistema de repositório GitLab como exemplo. Aqui vamos percorrer as etapas e ver como configurar um ambiente de teste com o GitLab do zero, criar um processo de digitalização e executar utilitários para testar um Dockerfile de teste e uma imagem aleatória - o aplicativo JuiceShop.

Instalando o GitLab
1. Instale o Docker:

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

2. Adicione o usuário atual ao grupo docker para que você possa trabalhar com o docker sem usar o sudo:

sudo addgroup <username> docker

3. Encontre seu IP:

ip addr

4. Instale e execute o GitLab no contêiner, substituindo o endereço IP no nome do host pelo seu:

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 aguardando o GitLab concluir todos os procedimentos de instalação necessários (você pode acompanhar o processo através da saída do arquivo de log: docker logs -f gitlab).

5. Abra seu IP local no navegador e veja uma página oferecendo para alterar a senha do usuário root:
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker
Defina uma nova senha e vá para o GitLab.

6. Crie um novo projeto, por exemplo, teste cícd e inicialize-o com um arquivo inicial README.md:
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker
7. Agora precisamos instalar o GitLab Runner: um agente que executará todas as operações necessárias sob solicitação.
Baixe a versão mais recente (neste caso, em Linux 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. Torne-o executável:

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

9. Adicione um usuário do SO para o Runner e inicie o serviço:

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

Deve ser algo assim:

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 registramos o Runner para que ele possa interagir com nossa instância do GitLab.
Para fazer isso, abra a página Settings-CI/CD (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) e localize a URL e o token de registro na guia Runners:
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker
11. Registre o Runner substituindo a URL e o token de registro:

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 um GitLab de trabalho pronto, no qual precisamos adicionar instruções para iniciar nossos utilitários. Nesta demonstração, não temos as etapas de criação e conteinerização do aplicativo, mas em um ambiente real elas precederão as etapas de verificação e gerarão imagens e um Dockerfile para análise.

configuração de pipeline

1. Adicione arquivos ao repositório meudockerfile.df (este é um Dockerfile de teste que iremos testar) e o arquivo de configuração do processo GitLab CI/CD .gitlab-ciccd.yml, que lista instruções para scanners (observe o ponto no nome do arquivo).

O arquivo de configuração .yaml contém instruções para executar três utilitários (Hadolint, Dockle e Trivy) que analisarão o Dockerfile selecionado e a imagem especificada na variável DOCKERFILE. Todos os arquivos necessários podem ser retirados do repositório: https://github.com/Swordfish-Security/docker_cicd/

Trecho de meudockerfile.df (este é um arquivo abstrato com um conjunto de instruções arbitrárias apenas para demonstrar como o utilitário funciona). Link direto para o arquivo: meudockerfile.df

Conteúdo 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 <rhys@arkins.net>"
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 configuração YAML se parece com isso (o arquivo em si pode ser obtido no link direto aqui: .gitlab-ci.yml):

Conteúdo 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 necessário, você também pode digitalizar imagens salvas como um arquivo .tar (no entanto, você precisará alterar os parâmetros de entrada para os utilitários no arquivo YAML)

NB: Trivy requer instalado rpm и git. Caso contrário, ele irá gerar erros ao escanear imagens baseadas em RedHat e obter atualizações para o banco de dados de vulnerabilidades.

2. Depois de adicionar os arquivos ao repositório, de acordo com as instruções em nosso arquivo de configuração, o GitLab iniciará automaticamente o processo de compilação e verificação. Na aba CI/CD → Pipelines, você pode ver o andamento das instruções.

Como resultado, temos quatro tarefas. Três deles estão diretamente envolvidos na verificação e o último (Relatório) coleta um relatório simples de arquivos dispersos com os resultados da verificação.
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker
Por padrão, o Trivy interrompe sua execução se vulnerabilidades CRÍTICAS forem encontradas na imagem ou nas dependências. Ao mesmo tempo, Hadolint sempre retorna Success no código de execução, pois sua execução sempre possui comentários, o que faz com que o build pare.

Dependendo de seus requisitos específicos, você pode configurar um código de saída para que esses utilitários também interrompam o processo de compilação quando forem detectados problemas de certa criticidade. No nosso caso, a compilação será interrompida apenas se Trivy detectar uma vulnerabilidade com uma gravidade que especificamos na variável SHOWSTOPPER em .gitlab-ci.yml.
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker

O resultado da operação de cada utilitário pode ser visualizado no log de cada tarefa de verificação, diretamente em arquivos json na seção de artefatos ou em um simples relatório HTML (mais sobre isso abaixo):
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker

3. Para apresentar relatórios utilitários em um formato um pouco mais legível por humanos, um pequeno script Python é usado para converter três arquivos json em um arquivo HTML com uma tabela de defeitos.
Esse script é iniciado por uma tarefa de relatório separada e seu artefato final é um arquivo HTML com um relatório. A fonte do script também está no repositório e pode ser adaptada às suas necessidades, cores, etc.
Métodos e exemplos de implementação de utilitários de verificação de segurança do Docker

Shell script

A segunda opção é adequada para casos em que você precisa verificar as imagens do Docker fora do sistema CI/CD ou precisa ter todas as instruções em um formulário que pode ser executado diretamente no host. Essa opção é coberta por um script de shell pronto que pode ser executado em uma máquina virtual (ou mesmo real) limpa. O script segue as mesmas instruções do gitlab-runner acima.

Para que o script funcione com sucesso, o Docker deve estar instalado no sistema e o usuário atual deve estar no grupo docker.

O script em si pode ser encontrado aqui: docker_sec_check.sh

No início do arquivo, as variáveis ​​especificam qual imagem deve ser digitalizada e qual a gravidade dos defeitos fará com que o utilitário Trivy saia com o código de erro especificado.

Durante a execução do script, todos os utilitários serão baixados para o diretório docker_tools, os resultados de seu trabalho - no diretório docker_tools/json, e o HTML com o relatório estará no arquivo 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

Imagem do Docker com todos os utilitários

Como terceira alternativa, compilei dois Dockerfiles simples para criar uma imagem com utilitários de segurança. Um Dockerfile ajudará a criar um conjunto para verificar a imagem do repositório, o segundo (Dockerfile_tar) criará um conjunto para verificar o arquivo tar com a imagem.

1. Pegamos o arquivo Docker apropriado e os scripts do repositório https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile.
2. Execute-o para montagem:

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

3. Após a conclusão da compilação, crie um contêiner a partir da imagem. Ao mesmo tempo, passamos a variável de ambiente DOCKERIMAGE com o nome da imagem que nos interessa e montamos o Dockerfile que queremos analisar de nossa máquina para o arquivo /Dockerfile (observe que é necessário um caminho absoluto para este arquivo):

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

Descobertas

Cobrimos apenas um conjunto básico de utilitários de varredura de artefatos do Docker, que eu acho que abrange uma boa parte dos requisitos de segurança de imagem de forma bastante eficaz. Existem muitas outras ferramentas pagas e gratuitas que podem realizar as mesmas verificações, desenhar belos relatórios ou trabalhar puramente no modo de console, abranger sistemas de gerenciamento de contêineres, etc. Uma visão geral dessas ferramentas e como integrá-las pode aparecer um pouco mais tarde.

O lado positivo do conjunto de ferramentas descrito no artigo é que todas elas são construídas em código aberto e você pode experimentá-las e outras ferramentas semelhantes para descobrir o que se adapta exatamente aos seus requisitos e recursos de infraestrutura. É claro que todas as vulnerabilidades encontradas devem ser estudadas para aplicabilidade em condições específicas, mas este é um tópico para um futuro grande artigo.

Espero que essas instruções, scripts e utilitários o ajudem e se tornem um ponto de partida para criar uma infraestrutura mais segura no campo da conteinerização.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção DDoS, servidores VPS VDS 🔥 Compre hospedagem de sites confiável com proteção contra DDoS, servidores VPS/VDS | ProHoster