保护容器构建的安全

保护容器构建的安全

关于此 Codelab

subject上次更新时间:3月 23, 2023
account_circleChristopher Grant 编写

1. 简介

ead1609267034bf7.png

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

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

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

学习内容

在本实验中,您将:

  • 使用 Cloud Build 构建映像
  • 使用 Artifact Registry for Containers
  • 利用自动漏洞扫描
  • 配置按需扫描
  • 在 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

查看构建详情

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

  1. 在 Cloud 控制台中打开 Cloud Build
  2. 点击构建以查看内容

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 流水线

修改构建流水线,将生成的映像推送到 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

运行持续集成流水线

提交 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 将失败,因为映像包含严重漏洞。

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 以进行处理,以验证在未发现严重级别为“严重”的漏洞时构建能否成功。

gcloud builds submit

检查构建成功与否

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

Cloud 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 日