本教程介绍如何为 Google Kubernetes Engine (GKE) 设置、配置和使用 Binary Authorization。二进制授权是在容器映像上创建证明的过程,目的是为了在将映像部署到 GKE 之前验证映像是否满足特定条件。
例如,Binary Authorization 可以验证应用是否通过了单元测试,或者应用是否通过使用一组特定系统构建的。如需了解详情,请参阅 Software Delivery Shield 概览。
本教程面向想要深入了解容器漏洞扫描和 Binary Authorization 及其在 CI/CD 流水线中的实现和应用情况的从业者。
本教程假定您熟悉以下主题和技术:
- 持续集成和持续部署
- 常见漏洞和披露 (CVE) 漏洞扫描
- GKE
- Artifact Registry
- Cloud Build
- Cloud Key Management Service (Cloud KMS)
目标
- 为预演和生产环境部署 GKE 集群。
- 创建多个证明者和证明。
- 使用 Cloud Build 部署 CI/CD 流水线。
- 测试部署流水线。
- 开发一个紧急访问权限流程。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
- 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
启用 Binary Authorization, Cloud Build, Cloud KMS, GKE, Artifact Registry, Artifact Analysis, Resource Manager, and Cloud Source Repositories API。
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
启用 Binary Authorization, Cloud Build, Cloud KMS, GKE, Artifact Registry, Artifact Analysis, Resource Manager, and Cloud Source Repositories API。
-
在 Google Cloud 控制台中,激活 Cloud Shell。
Cloud Shell 会话随即会在 Google Cloud 控制台的底部启动,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 且已为当前项目设置值的 Shell 环境。该会话可能需要几秒钟时间来完成初始化。
本教程中的所有命令都在 Cloud Shell 中运行。
CI/CD 流水线的架构
确保并强制应用部署按照您组织批准的流程操作是软件开发生命周期 (SDLC) 的一个重要环节。在 GKE 上使用 Binary Authorization 是建立这些检查和平衡的方法之一。首先,Binary Authorization 将备注附加到容器映像。然后,GKE 会在您部署应用之前验证必需的备注是否存在。
这些备注或证明可做出与映像有关的陈述。证明是完全可配置的,但以下是一些常见示例:
- 应用已通过单元测试。
- 该应用已通过质量保证 (QA) 团队的验证。
- 该应用已进行漏洞扫描,从未发现任何问题。
下图描绘了一个 SDLC,说明在漏洞扫描完成后未找到已知漏洞时应用了单个证明。
在本教程中,您将使用 Cloud Source Repositories、Cloud Build、Artifact Registry 和 GKE 创建一个 CI/CD 流水线。下图演示了这一 CI/CD 流水线。
此 CI/CD 流水线包含以下步骤:
构建一个包含应用源代码的容器映像。
将该容器映像推送到 Artifact Registry。
Artifact Analysis 会扫描容器映像以查找已知的安全漏洞或 CVE。
如果映像不包含严重性分数大于 5 的 CVE,则证明该映像没有严重 CVE,并将其自动部署到模拟环境。分数大于 5 表示发现中等到严重程度的漏洞,因此未得到证明或部署。
质量保证团队会在模拟集群中检查该应用。如果该应用满足要求,则团队会手动应用证明,确认该容器映像达到足够高的质量,可以部署到生产环境。系统将更新生产清单,且应用会部署到生产 GKE 集群中。
GKE 集群已配置为检查容器映像以进行证明,并拒绝没有所需证明的任何部署。模拟 GKE 集群只需要漏洞扫描证明,但生产 GKE 集群同时需要漏洞扫描和质量保证证明。
在本教程中,您在 CI/CD 流水线中引入了失败机制,以测试和验证此机制的实施情况。最后,您可以实现紧急访问权限过程,一旦有紧急情况,就可以在 GKE 中绕过这些部署检查。
设置环境
本教程使用以下环境变量。您可以更改这些值以满足您的要求,但本教程中的所有步骤都假定这些环境变量已存在并包含有效值。
在 Cloud Shell 中,设置要在其中部署和管理本教程中使用的所有资源的 Google Cloud 项目:
export PROJECT_ID="${DEVSHELL_PROJECT_ID}" gcloud config set project ${PROJECT_ID}
设置要在其中部署这些资源的区域:
export REGION="us-central1"
GKE 集群和 Cloud KMS 密钥位于此区域中。在本教程中,区域为
us-central1
。如需详细了解区域,请参阅地理位置和区域。设置 Cloud Build 项目编号:
export PROJECT_NUMBER="$(gcloud projects describe "${PROJECT_ID}" \ --format='value(projectNumber)')"
设置 Cloud Build 服务账号电子邮件:
export CLOUD_BUILD_SA_EMAIL="${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com"
创建 GKE 集群
创建两个 GKE 集群并向 Cloud Build 授予 Identity and Access Management (IAM) 权限,以将应用部署到 GKE。创建 GKE 集群可能需要几分钟时间。
在 Cloud Shell 中,创建 GKE 集群以用于模拟环境:
gcloud container clusters create "staging-cluster" \ --project "${PROJECT_ID}" \ --machine-type "n1-standard-1" \ --region "${REGION}" \ --num-nodes "1" \ --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE
创建 GKE 集群以用于生产环境:
gcloud container clusters create "prod-cluster" \ --project "${PROJECT_ID}" \ --machine-type "n1-standard-1" \ --region "${REGION}" \ --num-nodes "1" \ --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE
授予 Cloud Build 服务账号部署到 GKE 的权限:
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" \ --role "roles/container.developer"
创建签名密钥
创建两个 Cloud KMS 非对称密钥以给证明签名。
在 Cloud Shell 中,创建一个名为
binauthz
的 Cloud KMS 密钥环:gcloud kms keyrings create "binauthz" \ --project "${PROJECT_ID}" \ --location "${REGION}"
创建一个名为
vulnz-signer
的非对称 Cloud KMS 密钥,该密钥将用来给漏洞扫描证明签名并进行验证:gcloud kms keys create "vulnz-signer" \ --project "${PROJECT_ID}" \ --location "${REGION}" \ --keyring "binauthz" \ --purpose "asymmetric-signing" \ --default-algorithm "rsa-sign-pkcs1-4096-sha512"
创建一个名为
qa-signer
的非对称 Cloud KMS 密钥以给质量保证证明签名并进行验证:gcloud kms keys create "qa-signer" \ --project "${PROJECT_ID}" \ --location "${REGION}" \ --keyring "binauthz" \ --purpose "asymmetric-signing" \ --default-algorithm "rsa-sign-pkcs1-4096-sha512"
配置证明
您可以创建附加到容器映像的备注,并使用上述步骤中的密钥向 Cloud Build 服务账号授予查看备注、附加备注以及创建证明者的权限。
创建漏洞扫描工具证明
在 Cloud Shell 中,创建一个名为
vulnz-note
的 Artifact Analysis 备注:curl "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=vulnz-note" \ --request "POST" \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $(gcloud auth print-access-token)" \ --header "X-Goog-User-Project: ${PROJECT_ID}" \ --data-binary @- <<EOF { "name": "projects/${PROJECT_ID}/notes/vulnz-note", "attestation": { "hint": { "human_readable_name": "Vulnerability scan note" } } } EOF
授予 Cloud Build 服务账号查看
vulnz-note
备注并将其附加到容器映像的权限:curl "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/vulnz-note:setIamPolicy" \ --request POST \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $(gcloud auth print-access-token)" \ --header "X-Goog-User-Project: ${PROJECT_ID}" \ --data-binary @- <<EOF { "resource": "projects/${PROJECT_ID}/notes/vulnz-note", "policy": { "bindings": [ { "role": "roles/containeranalysis.notes.occurrences.viewer", "members": [ "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" ] }, { "role": "roles/containeranalysis.notes.attacher", "members": [ "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" ] } ] } } EOF
创建漏洞扫描证明者:
gcloud container binauthz attestors create "vulnz-attestor" \ --project "${PROJECT_ID}" \ --attestation-authority-note-project "${PROJECT_ID}" \ --attestation-authority-note "vulnz-note" \ --description "Vulnerability scan attestor"
为证明者的签名密钥添加公钥:
gcloud beta container binauthz attestors public-keys add \ --project "${PROJECT_ID}" \ --attestor "vulnz-attestor" \ --keyversion "1" \ --keyversion-key "vulnz-signer" \ --keyversion-keyring "binauthz" \ --keyversion-location "${REGION}" \ --keyversion-project "${PROJECT_ID}"
授予 Cloud Build 服务账号查看
vulnz-attestor
所做证明的权限:gcloud container binauthz attestors add-iam-policy-binding "vulnz-attestor" \ --project "${PROJECT_ID}" \ --member "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" \ --role "roles/binaryauthorization.attestorsViewer"
授予 Cloud Build 服务账号使用
vulnz-signer
密钥给对象签名的权限:gcloud kms keys add-iam-policy-binding "vulnz-signer" \ --project "${PROJECT_ID}" \ --location "${REGION}" \ --keyring "binauthz" \ --member "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" \ --role 'roles/cloudkms.signerVerifier'
创建质量保证证明
在 Cloud Shell 中,创建一个名为
qa-note
的 Artifact Analysis 备注:curl "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=qa-note" \ --request "POST" \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $(gcloud auth print-access-token)" \ --header "X-Goog-User-Project: ${PROJECT_ID}" \ --data-binary @- <<EOF { "name": "projects/${PROJECT_ID}/notes/qa-note", "attestation": { "hint": { "human_readable_name": "QA note" } } } EOF
授予 Cloud Build 服务账号查看
qa-note
备注并将其附加到容器映像的权限:curl "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/qa-note:setIamPolicy" \ --request POST \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $(gcloud auth print-access-token)" \ --header "X-Goog-User-Project: ${PROJECT_ID}" \ --data-binary @- <<EOF { "resource": "projects/${PROJECT_ID}/notes/qa-note", "policy": { "bindings": [ { "role": "roles/containeranalysis.notes.occurrences.viewer", "members": [ "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" ] }, { "role": "roles/containeranalysis.notes.attacher", "members": [ "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" ] } ] } } EOF
创建质量保证证明者:
gcloud container binauthz attestors create "qa-attestor" \ --project "${PROJECT_ID}" \ --attestation-authority-note-project "${PROJECT_ID}" \ --attestation-authority-note "qa-note" \ --description "QA attestor"
为证明者的签名密钥添加公钥:
gcloud beta container binauthz attestors public-keys add \ --project "${PROJECT_ID}" \ --attestor "qa-attestor" \ --keyversion "1" \ --keyversion-key "qa-signer" \ --keyversion-keyring "binauthz" \ --keyversion-location "${REGION}" \ --keyversion-project "${PROJECT_ID}"
授予 Cloud Build 服务账号查看
qa-attestor
所做证明的权限:gcloud container binauthz attestors add-iam-policy-binding "qa-attestor" \ --project "${PROJECT_ID}" \ --member "serviceAccount:${CLOUD_BUILD_SA_EMAIL}" \ --role "roles/binaryauthorization.attestorsViewer"
授予您的质量保证团队给证明签名的权限:
gcloud kms keys add-iam-policy-binding "qa-signer" \ --project "${PROJECT_ID}" \ --location "${REGION}" \ --keyring "binauthz" \ --member "group:qa-team@example.com" \ --role 'roles/cloudkms.signerVerifier'
设置 Binary Authorization 政策
即使您使用 --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE
创建了 GKE 集群,您也必须编写一项政策,就二进制文件在集群中运行所需的证明,向 GKE 发出指示。Binary Authorization 政策存在于项目级层,但包含集群级层的配置。
以下政策会通过以下方式更改默认政策:
将默认
evaluationMode
更改为ALWAYS_DENY
。只有豁免映像或具有所需证明的映像才能在集群中运行。启用
globalPolicyEvaluationMode
,从而将默认许可名单更改为仅包含 Google 提供的系统映像。定义以下集群准入规则:
staging-cluster
要求vulnz-attestor
提供证明。prod-cluster
要求vulnz-attestor
和qa-attestor
提供证明。
如需详细了解 Binary Authorization 政策,请参阅 YAML 格式政策参考文档。
在 Cloud Shell 中,创建一个 YAML 文件来描述 Google Cloud 项目的 Binary Authorization 政策:
cat > ./binauthz-policy.yaml <<EOF admissionWhitelistPatterns: - namePattern: docker.io/istio/* defaultAdmissionRule: enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG evaluationMode: ALWAYS_DENY globalPolicyEvaluationMode: ENABLE clusterAdmissionRules: # Staging cluster ${REGION}.staging-cluster: evaluationMode: REQUIRE_ATTESTATION enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG requireAttestationsBy: - projects/${PROJECT_ID}/attestors/vulnz-attestor # Production cluster ${REGION}.prod-cluster: evaluationMode: REQUIRE_ATTESTATION enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG requireAttestationsBy: - projects/${PROJECT_ID}/attestors/vulnz-attestor - projects/${PROJECT_ID}/attestors/qa-attestor EOF
将新政策上传到 Google Cloud 项目:
gcloud container binauthz policy import ./binauthz-policy.yaml \ --project "${PROJECT_ID}"
创建漏洞扫描检查工具并启用 API
创建在 Cloud Build 的构建步骤中使用的容器映像。此容器会将检测到的任何漏洞的严重性分数与配置的阈值进行比较。如果分数未超出阈值,则 Cloud Build 会在容器上创建证明。如果分数超出阈值,则构建失败,而不创建任何证明。
在 Cloud Shell 中,创建一个新的 Artifact Registry 代码库来存储证明者映像:
gcloud artifacts repositories create cloudbuild-helpers \ --repository-format=DOCKER --location=${REGION}
克隆 Binary Authorization 工具和示例应用来源:
git clone https://github.com/GoogleCloudPlatform/gke-binary-auth-tools ~/binauthz-tools
构建名为
attestor
的漏洞扫描证明者容器并将其推送到cloudbuild-helpers
Artifact Registry:gcloud builds submit \ --project "${PROJECT_ID}" \ --tag "us-central1-docker.pkg.dev/${PROJECT_ID}/cloudbuild-helpers/attestor" \ ~/binauthz-tools
设置 Cloud Build 流水线
为示例应用和 Kubernetes 清单创建 Cloud Source Repositories 代码库和 Cloud Build 触发器。
创建 hello-app Cloud Source Repositories 代码库和 Artifact Registry 代码库
在 Cloud Shell 中,为示例应用创建 Cloud Source Repositories 代码库:
gcloud source repos create hello-app \ --project "${PROJECT_ID}"
在本地克隆代码库:
gcloud source repos clone hello-app ~/hello-app \ --project "${PROJECT_ID}"
将示例代码复制到代码库中:
cp -R ~/binauthz-tools/examples/hello-app/* ~/hello-app
创建一个新的 Artifact Registry 代码库来存储应用映像:
gcloud artifacts repositories create applications \ --repository-format=DOCKER --location=${REGION}
创建 hello-app Cloud Build 触发器
在 Google Cloud 控制台中,转到触发器页面。
点击管理代码库。
对于
hello-app
代码库,请点击 ...,然后选择添加触发器。在触发器设置窗口中,输入以下详细信息:
- 在名称字段中,输入
build-vulnz-deploy
。 - 对于事件,选择推送到分支。
- 在代码库字段中,从菜单中选择
hello-app
。 - 在分支字段中,输入
master
。 - 对于配置,选择 Cloud Build 配置文件(yaml 或 json)。
- 在位置中,选择代码库并输入默认值
/cloudbuild.yaml
。
- 在名称字段中,输入
添加以下替代变量对:
_COMPUTE_REGION
,值为us-central1
(或者您在开始时选择的区域)。_KMS_KEYRING
,值为binauthz
。_KMS_LOCATION
,值为us-central1
(或者您在开始时选择的区域)。_PROD_CLUSTER
,值为prod-cluster
。_QA_ATTESTOR
,值为qa-attestor
。_QA_KMS_KEY
,值为qa-signer
。_QA_KMS_KEY_VERSION
,值为1
。_STAGING_CLUSTER
,值为staging-cluster
。_VULNZ_ATTESTOR
,值为vulnz-attestor
。_VULNZ_KMS_KEY
,值为vulnz-signer
。_VULNZ_KMS_KEY_VERSION
,值为1
。
点击创建。
测试 Cloud Build 流水线
如需测试 CI/CD 流水线,请提交示例应用并将其推送到 Cloud Source Repositories 代码库。Cloud Build 会检测更改、构建应用并将应用部署到 staging-cluster
。流水线会等待长达 10 分钟的时间以进行质量保证验证。质量保证团队验证完部署之后,该过程会继续进行,系统将会更新生产 Kubernetes 清单,且 Cloud Build 会将应用部署到 prod-cluster
。
在 Cloud Shell 中,提交
hello-app
文件并将其推送到 Cloud Source Repositories 代码库以触发构建:cd ~/hello-app git add . git commit -m "Initial commit" git push origin master
在 Google Cloud 控制台中,转到历史记录页面。
如需查看构建进度,请点击 Cloud Build 的最近一次运行。
完成在
staging-cluster
中的部署之后,请转到服务页面。为验证应用是否正常工作,请点击该应用的端点链接。
转到代码库页面。
点击
applications
。点击
hello-app
。点击您在模拟部署中验证过的映像。
从映像详细信息中复制 Digest 值。下一步需要用到此信息。
如需应用手动质量保证证明,请将
...
替换为您从映像详情中复制的值。DIGEST
变量的格式应该为sha256:hash-value
。Await QA attestation
构建步骤还将输出一个可复制并粘贴的命令,如下所示。DIGEST="sha256:..." # Replace with your value gcloud beta container binauthz attestations sign-and-create \ --project "${PROJECT_ID}" \ --artifact-url "${REGION}-docker.pkg.dev/${PROJECT_ID}/applications/hello-app@${DIGEST}" \ --attestor "qa-attestor" \ --attestor-project "${PROJECT_ID}" \ --keyversion "1" \ --keyversion-key "qa-signer" \ --keyversion-location "${REGION}" \ --keyversion-keyring "binauthz" \ --keyversion-project "${PROJECT_ID}"
为验证应用已经部署,请转到服务页面。
如需查看应用,请点击端点链接。
部署未经证明的映像
到目前为止,示例应用没有任何漏洞。更新该应用以输出其他消息并更改基础映像。
在 Cloud Shell 中,将输出从
Hello World
更改为Binary Authorization
,并将基础映像从distroless
更改为debian
:cd ~/hello-app sed -i "s/Hello World/Binary Authorization/g" main.go sed -i "s/FROM gcr\.io\/distroless\/static-debian11/FROM debian/g" Dockerfile
提交并推送更改:
git add . git commit -m "Change message and base image" git push origin master
如需监控 CI/CD 流水线的状态,请在 Google Cloud 控制台中转到历史记录页面。
由于在映像中检测到 CVE,导致此构建失败。
如需检查发现的 CVE,请转到映像页面。
点击
hello-app
。如需查看发现的 CVE,请点击最新映像的漏洞摘要。
在 Cloud Shell 中,尝试在不通过漏洞扫描进行证明的情况下,将新映像部署到生产环境:
export SHA_DIGEST="[SHA_DIGEST_VALUE]" cd ~/hello-app sed "s/REGION/${REGION}/g" kubernetes/deployment.yaml.tpl | \ sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_ID}/g" | \ sed -e "s/DIGEST/${SHA_DIGEST}/g" > kubernetes/deployment.yaml gcloud container clusters get-credentials \ --project=${PROJECT_ID} \ --region="${REGION}" prod-cluster kubectl apply -f kubernetes
在 Google Cloud 控制台中,转到工作负载页面。
映像部署失败,因为它未由
vulnz-attestor
和qa-attestor
进行签名。
紧急访问权限过程
有时,您需要允许在正常工作流程范围之外进行更改。若要部署不含必需证明的映像,pod 定义需要使用紧急访问权限政策标志进行注释。如果启用此标志,则 GKE 仍会检查是否存在必需的证明,但会允许部署容器映像并记录违规行为。
如需详细了解如何绕过证明检查,请参阅覆盖政策。
在 Cloud Shell 中,取消注释 Kubernetes 清单中的紧急访问权限注释:
sed -i "31s/^#//" kubernetes/deployment.yaml
使用
kubectl
应用更改:kubectl apply -f kubernetes
如需验证更改是否已部署到
prod-cluster
,请转到 Google Cloud 控制台中的工作负载页面。现在,部署错误消息消失了。
为验证应用已经部署,请转到服务页面。
如需查看应用,请点击端点链接。
清除数据
为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。
删除项目
- 在 Google Cloud 控制台中,进入管理资源页面。
- 在项目列表中,选择要删除的项目,然后点击删除。
- 在对话框中输入项目 ID,然后点击关闭以删除项目。
后续步骤
- 构建容器的最佳做法。
- 部署容器化 Web 应用。
- 使用 Cloud Build 实现 GitOps 形式的持续交付。
- 代管式基础映像。
- 探索有关 Google Cloud 的参考架构、图表和最佳做法。查看我们的 Cloud Architecture Center。