保护工作场所安全检测系统

1. 简介

在本 Codelab 中,您将构建一个基本演示应用,该应用展示了如何集成各种 Google Cloud 服务,以用于具有合规性限制的项目中的服务。此项目使用以下安全功能:

本 Codelab 适合各种水平的开发者,包括新手。您将使用 Google Cloud Shell 中的命令行界面和 Python 代码。您无需成为 Python 专家,但对如何读取代码有基本的了解将有助于您理解相关概念。

注意:这是一个简化的概念验证,而不是生产应用。在实际应用场景中,对此服务采取额外的预防措施,例如经过身份验证的安全外部访问。

2. 准备工作

项目设置

../shared/_project-setup.md

启动 Cloud Shell

Cloud Shell 是在 Google Cloud 中运行的命令行环境,预加载了必要的工具。

  1. 点击 Google Cloud 控制台顶部的激活 Cloud Shell:

404e4cce0f23e5c5.png

  1. 连接到 Cloud Shell 后,运行以下命令以验证您在 Cloud Shell 中的身份验证:
gcloud auth list
  1. 运行以下命令,确认您的项目已配置为可与 gcloud 搭配使用:
gcloud config get project
  1. 确认项目符合预期,然后运行以下命令以设置项目 ID:
export PROJECT_ID=$(gcloud config get project)

必需的 IAM 权限

您用于此 Codelab 的账号必须具有以下 IAM 角色。这些权限对于创建所需的 Google Cloud 资源(项目、文件夹、GKE 集群、KMS 密钥、服务账号等)和配置保证型工作负载是必需的。

在组织级层:

  • roles/assuredworkloads.admin (Assured Workloads 管理员):用于创建和管理 Assured Workloads 资源本身,确保合规性配置。

在结算账号级别(在您的结算账号中):

  • roles/billing.accountUser (Billing Account User):用于关联指定的结算账号。

配置 Codelab 变量

如需创建所需的基础设施,您需要提供以下环境变量:

# The ID of the Billing Account in the format (XXXXXX-XXXXXX-XXXXXX).
# This value will be used to attach in the projects created using Assured Workloads
export BILLING_ACCOUNT=

# The ID of a Google Cloud Platform organization
# Run `gcloud organizations list` to check all your available organizations
export GCP_ORGANIZATION=

# The numeric ID of a folder where the Assured Workloads will create the resources.
export FOLDER_ID=

# Region where the application will be deployed.
# Since you are using Assured Workloads, you MUST use one of the valid locations as described here: <https://docs.cloud.google.com/assured-workloads/docs/locations>
export REGION="us-central1"

# The ID of an existing Google Cloud project to be used for API quota and billing purposes.
# This project will only be used to enable the Assured Workloads API and create an Assured Workload.
export QUOTA_PROJECT_ID=

# Random suffix used to avoid naming collisions when creating the GCP projects.
export RANDOM_SUFFIX=$(cat /dev/urandom | tr -dc 'a-z0-9' | head -c 5 ; echo)

# The ID of the projects that will be created using Assured Workloads.
# You can modify this value if you want a custom id.
export PROJECT_ID="il5-gemini-vision-aw-${RANDOM_SUFFIX}"
export KMS_PROJECT_ID="il5-gemini-vision-kms-${RANDOM_SUFFIX}"

3. 创建 Assured Workloads 基础

现在,您可以在受监管的环境中为应用奠定基础。使用 Assured Workloads 为资源创建受控环境,以帮助强制执行合规性要求。

配置配额项目

在配额项目中启用 Assured Workloads API。创建和管理 Assured Workloads 需要此 API。

gcloud services enable assuredworkloads.googleapis.com \
  --project="${QUOTA_PROJECT_ID}"

创建 Assured Workloads 环境

以下命令会为您的演示创建一个安全的“着陆区”。它会在您指定的文件夹和结算账号下创建两个新的 Google Cloud 项目。

  • 一个项目托管您的 GKE 集群和应用。
  • 另一个项目用于管理客户管理的加密密钥 (CMEK)。

从项目创建之日起,它会自动将指定的 IL5 合规性控制措施应用于这两个项目。

运行以下命令以创建工作负载环境。

export ASSURED_WORKLOAD_ID=$(gcloud assured workloads create \
    --project="${QUOTA_PROJECT_ID}" \
    --display-name="DoD IL5 Gemini Vision Demo" \
    --compliance-regime="IL5" \
    --billing-account="billingAccounts/${BILLING_ACCOUNT}" \
    --location="${REGION}" \
    --organization="${GCP_ORGANIZATION}" \
    --provisioned-resources-parent="folders/${FOLDER_ID}" \
    --resource-settings="consumer-project-id=${PROJECT_ID},consumer-project-name=DoD IL5 Workloads,encryption-keys-project-id=${KMS_PROJECT_ID},encryption-keys-project-name=DoD IL5 KMS" \
    --labels="codelab=gemini-vision-demo" \
    --format="value(name)")

echo "Assured Workload created: ${ASSURED_WORKLOAD_ID}"

export WORKLOAD_FOLDER_ID=$(gcloud assured workloads describe ${ASSURED_WORKLOAD_ID} \
    --location="${REGION}" \
    --project="${QUOTA_PROJECT_ID}" \
    --format="json" | grep -B 1 "CONSUMER_FOLDER" | grep -oE "[0-9]{10,}")

echo "Assured Workload folder created: ${WORKLOAD_FOLDER_ID}"

gcloud projects create "${PROJECT_ID}" \
    --folder="${WORKLOAD_FOLDER_ID}" \
    --name="DoD IL5 Workloads"

gcloud billing projects link "${PROJECT_ID}" \
    --billing-account="${BILLING_ACCOUNT}"

export PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")

启用必需的 Google Cloud API

在构建之前,请为所需服务启用必需的 API。

以下命令会在您的主要工作负载项目中激活此 Codelab 所需的所有服务。

gcloud services enable \
    aiplatform.googleapis.com \
    artifactregistry.googleapis.com \
    cloudkms.googleapis.com \
    compute.googleapis.com \
    container.googleapis.com \
    iam.googleapis.com \
    logging.googleapis.com \
    monitoring.googleapis.com \
    --project="${PROJECT_ID}"

4. GKE 基础架构设置

构建支持 GKE 集群的核心基础架构。这包括为集群设置专用网络,以及配置您自己的加密密钥来保护节点上的数据。

配置 VPC 网络

创建自定义的 Virtual Private Cloud (VPC) 和子网。这种方法让您可以完全控制 IP 地址范围,并确保集群按预期隔离。

运行以下命令,以在指定区域内创建 VPC 网络和子网。

export GKE_NETWORK_NAME="il5-gke-network"
export GKE_SUBNETWORK_NAME="il5-gke-subnet"

gcloud compute networks create "${GKE_NETWORK_NAME}" \
    --description="VPC network for GKE cluster in DoD IL5 Assured Workload" \
    --subnet-mode="custom" \
    --project="${PROJECT_ID}"

gcloud compute networks subnets create "${GKE_SUBNETWORK_NAME}" \
    --network="${GKE_NETWORK_NAME}" \
    --range="10.10.0.0/20" \
    --region="${REGION}" \
    --description="Subnet for GKE cluster nodes in DoD IL5 Assured Workload" \
    --project="${PROJECT_ID}"

使用 Cloud KMS 配置加密

如需满足对静态数据的严格合规性要求,请使用客户管理的加密密钥 (CMEK)。这样,您就可以直接控制用于加密 GKE 节点启动磁盘的密钥。

export KMS_KEYRING_NAME="il5_gke_key_ring"
export KMS_KEY_NAME="il5_gke_key"

gcloud kms keyrings create "${KMS_KEYRING_NAME}" \
    --location="$REGION" \
    --project="${KMS_PROJECT_ID}"

gcloud kms keys create "${KMS_KEY_NAME}" \
    --keyring="${KMS_KEYRING_NAME}" \
    --location="${REGION}" \
    --purpose="encryption" \
    --project="${KMS_PROJECT_ID}"

由于加密密钥位于需要使用它的服务所在的 KMS 项目之外,因此工作负载项目中的 Google Compute Engine 服务代理需要获得对该密钥的访问权限。

您必须明确授予工作负载项目的 GCE 服务代理使用此密钥的权限。以下命令会向密钥添加 IAM 政策绑定,从而向服务代理授予必要的角色。

gcloud kms keys add-iam-policy-binding "${KMS_KEY_NAME}" \
    --location="${REGION}" \
    --keyring="${KMS_KEYRING_NAME}" \
    --member="serviceAccount:service-${PROJECT_NUMBER}@compute-system.iam.gserviceaccount.com" \
    --role="roles/cloudkms.cryptoKeyEncrypterDecrypter" \
    --project="${KMS_PROJECT_ID}"

配置 GKE 节点服务账号

export GKE_NODE_SA=gke-node-sa

gcloud iam service-accounts create "${GKE_NODE_SA}" \
    --display-name="GKE Node Service Account" \
    --project="${PROJECT_ID}"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/logging.logWriter"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/monitoring.metricWriter"

5. GKE 集群创建和配置

现在,您可以创建 GKE 集群。以下命令用于预配启用了多项安全功能的 GKE 集群。

由于 Google Cloud 会预配节点和控制平面,因此此过程需要几分钟才能完成。

export GKE_CLUSTER=ppe-app

gcloud beta container clusters create "${GKE_CLUSTER}" \
    --project="$PROJECT_ID" \
    --region="$REGION" \
    --service-account="${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --release-channel="regular" \
    --machine-type="n2d-standard-4" \
    --image-type="COS_CONTAINERD" \
    --disk-type="pd-ssd" \
    --disk-size="50" \
    --boot-disk-kms-key="projects/${KMS_PROJECT_ID}/locations/${REGION}/keyRings/${KMS_KEYRING_NAME}/cryptoKeys/${KMS_KEY_NAME}" \
    --metadata disable-legacy-endpoints=true \
    --num-nodes="1" \
    --network="projects/${PROJECT_ID}/global/networks/${GKE_NETWORK_NAME}" \
    --subnetwork="projects/${PROJECT_ID}/regions/${REGION}/subnetworks/${GKE_SUBNETWORK_NAME}" \
    --security-posture="standard" \
    --workload-vulnerability-scanning="disabled" \
    --workload-pool="${PROJECT_ID}.svc.id.goog" \
    --workload-metadata=GKE_METADATA \
    --addons="HorizontalPodAutoscaling,HttpLoadBalancing,NodeLocalDNS,GcePersistentDiskCsiDriver" \
    --max-surge-upgrade=1 \
    --max-unavailable-upgrade=0 \
    --binauthz-evaluation-mode="DISABLED" \
    --no-enable-basic-auth \
    --enable-autoupgrade \
    --enable-autorepair \
    --enable-confidential-nodes \
    --confidential-node-type=sev \
    --enable-ip-access \
    --enable-ip-alias \
    --enable-managed-prometheus \
    --enable-dns-access \
    --enable-shielded-nodes \
    --shielded-integrity-monitoring \
    --shielded-secure-boot

连接到新集群

如需与新集群互动,请配置本地 kubectl 命令行工具。

此命令会提取集群的凭据和端点,并自动配置本地 kubeconfig 文件。运行此命令后,您运行的任何 kubectl 命令都将针对新的 GKE 集群。

gcloud container clusters get-credentials "${GKE_CLUSTER}" \
    --region="${REGION}" \
    --project="${PROJECT_ID}" \
    --dns-endpoint

6. 应用身份配置

如需将 Kubernetes 服务账号连接到 Google Cloud IAM 服务账号,请配置 Workload Identity。

创建服务账号

在集群内创建专用 Kubernetes 服务账号 (KSA)。

export GKE_NAMESPACE=default
export GKE_SA=ppe-sa

kubectl create sa "${GKE_SA}" --namespace="${GKE_NAMESPACE}"

接下来,您的应用需要在 Google Cloud 中拥有身份。为应用创建 Google Cloud IAM 服务账号。创建服务账号后,向其授予必要的角色。

# Create GCP service account
gcloud iam service-accounts create "${GKE_SA}" \
    --project="${PROJECT_ID}"
# Grant necessary roles
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${GKE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/aiplatform.user"

允许 Kubernetes 服务账号模拟 IAM 服务账号

创建这两个服务账号后,最后一步是创建它们之间的关联。此流程分为两部分。首先,向您的 Google Cloud 服务账号添加 IAM 政策。

# Allow the Kubernetes service account to act as GCP service account by using Workload Identity
gcloud iam service-accounts add-iam-policy-binding "${GKE_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --project="${PROJECT_ID}" \
    --role="roles/iam.workloadIdentityUser" \
    --member="serviceAccount:${PROJECT_ID}.svc.id.goog[${GKE_NAMESPACE}/${GKE_SA}]"

其次,为 Kubernetes 服务账号添加注释。

kubectl annotate --namespace="${GKE_NAMESPACE}" serviceaccount "$GKE_SA" \
    iam.gke.io/gcp-service-account="${GKE_SA}@${PROJECT_ID}.iam.gserviceaccount.com"

完成此操作后,集群中以 Kubernetes 服务账号运行的任何 pod 现在都可以访问 Vertex API。

注意:您可以消除服务账号模拟,以简化此配置。如需了解详情和限制,请点击此处。

7. 应用构建和部署

现在,您可以打包应用、存储应用,然后将其部署到 GKE 集群。

创建 Artifact Registry 代码库

您必须先将应用封装为 Docker 容器并将其存储在 Artifact Registry 代码库中,然后才能运行该应用。使用以下命令创建此代码库。

export REPOSITORY_ID=ppe-repo

gcloud artifacts repositories create "${REPOSITORY_ID}" \
  --repository-format=docker \
  --location="${REGION}" \
  --project="${PROJECT_ID}" \
  --description="Regional Docker repo for PPE App"

您必须明确授予 GKE 节点所用服务账号从新代码库读取数据的权限。

gcloud artifacts repositories add-iam-policy-binding "${REPOSITORY_ID}" \
    --location="${REGION}" \
    --role="roles/artifactregistry.reader" \
    --project="${PROJECT_ID}" \
    --member="serviceAccount:${GKE_NODE_SA}@${PROJECT_ID}.iam.gserviceaccount.com"

构建和推送 Docker 映像

构建 Docker 映像并将其推送到代码库。首先,克隆源代码并构建容器映像。然后,使用完整的 Artifact Registry 路径为其添加标记,并将其推送到您之前创建的代码库。

git clone https://github.com/GoogleCloudPlatform/next-26-sessions.git

cd BRK3-034-workplace-safety

cd ppe

export IMAGE_TAG="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_ID}/ppe-app:v15"
docker build -t "${IMAGE_TAG}" .
docker push "${IMAGE_TAG}"

部署到 GKE

有了 Artifact Registry 中的容器映像,最后一步就是指示 GKE 拉取并运行该映像。为此,您需要在 Kubernetes 清单文件中定义应用的资源,然后将其应用于集群。此命令会创建文件中定义的 Deployment 和 Service 对象。

export GKE_DEPLOY=ppe-detector

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${GKE_DEPLOY}
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ${GKE_DEPLOY}
  template:
    metadata:
      labels:
        app: ${GKE_DEPLOY}
    spec:
      serviceAccountName: ${GKE_SA}
      containers:
      - name: ${GKE_DEPLOY}
        image: ${IMAGE_TAG}
        env:
        - name: PROJECT_ID
          value: ${PROJECT_ID}
        - name: LOCATION
          value: ${REGION}
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
          limits:
            cpu: "500m"
            memory: "1Gi"
---
apiVersion: v1
kind: Service
metadata:
  name: ${GKE_DEPLOY}
spec:
  type: LoadBalancer
  selector:
    app: ${GKE_DEPLOY}
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
EOF

8. 测试应用

最后一步是访问并测试演示版应用。这包括检索分配给服务的外部 IP 地址,并通过简单的前端与之互动。

检索服务的外部 IP

获取公开服务的外部 IP 地址(预配需要约 30 秒)

export IP_ADDRESS=$(kubectl get service "${GKE_DEPLOY}" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $IP_ADDRESS

在本地运行前端

在此演示中,前端是一个简单的 HTML/JavaScript 网页,不属于 GKE 部署。它旨在在本地机器上运行。

在正式版应用中,前端应从 GCP 提供。在本地机器上:

# Update the index.html file with the server IP address
cd frontend

# For Linux
sed -i "s#\(const BACKEND_URL = \"http://\)[^/]\+\(\/analyze\";\)#\1${IP_ADDRESS}\2#g" "index.html"

# For MacOS
#sed -i '' "s#\(const BACKEND_URL = #\"http://\)[^/]*\(\/analyze\";\)#\1${IP_ADDRESS}\2#g" "index.html"

python3 -m http.server 8001

在 Chrome 中打开 http://localhost:8001/index.html。

9. 清理

为避免持续产生费用,请删除在本 Codelab 中创建的资源。

销毁 GKE 集群

如需删除整个应用,只需删除 GKE 集群。为此,请运行以下命令:

gcloud container clusters delete "${GKE_CLUSTER}" \
    --region="$REGION" \
    --project="${PROJECT_ID}"

删除 Assured Workloads

运行以下命令可删除所有与 Assured Workloads 相关的资源。

# Workload project deletion
gcloud billing projects unlink "${PROJECT_ID}"
gcloud projects delete "${PROJECT_ID}"

# KMS project deletion
gcloud billing projects unlink "${KMS_PROJECT_ID}"
gcloud projects delete "${KMS_PROJECT_ID}"

# Assured Workload folder deletion
gcloud resource-manager folders delete ${WORKLOAD_FOLDER_ID} --quiet

# Assured Workload deletion
gcloud assured workloads delete "${ASSURED_WORKLOAD_ID}" \
    --location="${REGION}" \
    --organization="${GCP_ORGANIZATION}" \
    --project="${QUOTA_PROJECT_ID}"

10. 恭喜

任务完成!您已成功构建了一个工作场所安全检测系统,该系统适用于受监管的行业,并使用 Gemini 来检测安全帽。

您完成的任务:

  • 数据保护和隐私权:您已预配使用 CMEK 的机密 GKE 节点
  • 数据边界:您为受监管的环境启用了平台合规性控制措施

参考文档