嘿哈布尔!
在今天的现实中,由于容器化在开发过程中的作用越来越大,确保与容器相关的各个阶段和实体的安全问题并不是最后的问题。 手动执行检查是一项艰巨的任务,因此最好至少采取初始步骤来自动化此过程。
在本文中,我将分享用于实施多个 Docker 安全实用程序的现成脚本,以及有关如何设置小型演示台来测试此过程的说明。 您可以使用这些材料来试验如何组织测试 Dockerfile 图像和指令的安全性的过程。 很明显,每个人的开发和实施基础设施都不同,因此下面我将给出几种可能的选择。
安全检查实用程序
有大量不同的帮助应用程序和脚本可以对 Docker 基础设施的各个方面执行检查。 其中一些已经在之前的文章中描述过(
哈多林特
一个相当简单的控制台实用程序,有助于首先评估 Dockerfile 指令的正确性和安全性(例如,仅使用允许的图像注册表或使用 sudo)。
多克
一个控制台实用程序,用于图像(或保存的图像 tarball),通过分析图像的层和配置来检查特定图像的正确性和安全性 - 创建了哪些用户,正在使用哪些指令,安装了哪些卷,是否存在空白密码等。 e. 虽然检查次数不是很多,但基于自己的检查和建议
特里维
此实用程序旨在发现两种类型的漏洞 - 操作系统构建问题(支持 Alpine、RedHat (EL)、CentOS、Debian GNU、Ubuntu)和依赖项问题(Gemfile.lock、Pipfile.lock、composer.lock、package-lock .json、纱线锁、货物锁)。 Trivy既可以扫描仓库中的镜像,也可以扫描本地镜像,也可以基于传输过来的带有Docker镜像的.tar文件进行扫描。
实用程序实施选项
为了在孤立的条件下试用所描述的应用程序,我将提供安装所有实用程序的说明作为简化过程的一部分。
主要思想是演示如何对开发期间创建的 Dockerfile 和 Docker 映像实施自动内容检查。
验证本身包括以下步骤:
- 使用 linter 实用程序检查 Dockerfile 指令的正确性和安全性 哈多林特
- 检查最终和中间图像的正确性和安全性 - 一个实用程序 多克
- 检查基础映像中的常见漏洞 (CVE) 和一些依赖项 - 通过实用程序 特里维
在本文的后面,我将提供三个选项来实现这些步骤:
第一个是使用 GitLab 的示例配置 CI / CD 管道(并描述了引发测试实例的过程)。
第二种是使用 shell 脚本。
第三个是构建 Docker 镜像以扫描 Docker 镜像。
您可以选择最适合您的选项,将其转移到您的基础架构并使其适应您的需求。
所有必要的文件和附加说明也在存储库中:
GitLab CI/CD 集成
在第一个选项中,我们将以 GitLab 存储库系统为例,了解如何实施安全检查。 在这里,我们将完成这些步骤,看看如何从头开始使用 GitLab 设置测试环境,创建扫描进程并运行实用程序来测试测试 Dockerfile 和随机图像 - JuiceShop 应用程序。
安装 GitLab
1.安装Docker:
sudo apt-get update && sudo apt-get install docker.io
2.将当前用户添加到docker组,这样就可以在不使用sudo的情况下使用docker:
sudo addgroup <username> docker
3.找到你的IP:
ip addr
4.在容器中安装并运行GitLab,将hostname中的IP地址替换成你自己的:
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
我们正在等待 GitLab 完成所有必要的安装程序(您可以通过日志文件的输出来跟踪该过程:docker logs -f gitlab)。
5.在浏览器中打开你的本地IP,看到一个页面提供修改root用户的密码:
设置新密码并转到 GitLab。
6.创建一个新项目,例如cicd-test并用一个启动文件初始化它 README.md:
7. 现在我们需要安装 GitLab Runner:一个将根据请求运行所有必要操作的代理。
下载最新版本(在本例中,在 Linux 64 位下):
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
8. 使其可执行:
sudo chmod +x /usr/local/bin/gitlab-runner
9.为Runner添加OS用户并启动服务:
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
它应该看起来像这样:
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. 现在我们注册 Runner 以便它可以与我们的 GitLab 实例进行交互。
为此,打开 Settings-CI/CD 页面 (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) 并在 Runners 选项卡上找到 URL 和 Registration token:
11. 通过替换 URL 和注册令牌注册 Runner:
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"
结果,我们得到了一个现成的工作 GitLab,我们需要在其中添加指令来启动我们的实用程序。 在此演示中,我们没有应用程序构建和容器化步骤,但在真实环境中,它们将在扫描步骤之前生成图像和 Dockerfile 以供分析。
管道配置
1.将文件添加到存储库 我的docker文件.df (这是我们要测试的测试Dockerfile)和GitLab CI/CD进程配置文件 .gitlab-cicd.yml,其中列出了扫描仪的说明(请注意文件名中的点)。
.yaml 配置文件包含运行三个实用程序(Hadolint、Dockle 和 Trivy)的说明,这些实用程序将解析选定的 Dockerfile 和 DOCKERFILE 变量中指定的图像。 所有必要的文件都可以从存储库中获取:
摘录自 我的docker文件.df (这是一个带有一组任意指令的抽象文件,只是为了演示该实用程序的工作原理)。 文件直接链接:
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
配置 YAML 如下所示(文件本身可以从此处的直接链接获取:
.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
如有必要,您还可以将保存的图像扫描为 .tar 存档(但是,您需要更改 YAML 文件中实用程序的输入参数)
注意:Trivy 需要安装 转 и 混帐. 否则,它会在扫描基于 RedHat 的图像和获取漏洞数据库更新时产生错误。
2. 将文件添加到仓库后,根据我们配置文件中的说明,GitLab 会自动启动构建和扫描过程。 在 CI/CD → Pipelines 选项卡上,可以看到指令的进度。
因此,我们有四个任务。 其中三个直接参与扫描,最后一个(报告)从分散的文件中收集扫描结果的简单报告。
默认情况下,如果在图像或依赖项中发现严重漏洞,Trivy 将停止执行。 同时,Hadolint在执行代码中总是返回Success,因为它的执行总是有备注,导致构建停止。
根据您的具体要求,您可以配置一个退出代码,以便这些实用程序在检测到某个严重程度的问题时也停止构建过程。 在我们的例子中,只有当 Trivy 检测到我们在 SHOWSTOPPER 变量中指定的严重程度的漏洞时,构建才会停止 .gitlab-ci.yml.
每个实用程序的运行结果可以在每个扫描任务的日志中查看,直接在工件部分的 json 文件中查看,或者在简单的 HTML 报告中查看(更多内容见下文):
3. 为了以更易于阅读的形式呈现效用报告,使用一个小的 Python 脚本将三个 json 文件转换为一个包含缺陷表的 HTML 文件。
此脚本由单独的报告任务启动,其最终工件是带有报告的 HTML 文件。 脚本源也在存储库中,可以根据您的需要、颜色等进行调整。
外壳脚本
第二个选项适用于需要检查不在 CI/CD 系统内的 Docker 镜像,或者需要所有指令以一种可以直接在主机上执行的形式的情况。 这个选项包含在一个现成的 shell 脚本中,可以在干净的虚拟(甚至真实)机器上运行。 该脚本遵循与上面的 gitlab-runner 相同的指令。
要使脚本成功运行,必须在系统上安装 Docker,并且当前用户必须在 docker 组中。
脚本本身可以在这里找到:
在文件的开头,变量指定应该扫描哪个图像以及什么严重的缺陷会导致 Trivy 实用程序退出并显示指定的错误代码。
在脚本执行期间,所有实用程序将被下载到该目录 docker_工具, 他们的工作成果 - 在目录中 docker_tools/json,带有报告的 HTML 将在文件中 结果.html.
示例脚本输出
~/docker_cicd$ ./docker_sec_check.sh
[+] Setting environment variables
[+] Installing required packages
[+] Preparing necessary directories
[+] Fetching sample Dockerfile
2020-10-20 10:40:00 (45.3 MB/s) - ‘Dockerfile’ saved [8071/8071]
[+] Pulling image to scan
latest: Pulling from bkimminich/juice-shop
[+] Running Hadolint
...
Dockerfile:205 DL3015 Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:248 DL3002 Last USER should not be root
...
[+] Running Dockle
...
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
...
[+] Running Trivy
juice-shop/frontend/package-lock.json
=====================================
Total: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 2, CRITICAL: 0)
+---------------------+------------------+----------+---------+-------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | VERSION | TITLE |
+---------------------+------------------+----------+---------+-------------------------+
| object-path | CVE-2020-15256 | HIGH | 0.11.4 | Prototype pollution in |
| | | | | object-path |
+---------------------+------------------+ +---------+-------------------------+
| tree-kill | CVE-2019-15599 | | 1.2.2 | Code Injection |
+---------------------+------------------+----------+---------+-------------------------+
| webpack-subresource | CVE-2020-15262 | LOW | 1.4.1 | Unprotected dynamically |
| | | | | loaded chunks |
+---------------------+------------------+----------+---------+-------------------------+
juice-shop/package-lock.json
============================
Total: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
juice-shop/package-lock.json
============================
Total: 5 (CRITICAL: 5)
...
[+] Removing left-overs
[+] Making the output look pretty
[+] Converting JSON results
[+] Writing results HTML
[+] Clean exit ============================================================
[+] Everything is done. Find the resulting HTML report in results.html
包含所有实用程序的 Docker 映像
作为第三种选择,我编译了两个简单的 Dockerfile 来创建带有安全实用程序的映像。 一个 Dockerfile 将帮助构建一个集合来扫描存储库中的图像,第二个 (Dockerfile_tar) 将构建一个集合来扫描带有图像的 tar 文件。
1. 我们从存储库中获取适当的 Docker 文件和脚本
2.运行它进行组装:
docker build -t dscan:image -f docker_security.df .
3. 构建完成后,从镜像中创建一个容器。 同时,我们将我们感兴趣的图像名称传递给 DOCKERIMAGE 环境变量,并将我们要分析的 Dockerfile 从我们的机器挂载到文件中 /码头文件 (请注意,此文件的绝对路径是必需的):
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
结果
我们只介绍了一组基本的 Docker 工件扫描实用程序,我认为它非常有效地涵盖了图像安全要求的很大一部分。 还有许多其他付费和免费工具可以执行相同的检查、绘制漂亮的报告或纯粹在控制台模式下工作、涵盖容器管理系统等。这些工具的概述以及如何集成它们可能稍后会出现。
本文中描述的工具集的积极方面是,它们都是基于开源构建的,您可以对它们和其他类似工具进行试验,以找到完全适合您的要求和基础架构功能的工具。 当然,应该研究所有发现的漏洞在特定条件下的适用性,但这是未来一篇大文章的主题。
我希望这些说明、脚本和实用程序对您有所帮助,并成为在容器化领域创建更安全基础架构的起点。
来源: habr.com