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

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 Administrator):用于创建和管理 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。此 API 是创建和管理 Assured Workloads 所必需的。

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 网络

创建自定义的虚拟私有云 (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 节点
  • 数据边界:您为受监管的环境启用了平台合规性控制措施

参考文档