保护容器构建的安全

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 需要有权访问 On-Demand Scanning 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

运行 CI 流水线

提交 build 以供处理

gcloud builds submit

查看 build 详情

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

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

4. Artifact Registry for Containers

创建 Artifact Registry 代码库

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

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

将 Docker 配置为使用您的 gcloud 凭证访问 Artifact Registry。

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.png

默认情况下,系统会启用自动扫描功能。查看 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) 

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

标记严重问题

人类用户很少直接使用报告中存储的数据。该结果通常供自动化流程使用。使用以下命令读取报告详细信息,并在发现任何严重程度为 CRITICAL 的漏洞时进行记录

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 需要有权访问 On-Demand Scanning 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

运行 CI 流水线

提交 build 以供处理,验证在发现  CRITICAL 严重级别的漏洞时,构建会中断。

gcloud builds submit

查看构建失败

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

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

修复漏洞

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

使用以下命令覆盖 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

使用良好的映像运行 CI 流程

提交 build 以供处理,验证在未发现  CRITICAL 严重级别的漏洞时,构建会成功。

gcloud builds submit

查看 build 是否成功

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

Cloud Build 历史记录页面中查看构建成功情况

查看扫描结果

查看 Artifact Registry 中的良好映像

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

8. 恭喜!

恭喜,您已完成此 Codelab!

所学内容:

  • 使用 Cloud Build 构建映像
  • Artifact Registry for Containers
  • 自动漏洞扫描
  • 按需扫描
  • 使用 Cloud Build 在 CICD 中进行扫描

后续步骤:

清理

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

删除项目

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

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