Docker 安全檢查實用程序的實現方法和示例

Docker 安全檢查實用程序的實現方法和示例
嘿哈布爾!

在當今的現實中,由於容器化在開發過程中的作用越來越大,確保與容器相關的各個階段和實體的安全問題並不是最後一個問題。 手動執行檢查是一項艱鉅的任務,因此最好至少採取初步步驟來自動化此過程。

在本文中,我將分享用於實現多個 Docker 安全實用程序的現成腳本,以及有關如何設置小型演示站來測試此過程的說明。 您可以使用這些材料來嘗試如何組織測試 Dockerfile 鏡像和指令的安全性的過程。 顯然,每個人的開發和實施基礎設施都是不同的,所以下面我將給出幾種可能的選擇。

安全檢查實用程序

有大量不同的幫助應用程序和腳本可以對 Docker 基礎設施的各個方面執行檢查。 其中一些已經在之前的文章中描述過(https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security),在本文中,我想重點討論其中三個,它們涵蓋了在開發過程中構建的 Docker 映像的大部分安全要求。 此外,我還將展示一個示例,說明如何將這三個實用程序組合成一個管道來執行安全檢查。

哈多林特
https://github.com/hadolint/hadolint

一個相當簡單的控制台實用程序,有助於首先評估 Dockerfile 指令的正確性和安全性(例如,僅使用允許的映像註冊表或使用 sudo)。

Docker 安全檢查實用程序的實現方法和示例

多克爾
https://github.com/goodwithtech/dockle

一個控制台實用程序,用於處理映像(或保存的映像 tarball),通過分析其層和配置來檢查特定映像的正確性和安全性 - 創建了哪些用戶、正在使用哪些指令、安裝了哪些卷、是否存在空白密碼等e. 雖然檢查次數不是很多並且基於多次自己的檢查和建議 CIS(互聯網安全中心)基準 對於碼頭工人。
Docker 安全檢查實用程序的實現方法和示例

特里維
https://github.com/aquasecurity/trivy

該實用程序旨在查找兩種類型的漏洞- 操作系統構建問題(支持Alpine、RedHat (EL)、CentOS、Debian GNU、Ubuntu)和依賴性問題(Gemfile.lock、Pipfile.lock、composer.lock、package -lock) .json、yarn.lock、Cargo.lock)。 Trivy 可以掃描存儲庫中的鏡像和本地鏡像,還可以根據 Docker 鏡像傳輸的 .tar 文件進行掃描。

Docker 安全檢查實用程序的實現方法和示例

實用程序實施選項

為了在隔離條件下嘗試所描述的應用程序,我將提供安裝所有實用程序的說明,作為簡化過程的一部分。

主要思想是演示如何對開發過程中創建的 Dockerfile 和 Docker 映像實現自動內容檢查。

驗證本身包括以下步驟:

  1. 使用 linter 實用程序檢查 Dockerfile 指令的正確性和安全性 哈多林特
  2. 檢查最終和中間圖像的正確性和安全性 - 實用程序 多克爾
  3. 檢查基礎映像中的常見漏洞 (CVE) 和許多依賴項 - 通過實用程序 特里維

在本文後面,我將提供實現這些步驟的三個選項:
第一個是使用 GitLab 示例配置 CI / CD 管道(帶有引發測試實例的過程的描述)。
第二種是使用 shell 腳本。
第三種是構建 Docker 鏡像來掃描 Docker 鏡像。
您可以選擇最適合您的選項,將其轉移到您的基礎設施並根據您的需求進行調整。

所有必需的文件和附加說明也位於存儲庫中: https://github.com/Swordfish-Security/docker_cicd

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,將主機名中的 IP 地址替換為您自己的 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 log -f gitlab)。

5. 在瀏覽器中打開您的本地 IP,並看到一個提供更改 root 用戶密碼的頁面:
Docker 安全檢查實用程序的實現方法和示例
設置新密碼並轉到 GitLab。

6. 創建一個新項目,例如cicd-test並使用啟動文件對其進行初始化 README.md:
Docker 安全檢查實用程序的實現方法和示例
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 和註冊令牌:
Docker 安全檢查實用程序的實現方法和示例
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. 將文件添加到存儲庫 mydockerfile.df (這是我們將測試的測試 Dockerfile)和 GitLab CI/CD 進程配置文件 .gitlab-cicd.yml,其中列出了掃描儀的說明(注意文件名中的點)。

.yaml 配置文件包含運行三個實用程序(Hadolint、Dockle 和 Trivy)的指令,這些實用程序將解析選定的 Dockerfile 和 DOCKERFILE 變量中指定的映像。 所有必需的文件都可以從存儲庫中獲取: https://github.com/Swordfish-Security/docker_cicd/

摘自 mydockerfile.df (這是一個帶有一組任意指令的抽象文件,只是為了演示該實用程序如何工作)。 直接鏈接到文件: mydockerfile.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):

.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 選項卡上,您可以看到指令的進度。

因此,我們有四項任務。 其中三個直接參與掃描,最後一個(報告)從帶有掃描結果的分散文件中收集一個簡單的報告。
Docker 安全檢查實用程序的實現方法和示例
默認情況下,如果在映像或依賴項中發現嚴重漏洞,Trivy 將停止執行。 同時,Hadolint在執行代碼中總是返回Success,因為它的執行總是有註釋,這會導致構建停止。

根據您的具體要求,您可以配置退出代碼,以便這些實用程序在檢測到特定嚴重性的問題時也停止構建過程。 在我們的例子中,只有當 Trivy 檢測到我們在 SHOWSTOPPER 變量中指定的嚴重性的漏洞時,構建才會停止 .gitlab-ci.yml.
Docker 安全檢查實用程序的實現方法和示例

每個實用程序的操作結果可以在每個掃描任務的日誌中、直接在工件部分的 json 文件中或在簡單的 HTML 報告中查看(更多信息見下文):
Docker 安全檢查實用程序的實現方法和示例

3. 為了以更易於理解的形式呈現實用程序報告,使用一個小型 Python 腳本將三個 json 文件轉換為一個包含缺陷表的 HTML 文件。
該腳本由單獨的報告任務啟動,其最終工件是帶有報告的 HTML 文件。 腳本源也在存儲庫中,可以根據您的需求、顏色等進行調整。
Docker 安全檢查實用程序的實現方法和示例

外殼腳本

第二種選擇適用於需要檢查不在 CI/CD 系統內的 Docker 鏡像,或者需要以可直接在主機上執行的形式獲取所有指令的情況。 此選項由現成的 shell 腳本覆蓋,該腳本可以在乾淨的虛擬(甚至真實)機器上運行。 該腳本遵循與上面的 gitlab-runner 相同的說明。

為了使腳本成功運行,系統上必須安裝 Docker,並且當前用戶必須位於 docker 組中。

腳本本身可以在這裡找到: docker_sec_check.sh

在文件的開頭,變量指定應掃描哪個圖像以及缺陷的嚴重程度將導致 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 (Dockerfile_tar) 將構建一組以掃描帶有圖像的 tar 文件。

1. 我們從存儲庫中獲取適當的 Docker 文件和腳本 https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile.
2. 運行它進行組裝:

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

3. 構建完成後,從鏡像創建容器。 同時,我們將感興趣的鏡像名稱傳遞給 DOCKERIMAGE 環境變量,並將我們想要分析的 Dockerfile 從我們的機器掛載到該文件中 /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 工件掃描工具,我認為它非常有效地涵蓋了相當多的圖像安全要求。 還有許多其他付費和免費工具可以執行相同的檢查、繪製漂亮的報告或純粹在控制台模式下工作、涵蓋容器管理系統等。這些工具的概述以及如何集成它們可能會在稍後出現。

本文中描述的這組工具的積極方面是它們都是基於開源構建的,您可以嘗試使用它們和其他類似的工具,以找到完全適合您的要求和基礎設施功能的工具。 當然,所有發現的漏洞都應該研究特定條件下的適用性,但這是未來大型文章的主題。

我希望這些說明、腳本和實用程序能夠幫助您,並成為在容器化領域創建更安全的基礎設施的起點。

來源: www.habr.com

添加評論