保护容器构建的安全

1. 简介

ead1609267034bf7.png

软件漏洞是可能导致意外系统故障或为不法分子入侵您软件的漏洞。Container Analysis 提供两种操作系统扫描来查找容器中的漏洞:

  • 借助 On-Demand Scanning API,您可以手动扫描容器映像,检查是否存在操作系统漏洞,无论是在计算机本地还是在 Container Registry 或 Artifact Registry 中远程执行扫描均可。
  • 借助 Container Scanning API,您可以自动检测操作系统漏洞,每次将映像推送到 Container Registry 或 Artifact Registry 时进行扫描。启用此 API 还会对 Go 和 Java 漏洞启用语言包扫描。

借助 On-Demand Scanning API,您可以扫描存储在计算机本地的映像,也可以扫描存储在 Container Registry 或 Artifact Registry 中的远程映像。这样,您就可以精细控制要扫描漏洞的容器。您可以在 CI/CD 流水线中使用“按需扫描”功能扫描映像,然后再决定是否将其存储在注册表中。

学习内容

在本实验中,您将:

  • 使用 Cloud Build 构建映像
  • 为容器使用 Artifact Registry
  • 利用自动漏洞扫描
  • 配置按需扫描
  • 在 Cloud Build 的 CICD 中添加映像扫描

2. 设置和要求

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常您不在乎这是什么在大多数 Codelab 中,您都需要引用项目 ID(它通常标识为 PROJECT_ID)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。
  • 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除整个项目。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。

环境设置

在 Cloud Shell 中,设置项目 ID 和项目编号。将它们保存为 PROJECT_IDPROJECT_ID 变量。

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

启用服务

启用所有必要的服务:

gcloud services enable \
  cloudkms.googleapis.com \
  cloudbuild.googleapis.com \
  container.googleapis.com \
  containerregistry.googleapis.com \
  artifactregistry.googleapis.com \
  containerscanning.googleapis.com \
  ondemandscanning.googleapis.com \
  binaryauthorization.googleapis.com 

3. 使用 Cloud Build 构建映像

在本部分中,您将创建一个自动化构建流水线,用于构建容器映像,对其进行扫描,然后评估结果。如果系统未发现任何严重漏洞,则会将映像推送到代码库。如果发现严重漏洞,构建将失败并退出。

为 Cloud Build 服务账号提供访问权限

Cloud Build 需要有权访问按需扫描 API。使用以下命令提供访问权限。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

创建并切换到工作目录

mkdir vuln-scan && cd vuln-scan

定义示例图片

创建名为 Dockerfile 的文件,其中包含以下内容。

cat > ./Dockerfile << EOF
FROM gcr.io/google-appengine/debian9@sha256:ebffcf0df9aa33f342c4e1d4c8428b784fc571cdf6fbab0b31330347ca8af97a

# System
RUN apt update && apt install python3-pip -y

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==1.1.4
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

EOF

创建一个名为 main.py 的文件,其中包含以下内容

cat > ./main.py << EOF
import os
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    name = os.environ.get("NAME", "Worlds")
    return "Hello {}!".format(name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF

创建 Cloud Build 流水线

以下命令将在用于自动化流程的目录中创建一个 cloudbuild.yaml 文件。在此示例中,步骤仅限于容器构建流程。不过,在实践中,除了容器步骤之外,您还需要添加特定于应用的说明和测试。

使用以下命令创建文件。

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']


EOF

运行持续集成流水线

提交 build 以进行处理

gcloud builds submit

查看 build 详情

构建流程开始后,在 Cloud Build 信息中心内查看进度。

  1. 在 Cloud 控制台中打开 Cloud Build
  2. 点击 build 即可查看内容

4. 适用于容器的 Artifact Registry

创建 Artifact Registry 仓库

在本实验中,您将使用 Artifact Registry 来存储和扫描映像。使用以下命令创建代码库。

gcloud artifacts repositories create artifact-scanning-repo \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository"

配置 Docker,以便在访问 Artifact Registry 时使用您的 gcloud 凭据。

gcloud auth configure-docker us-central1-docker.pkg.dev

更新 Cloud Build 流水线

修改 build 流水线,将生成的映像推送到 Artifact Registry

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

# push to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

运行 CI 流水线

提交 build 以供处理

gcloud builds submit

5. 自动漏洞扫描

每次您将新映像推送到 Artifact Registry 或 Container Registry 时,系统都会自动触发制品扫描。发现新漏洞时,漏洞信息会持续更新。在本部分,您将回顾刚刚构建并推送到 Artifact Registry 的映像,并探索漏洞结果。

查看图片详情

上一个构建流程完成后,请在 Artifact Registry 信息中心查看映像和漏洞结果。

  1. 在 Cloud 控制台中打开 Artifact Registry
  2. 点击 artifact-scanning-repo 以查看其内容
  3. 点击查看图片详情
  4. 点击查看映像的最新摘要
  5. 扫描完成后,点击映像的“漏洞”标签页

在“漏洞”标签页中,您将看到您刚构建的映像的自动扫描结果。

361be7b3bf293fca

自动扫描功能默认处于启用状态。探索 Artifact Registry 设置,了解如何关闭/开启自动扫描。

6. 按需扫描

在很多情况下,您可能需要先执行扫描,然后才能将映像推送到代码库。例如,容器开发者可以先扫描映像并修复问题,然后再将代码推送到源代码控制系统。在以下示例中,您将在本地构建和分析映像,然后再对结果执行操作。

构建映像

在此步骤中,您将使用本地 Docker 将映像构建到本地缓存。

docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image .

扫描图片

构建映像后,请求扫描该映像。扫描结果存储在元数据服务器中。此作业通过结果在元数据服务器中的位置完成。

gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --format="value(response.scan)" > scan_id.txt

查看输出文件

请花点时间查看存储在 scan_id.txt 文件中的上一步骤的输出。请注意扫描结果在元数据服务器中的报告位置。

cat scan_id.txt

查看详细的扫描结果

如需查看扫描的实际结果,请对输出文件中注明的报告位置使用 list-vulnerabilities 命令。

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) 

输出包含有关映像中所有漏洞的大量数据。

标记严重问题

人类很少直接使用报告中存储的数据。结果通常由自动化流程使用。使用以下命令读取报告详情,并记录是否发现了任何严重漏洞

export SEVERITY=CRITICAL

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq ${SEVERITY}; then echo "Failed vulnerability check for ${SEVERITY} level"; else echo "No ${SEVERITY} Vulnerabilities found"; fi

此命令的输出将是

Failed vulnerability check for CRITICAL level

7. 使用 Cloud Build 在 CICD 中进行扫描

提供对 Cloud Build 服务账号的访问权限

Cloud Build 需要有权访问按需扫描 API。使用以下命令提供访问权限。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

更新 Cloud Build 流水线

以下命令将在用于自动化流程的目录中创建一个 cloudbuild.yaml 文件。在此示例中,步骤仅限于容器构建流程。不过,在实践中,除了容器步骤之外,您还需要添加特定于应用的说明和测试。

使用以下命令创建文件。

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

运行持续集成流水线

提交 build 以进行处理,以便在发现严重级别为“严重”的漏洞时验证 build 是否中断。

gcloud builds submit

审核 build 失败

您刚刚提交的 build 将会失败,因为映像包含严重漏洞。

Cloud Build 历史记录页面中查看构建失败

修复漏洞

更新 Dockerfile,以使用不包含严重漏洞的基础映像。

使用以下命令覆盖 Dockerfile 以使用 Debian 10 映像

cat > ./Dockerfile << EOF
from python:3.8-slim  

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==2.1.0
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 main:app

EOF

使用良好的映像运行持续集成流程

提交 build 以进行处理,以验证在未发现严重漏洞的情况下 build 是否会成功。

gcloud builds submit

检查构建成功与否

您刚刚提交的 build 将会成功,因为更新后的映像不含任何严重漏洞。

Cloud Build 历史记录页面中查看 build 是否成功

查看扫描结果

在 Artifact Registry 中查看正常的映像

  1. 在 Cloud 控制台中打开 Artifact Registry
  2. 点击 artifact-scanning-repo 以查看内容
  3. 点击查看图片详情
  4. 点击查看映像的最新摘要
  5. 点击映像的“漏洞”标签页

8. 恭喜!

恭喜,您已完成此 Codelab!

所学内容:

  • 使用 Cloud Build 构建映像
  • 适用于容器的 Artifact Registry
  • 自动漏洞扫描
  • 按需扫描
  • 使用 Cloud Build 在 CICD 中进行扫描

后续步骤:

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

若要避免产生费用,最简单的方法是删除您为本教程创建的项目。

上次更新时间:2023 年 3 月 21 日