使用无代理 gRPC(旧版)设置服务安全性
本指南介绍如何为无代理 gRPC 服务网格配置安全服务。
本文档适用于具有负载均衡 API 的 Cloud Service Mesh 。这是旧版文档。
使用要求
在为 gRPC 代理无服务网格配置服务安全之前,请确保满足以下要求。
- 您的部署满足 准备使用无代理 gRPC 设置 Cloud Service Mesh。
- 必须使用 xDS v3。
- 您可以使用以下任一语言访问所需的 xDS 版本和证书提供程序功能:
- gRPC Java
- gRPC C++
- gRPC Python
- gRPC Go 您可以在 github 上找到所需的语言版本
- 您可以访问引导生成器 0.13.0 版。引导生成器映像位于 Google Cloud 容器代码库中。
- 您已满足 gRPC 无代理服务网格负载均衡。
- 您拥有足够的权限来创建或更新 Cloud Service Mesh 和 Google Cloud 服务网格资源,以使用无代理服务网格 (PSM) 安全。如需了解所需权限的完整信息,请参阅准备使用无代理 gRPC 服务设置 Cloud Service Mesh。
- 您拥有使用 Certificate Authority Service 所需的权限,如为颁发证书创建证书授权机构中所述
配置身份和访问权限管理
您必须具有 使用 Google Kubernetes Engine 所需的权限。您必须至少具有以下角色:
roles/container.clusterAdmin
GKE 角色roles/compute.instanceAdmin
Compute Engine 角色roles/iam.serviceAccountUser
角色
如要创建设置所需的资源,您必须具有 compute.NetworkAdmin
角色。此角色包含创建、更新、删除、列出和使用所需资源(即在其他资源中引用)的所有必要权限。如果您是项目的所有者编辑者,则会自动拥有此角色。
请注意,在后端服务和目标 HTTPS 代理资源中引用这些资源时,系统不会强制执行 networksecurity.googleapis.com.clientTlsPolicies.use
和 networksecurity.googleapis.com.serverTlsPolicies.use
。
如果在未来强制执行此操作,并且您使用的是 compute.NetworkAdmin
角色,那么强制执行此检查时您不会发现任何问题。
如果您使用的是自定义角色,并且此检查将强制执行,那么您必须确保添加相应的 .use
权限。否则,将来,您可能会发现自定义角色没有必要的权限,分别引用后端服务或目标 HTTPS 代理中的 clientTlsPolicy
或 serverTlsPolicy
。
准备设置
无代理服务网格 (PSM) 安全性为根据无代理 gRPC 服务文档设置的负载均衡服务网格增加了安全性。在无代理服务网格中,gRPC 客户端在 URI 中使用架构 xds:
来访问服务,这将启用 PSM 负载均衡和端点发现功能。
将 gRPC 客户端和服务器更新为正确的版本
使用您的语言支持的最低 gRPC 版本构建或重建您的应用。
更新引导文件
gRPC 应用使用单个引导文件,该文件必须包含 gRPC 客户端和服务器端代码所需的所有字段。引导生成器会自动生成引导文件,其中包含 PSM 安全所需的标志和值。如需了解详情,请参阅引导文件部分,其中包含示例引导文件。
设置概览
此设置流程是 Cloud Service Mesh 设置 GKE 和无代理 gRPC 服务实现连接。会在适用的位置引用该设置过程的现有未修改步骤。
对使用 GKE 设置 Cloud Service Mesh 的主要改进如下:
- 设置 CA Service,在其中创建私有 CA 池和所需的证书授权机构。
- 创建具有 GKE Workload Identity Federation for GKE 和网格证书功能以及 CA Service 集成的 GKE 集群。
- 在集群上配置网格证书颁发。
- 创建客户端和服务器服务账号。
- 设置示例服务器 (使用 xDS API 和 xDS 服务器凭据) Cloud Service Mesh 中的自定义配置。
- 设置使用 xDS 凭据的示例客户端。
- 更新 Cloud Service Mesh 配置以包含安全配置。
您可以在以下位置查看使用 xDS 凭据的代码示例:
更新 Google Cloud CLI
如需更新 Google Cloud CLI,请运行以下命令:
gcloud components update
设置环境变量
在本指南中,您将使用 Cloud Shell 命令,命令中的重复信息由各种环境变量表示。在执行命令之前,将 Shell 环境中的以下环境变量设置为您的特定值。每个注释行说明关联的环境变量的含义。
# Your project ID PROJECT_ID=YOUR_PROJECT_ID # GKE cluster name and zone for this example. CLUSTER_NAME="secure-psm-cluster" ZONE="us-east1-d" # GKE cluster URL derived from the above GKE_CLUSTER_URL="https://container.googleapis.com/v1/projects/${PROJECT_ID}/locations/${ZONE}/clusters/${CLUSTER_NAME}" # Workload pool to be used with the GKE cluster WORKLOAD_POOL="${PROJECT_ID}.svc.id.goog" # Kubernetes namespace to run client and server demo. K8S_NAMESPACE='default' DEMO_BACKEND_SERVICE_NAME='grpc-gke-helloworld-service' # Compute other values # Project number for your project PROJNUM=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)") # VERSION is the GKE cluster version. Install and use the most recent version # from the rapid release channel and substitute its version for # CLUSTER_VERSION, for example: # VERSION=latest available version # Note that the minimum required cluster version is 1.21.4-gke.1801. VERSION="CLUSTER_VERSION" SA_GKE=service-${PROJNUM}@container-engine-robot.iam.gserviceaccount.com
启用对所需 API 的访问权限
此部分介绍如何启用对必需的 API 的访问权限。
运行以下命令以启用 Cloud Service Mesh 和其他 API 是实现无代理 gRPC 服务网格安全性的必要条件。
gcloud services enable \ container.googleapis.com \ cloudresourcemanager.googleapis.com \ compute.googleapis.com \ trafficdirector.googleapis.com \ networkservices.googleapis.com \ networksecurity.googleapis.com \ privateca.googleapis.com \ gkehub.googleapis.com
运行以下命令以允许默认服务账号访问 Cloud Service Mesh Security API。
GSA_EMAIL=$(gcloud iam service-accounts list --format='value(email)' \ --filter='displayName:Compute Engine default service account') gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member serviceAccount:${GSA_EMAIL} \ --role roles/trafficdirector.client
创建或更新 GKE 集群
Cloud Service Mesh 服务安全性取决于 CA Service 与 GKE 集成除了设置要求之外,GKE 集群还必须满足以下要求:
- 使用的最低集群版本为 1.21.4-gke.1801。如果您需要更高版本的功能,则可以从快速发布渠道中获取该版本。
- 必须使用网格证书启用和配置 GKE 集群,如创建证书授权机构以颁发证书中所述。
创建使用适用于 GKE 的工作负载身份联合的新集群。如果您要更新现有集群,请跳至下一步。您为“
--tags
”指定的值 必须与传递给--target-tags
标志的 部分中的firewall-rules create
命令 使用 Cloud Load Balancing 组件配置 Cloud Service Mesh。# Create a GKE cluster with GKE managed mesh certificates. gcloud container clusters create CLUSTER_NAME \ --release-channel=rapid \ --scopes=cloud-platform \ --image-type=cos_containerd \ --machine-type=e2-standard-2 \ --zone=ZONE \ --workload-pool=PROJECT_ID.svc.id.goog \ --enable-mesh-certificates \ --cluster-version=CLUSTER_VERSION \ --enable-ip-alias \ --tags=allow-health-checks \ --workload-metadata=GKE_METADATA
集群创建可能需要几分钟才能完成。
如果您使用的是现有集群,请启用适用于 GKE 的工作负载身份联合,并 GKE 网格证书。确保使用
--enable-ip-alias
标志创建集群,该标志无法与update
命令一起使用。gcloud container clusters update CLUSTER_NAME \ --enable-mesh-certificates
运行以下命令切换到作为
kubectl
命令的默认集群的新集群:gcloud container clusters get-credentials CLUSTER_NAME \ --zone ZONE
向舰队注册集群
向舰队注册您在创建 GKE 集群中创建或更新的集群。通过注册集群,您可以更轻松地跨多个项目配置集群。
请注意,每个步骤最长可能需要十分钟才能完成。
向舰队注册集群:
gcloud container fleet memberships register CLUSTER_NAME \ --gke-cluster=ZONE/CLUSTER_NAME \ --enable-workload-identity --install-connect-agent \ --manifest-output-file=MANIFEST-FILE_NAME
替换如下变量:
- CLUSTER_NAME:您的集群的名称。
- ZONE:您的集群的可用区。
- MANIFEST-FILE_NAME:这些命令生成注册清单的路径。
注册成功后,您会看到如下消息:
Finished registering the cluster CLUSTER_NAME with the fleet.
将生成的清单文件应用于您的集群:
kubectl apply -f MANIFEST-FILE_NAME
应用成功后,您会看到如下消息:
namespace/gke-connect created serviceaccount/connect-agent-sa created podsecuritypolicy.policy/gkeconnect-psp created role.rbac.authorization.k8s.io/gkeconnect-psp:role created rolebinding.rbac.authorization.k8s.io/gkeconnect-psp:rolebinding created role.rbac.authorization.k8s.io/agent-updater created rolebinding.rbac.authorization.k8s.io/agent-updater created role.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created clusterrole.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created clusterrolebinding.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created clusterrolebinding.rbac.authorization.k8s.io/gke-connect-feature-authorizer-20210416-01-00 created rolebinding.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created role.rbac.authorization.k8s.io/gke-connect-namespace-getter created rolebinding.rbac.authorization.k8s.io/gke-connect-namespace-getter created secret/http-proxy created deployment.apps/gke-connect-agent-20210416-01-00 created service/gke-connect-monitoring created secret/creds-gcp create
从集群获取成员资格资源:
kubectl get memberships membership -o yaml
输出应包含由舰队分配的 Workoad Identity 池,其中 PROJECT_ID 是您的项目 ID:
workload_identity_pool: PROJECT_ID.svc.id.goog
这表示集群已成功注册。
创建证书授权机构以颁发证书
如需向 Pod 颁发证书,请创建 CA 服务池和以下证书授权机构 (CA):
- 根 CA。这是所有已颁发的网格证书的信任根。可以使用现有的根 CA。在
enterprise
层级创建根 CA,用于颁发长期、少量的证书。 - 从属 CA。此 CA 会为工作负载颁发证书。请在部署集群的区域中创建从属 CA。在
devops
层级创建从属 CA,用于颁发短期、大量的证书。
创建从属 CA 是可选操作,但我们强烈建议您创建一个,而不是使用根 CA 颁发 GKE 网格证书。如果您决定使用根 CA 颁发网格证书,请确保允许使用默认的基于配置的颁发模式。
从属 CA 的区域可以不同于集群的区域,但我们强烈建议您在集群所在的区域中创建从属 CA 以优化性能。但是,您可以在不同区域中创建根 CA 和从属 CA,这不会影响性能或可用性。
CA Service 支持以下区域:
区域名称 | 区域说明 |
---|---|
asia-east1 |
台湾 |
asia-east2 |
香港 |
asia-northeast1 |
东京 |
asia-northeast2 |
大阪 |
asia-northeast3 |
首尔 |
asia-south1 |
孟买 |
asia-south2 |
德里 |
asia-southeast1 |
新加坡 |
asia-southeast2 |
雅加达 |
australia-southeast1 |
悉尼 |
australia-southeast2 |
墨尔本 |
europe-central2 |
华沙 |
europe-north1 |
芬兰 |
europe-southwest1 |
马德里 |
europe-west1 |
比利时 |
europe-west2 |
伦敦 |
europe-west3 |
法兰克福 |
europe-west4 |
荷兰 |
europe-west6 |
苏黎世 |
europe-west8 |
米兰 |
europe-west9 |
巴黎 |
europe-west10 |
柏林 |
europe-west12 |
都灵 |
me-central1 |
多哈 |
me-central2 |
达曼 |
me-west1 |
特拉维夫 |
northamerica-northeast1 |
蒙特利尔 |
northamerica-northeast2 |
多伦多 |
southamerica-east1 |
圣保罗 |
southamerica-west1 |
圣地亚哥 |
us-central1 |
爱荷华 |
us-east1 |
南卡罗来纳 |
us-east4 |
北弗吉尼亚 |
us-east5 |
哥伦布 |
us-south1 |
达拉斯 |
us-west1 |
俄勒冈 |
us-west2 |
洛杉矶 |
us-west3 |
盐湖城 |
us-west4 |
拉斯维加斯 |
此外,还可以通过运行以下命令来查看受支持位置的列表:
gcloud privateca locations list
将 IAM
roles/privateca.caManager
授予创建 CA 池和 CA 的个人。请注意,对于 MEMBER,正确格式为user:userid@example.com
。如果该人员是当前用户,您可以使用 shell 命令$(gcloud auth list --filter=status:ACTIVE --format="value(account)")
获取当前用户 ID。gcloud projects add-iam-policy-binding PROJECT_ID \ --member=MEMBER \ --role=roles/privateca.caManager
将 CA 角色
role/privateca.admin
授予需要修改 IAM 政策的个人,其中MEMBER
是需要此访问权限的个人,具体而言是执行以下步骤的个人这些角色可授予privateca.auditor
和privateca.certificateManager
角色:gcloud projects add-iam-policy-binding PROJECT_ID \ --member=MEMBER \ --role=roles/privateca.admin
创建根 CA 服务池。
gcloud privateca pools create ROOT_CA_POOL_NAME \ --location ROOT_CA_POOL_LOCATION \ --tier enterprise
创建根 CA。
gcloud privateca roots create ROOT_CA_NAME --pool ROOT_CA_POOL_NAME \ --subject "CN=ROOT_CA_NAME, O=ROOT_CA_ORGANIZATION" \ --key-algorithm="ec-p256-sha256" \ --max-chain-length=1 \ --location ROOT_CA_POOL_LOCATION
对于此演示设置,请为变量使用以下值:
- ROOT_CA_POOL_NAME=td_sec_pool
- ROOT_CA_NAME=pkcs2-ca
- ROOT_CA_POOL_LOCATION=us-east1
- ROOT_CA_ORGANIZATION="TestCorpLLC"
创建从属池和从属 CA。确保允许使用默认的基于配置的颁发模式。
gcloud privateca pools create SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --tier devops
gcloud privateca subordinates create SUBORDINATE_CA_NAME \ --pool SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --issuer-pool ROOT_CA_POOL_NAME \ --issuer-location ROOT_CA_POOL_LOCATION \ --subject "CN=SUBORDINATE_CA_NAME, O=SUBORDINATE_CA_ORGANIZATION" \ --key-algorithm "ec-p256-sha256" \ --use-preset-profile subordinate_mtls_pathlen_0
对于此演示设置,请为变量使用以下值:
- SUBORDINATE_CA_POOL_NAME="td-ca-pool"
- SUBORDINATE_CA_POOL_LOCATION=us-east1
- SUBORDINATE_CA_NAME="td-ca"
- SUBORDINATE_CA_ORGANIZATION="TestCorpLLC"
- ROOT_CA_POOL_NAME=td_sec_pool
- ROOT_CA_POOL_LOCATION=us-east1
授予根 CA 池 IAM
privateca.auditor
角色,以允许从 GKE 服务账号进行访问:gcloud privateca pools add-iam-policy-binding ROOT_CA_POOL_NAME \ --location ROOT_CA_POOL_LOCATION \ --role roles/privateca.auditor \ --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
授予从属 CA 池 IAM
privateca.certificateManager
角色,以允许从 GKE 服务账号进行访问:gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --role roles/privateca.certificateManager \ --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
保存以下
WorkloadCertificateConfig
YAML 配置,以告知集群如何颁发网格证书:apiVersion: security.cloud.google.com/v1 kind: WorkloadCertificateConfig metadata: name: default spec: # Required. The CA service that issues your certificates. certificateAuthorityConfig: certificateAuthorityServiceConfig: endpointURI: ISSUING_CA_POOL_URI # Required. The key algorithm to use. Choice of RSA or ECDSA. # # To maximize compatibility with various TLS stacks, your workloads # should use keys of the same family as your root and subordinate CAs. # # To use RSA, specify configuration such as: # keyAlgorithm: # rsa: # modulusSize: 4096 # # Currently, the only supported ECDSA curves are "P256" and "P384", and the only # supported RSA modulus sizes are 2048, 3072 and 4096. keyAlgorithm: rsa: modulusSize: 4096 # Optional. Validity duration of issued certificates, in seconds. # # Defaults to 86400 (1 day) if not specified. validityDurationSeconds: 86400 # Optional. Try to start rotating the certificate once this # percentage of validityDurationSeconds is remaining. # # Defaults to 50 if not specified. rotationWindowPercentage: 50
替换以下内容:
- 运行您的集群的项目的 ID:
PROJECT_ID
- 颁发网格证书的 CA 的完全限定 URI (ISSUING_CA_POOL_URI)。这可以是从属 CA(推荐)也可以是根 CA。格式为:
//privateca.googleapis.com/projects/PROJECT_ID/locations/SUBORDINATE_CA_POOL_LOCATION/caPools/SUBORDINATE_CA_POOL_NAME
- 运行您的集群的项目的 ID:
保存以下
TrustConfig
YAML 配置,以告知集群如何信任颁发的证书:apiVersion: security.cloud.google.com/v1 kind: TrustConfig metadata: name: default spec: # You must include a trustStores entry for the trust domain that # your cluster is enrolled in. trustStores: - trustDomain: PROJECT_ID.svc.id.goog # Trust identities in this trustDomain if they appear in a certificate # that chains up to this root CA. trustAnchors: - certificateAuthorityServiceURI: ROOT_CA_POOL_URI
替换以下内容:
- 运行您的集群的项目的 ID:
PROJECT_ID
- 根 CA 池的完全限定 URI (ROOT_CA_POOL_URI)。格式为:
//privateca.googleapis.com/projects/PROJECT_ID/locations/ROOT_CA_POOL_LOCATION/caPools/ROOT_CA_POOL_NAME
- 运行您的集群的项目的 ID:
将配置应用到您的集群:
kubectl apply -f WorkloadCertificateConfig.yaml kubectl apply -f TrustConfig.yaml
使用 NEG 创建无代理 gRPC 服务
为实现 PSM 安全机制,您需要一个能够使用 xDS 从 Cloud Service Mesh 获取安全配置的无代理 gRPC 服务器。此步骤类似于 PSM 负载均衡设置指南中的使用 NEG 配置 GKE 服务,但您使用 grpc-java
代码库的 xDS 示例中启用 xDS 的 helloworld
服务器,而不是 java-example-hostname
映像。
在通过 openjdk:8-jdk
映像构建的容器中构建和运行此服务器。您还可以使用命名 NEG 功能,为 NEG 指定名称。这可以简化后续步骤,因为部署知道 NEG 的名称,从而无需进行查找。
以下是 gRPC 服务器 Kubernetes 规范的完整示例。请注意以下事项:
- 此规范创建一个由 gRPC 服务器 pod 使用的 Kubernetes 服务账号
example-grpc-server
。 - 此规范使用服务的
cloud.google.com/neg
注释中的name
字段指定 NEG 名称example-grpc-server
。 - 变量
${PROJNUM}
表示您的项目的项目编号。 - 此规范使用
initContainers
部分运行引导生成器,以填充无代理 gRPC 库所需的引导文件。此引导文件位于名为example-grpc-server
的 gRPC 服务器容器中的/tmp/grpc-xds/td-grpc-bootstrap.json
。
将以下注释添加到 pod 规范:
annotations: security.cloud.google.com/use-workload-certificates: ""
您可以在下面的完整规范中看到正确的显示位置。
创建后,每个 pod 都会获得一个位于 /var/run/secrets/workload-spiffe-credentials
的卷。此卷包含以下内容:
private_key.pem
是自动生成的私钥。certificates.pem
是一组 PEM 格式的证书,可作为客户端证书链提供给其他 pod,也可以用作服务器证书链。ca_certificates.pem
是一组 PEM 格式的证书,在验证其他 pod 提供的客户端证书链或连接到其他 pod 时收到的服务器证书链时用作信任锚。
请注意,ca_certificates.pem
包含工作负载的本地信任网域(即集群的工作负载池)的证书。
certificates.pem
中的叶证书包含以下纯文本 SPIFFE 身份断言:
spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT
在此断言中:
- WORKLOAD_POOL 是集群工作负载池的名称。
- NAMESPACE 是您的 Kubernetes 服务账号的命名空间。
- KUBERNETES_SERVICE_ACCOUNT 是您的 Kubernetes 服务账号名称。
以下针对您的语言的说明创建了要在此示例中使用的规范。
Java
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建规范:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: openjdk:8-jdk imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 800m memory: 512Mi requests: cpu: 100m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
C++
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建规范:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Python
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建规范:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Go
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建规范:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: golang:1.16-alpine imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
请按以下方式完成此过程。
应用规范:
kubectl apply -f example-grpc-server.yaml
向服务账号授予所需角色:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \ ${PROJNUM}-compute@developer.gserviceaccount.com gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \ --role roles/trafficdirector.client
运行以下命令验证服务和 Pod 是否已正确创建:
kubectl get deploy/example-grpc-server kubectl get svc/example-grpc-server
验证 NEG 名称正确无误:
gcloud compute network-endpoint-groups list \ --filter "name=example-grpc-server" --format "value(name)"
上一个命令应返回 NEG 名称
example-grpc-server
。
使用 Google Cloud 负载均衡组件配置 Cloud Service Mesh
本部分中的步骤与 使用负载均衡组件配置 Cloud Service Mesh, 但有一些变化,如以下部分所述。
创建健康检查、防火墙规则和后端服务
gRPC 服务器配置为使用 mTLS 时,gRPC 健康检查将不起作用,因为健康检查客户端无法向服务器提供有效的客户端证书。您可以通过以下两种方法之一来解决此问题:
在第一种方法中,您使服务器创建一个额外的服务端口,它被指定为健康检查端口。该端口连接到一个特殊健康检查服务,它以纯文本或 TLS 形式访问该端口。
xDS helloworld
示例服务器
使用 PORT_NUMBER
+ 1 作为纯文本健康检查端口。该示例使用 50052 作为健康检查端口,因为 50051 是 gRPC 应用服务器端口。
在第二种方法中,您将健康检查配置为仅检查到应用服务端口的 TCP 连接性。此方法仅检查连接性,并且当 TLS 握手失败时,会产生到服务器的不必要流量。因此,我们建议您使用第一种方法。
创建健康检查。 请注意,只有创建并启动服务器后,健康检查才会启动。
如果要为健康检查创建指定的服务端口,即我们推荐的方法,请使用以下命令:
gcloud compute health-checks create grpc grpc-gke-helloworld-hc \ --enable-logging --port 50052
如果您要创建 TCP 健康检查(我们不建议这样做),请使用 此命令:
gcloud compute health-checks create tcp grpc-gke-helloworld-hc \ --use-serving-port
创建防火墙。确保
--target-tags
的值与您在创建或更新 GKE 集群部分中为--tags
提供的值匹配。gcloud compute firewall-rules create grpc-gke-allow-health-checks \ --network default --action allow --direction INGRESS \ --source-ranges 35.191.0.0/16,130.211.0.0/22 \ --target-tags allow-health-checks \ --rules tcp:50051-50052
创建后端服务:
gcloud compute backend-services create grpc-gke-helloworld-service \ --global \ --load-balancing-scheme=INTERNAL_SELF_MANAGED \ --protocol=GRPC \ --health-checks grpc-gke-helloworld-hc
将 NEG 附加到后端服务:
gcloud compute backend-services add-backend grpc-gke-helloworld-service \ --global \ --network-endpoint-group example-grpc-server \ --network-endpoint-group-zone ${ZONE} \ --balancing-mode RATE \ --max-rate-per-endpoint 5
创建路由规则映射
这与您在 Google Cloud 控制台中创建路由规则映射的方式类似。 使用 Google Kubernetes Engine 和无代理 gRPC 服务设置 Cloud Service Mesh。
创建网址映射:
gcloud compute url-maps create grpc-gke-url-map \ --default-service grpc-gke-helloworld-service
向网址映射添加路径匹配器:
gcloud compute url-maps add-path-matcher grpc-gke-url-map \ --default-service grpc-gke-helloworld-service \ --path-matcher-name grpc-gke-path-matcher \ --new-hosts helloworld-gke:8000
创建目标 gRPC 代理:
gcloud compute target-grpc-proxies create grpc-gke-proxy \ --url-map grpc-gke-url-map --validate-for-proxyless
创建转发规则:
gcloud compute forwarding-rules create grpc-gke-forwarding-rule \ --global \ --load-balancing-scheme=INTERNAL_SELF_MANAGED \ --address=0.0.0.0 \ --target-grpc-proxy=grpc-gke-proxy \ --ports 8000 \ --network default
使用无代理 gRPC 安全性配置 Cloud Service Mesh
此示例演示了如何在客户端和服务器端配置 mTLS。
政策引用的格式
请注意引用服务器 TLS 和客户端 TLS 政策的以下所需格式:
projects/PROJECT_ID/locations/global/[serverTlsPolicies|clientTlsPolicies]/[server-tls-policy|client-mtls-policy]
例如:
projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy
在服务器端配置 mTLS
首先,您需要创建服务器 TLS 政策。此政策要求 gRPC 服务器端为身份证书使用由名称 google_cloud_private_spiffe
标识的 certificateProvicerInstance
插件配置,这是 serverCertificate
的一部分。mtlsPolicy
部分指示 mTLS 安全,并使用与 clientValidationCa
的插件配置相同的 google_cloud_private_spiffe
,后者是根(验证)证书规范。
接下来,您需要创建端点政策。此政策指定后端(例如 gRPC 服务器)使用 50051
端口以及任何元数据标签或者不使用元数据标签,接收名为 server-mtls-policy
的附加服务器 TLS 政策。您可以使用 MATCH_ALL
指定元数据标签。您可以使用您已定义的政策和包含端点政策资源的值的临时文件 ep-mtls-psms.yaml
创建端点政策。
使用服务器 TLS 政策资源的值在当前目录中创建临时文件
server-mtls-policy.yaml
:name: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-mtls-policy" serverCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe mtlsPolicy: clientValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffe
通过导入临时文件
server-mtls-policy.yaml
创建名为server-mtls-policy
的服务器 TLS 政策资源:gcloud network-security server-tls-policies import server-mtls-policy \ --source=server-mtls-policy.yaml --location=global
通过创建临时文件
ep-mtls-psms.yaml
创建端点政策:name: "ep-mtls-psms" type: "GRPC_SERVER" serverTlsPolicy: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-mtls-policy" trafficPortSelector: ports: - "50051" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: "MATCH_ALL" metadataLabels: - labelName: app labelValue: helloworld
通过导入
ep-mtls-psms.yaml
文件来创建端点政策资源:gcloud beta network-services endpoint-policies import ep-mtls-psms \ --source=ep-mtls-psms.yaml --location=global
在客户端配置 mTLS
客户端安全政策附加到后端服务。当客户端通过后端服务访问后端(gRPC 服务器)时,附加的客户端安全政策会被发送到客户端。
在名为 的临时文件中创建客户端 TLS 政策资源内容
client-mtls-policy.yaml
:name: "client-mtls-policy" clientCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe serverValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffe
通过导入临时文件
client-mtls-policy.yaml
创建名为client-mtls-policy
的客户端 TLS 政策资源:gcloud network-security client-tls-policies import client-mtls-policy \ --source=client-mtls-policy.yaml --location=global
在临时文件中创建一个代码段来引用此政策,并在
SecuritySettings
消息中添加subjectAltNames
的详细信息,如以下示例所示。将${PROJECT_ID}
替换为您的项目 ID 值,即 之前描述的${PROJECT_ID}
环境变量的值。请注意,subjectAltNames
中的example-grpc-server
是部署规范中用于 gRPC 服务器 pod 的 Kubernetes 服务账号名称。if [ -z "$PROJECT_ID" ] ; then echo Please make sure PROJECT_ID is set. ; fi cat << EOF > client-security-settings.yaml securitySettings: clientTlsPolicy: projects/${PROJECT_ID}/locations/global/clientTlsPolicies/client-mtls-policy subjectAltNames: - "spiffe://${PROJECT_ID}.svc.id.goog/ns/default/sa/example-grpc-server" EOF
将
securitySettings
消息添加到您已创建的后端服务中。这些步骤会导出当前后端服务内容,添加客户端securitySetting
消息并重新导入新内容以更新后端服务。gcloud compute backend-services export grpc-gke-helloworld-service --global \ --destination=/tmp/grpc-gke-helloworld-service.yaml cat /tmp/grpc-gke-helloworld-service.yaml client-security-settings.yaml \ >/tmp/grpc-gke-helloworld-service1.yaml gcloud compute backend-services import grpc-gke-helloworld-service --global \ --source=/tmp/grpc-gke-helloworld-service1.yaml -q
验证配置
Cloud Service Mesh 配置现已完成,包括服务器和 客户端安全性接下来,准备并运行服务器和客户端工作负载。这样就完成了示例。
创建无代理 gRPC 客户端
此步骤类似于上一部分创建无代理 gRPC 服务。
您使用 grpc-java
代码库的 xDS 示例目录中启用 xDS 的 helloworld
客户端。在通过 openjdk:8-jdk
映像构建的容器中构建和运行客户端。gRPC 客户端 Kubernetes 规范
关注。
- 它会创建一个供 gRPC 客户端 Pod 使用的 Kubernetes 服务账号
example-grpc-client
。 ${PROJNUM}
表示您的项目的项目编号,需要替换为实际编号。
将以下注释添加到 pod 规范:
annotations: security.cloud.google.com/use-workload-certificates: ""
创建后,每个 pod 都会获得一个位于 /var/run/secrets/workload-spiffe-credentials
的卷。此卷包含以下内容:
private_key.pem
是自动生成的私钥。certificates.pem
是一组 PEM 格式的证书,可作为客户端证书链提供给其他 pod,也可以用作服务器证书链。ca_certificates.pem
是一组 PEM 格式的证书,在验证其他 pod 提供的客户端证书链或连接到其他 pod 时收到的服务器证书链时用作信任锚。
请注意,ca_certificates.pem
包含工作负载的本地信任网域(即集群的工作负载池)的根证书。
certificates.pem
中的叶证书包含以下纯文本 SPIFFE 身份断言:
spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT
在此断言中:
- WORKLOAD_POOL 是集群工作负载池的名称。
- NAMESPACE 是您的 Kubernetes 服务账号名称。
- KUBERNETES_SERVICE_ACCOUNT 是您的 Kubernetes 服务账号的命名空间。
以下针对您的语言的说明创建了要在此示例中使用的规范。
Java
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建以下规范:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: openjdk:8-jdk imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 800m memory: 512Mi requests: cpu: 100m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
C++
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建以下规范:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Python
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建以下规范:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Go
运行以下命令,确保正确设置了项目编号:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
创建以下规范:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: golang:1.16-alpine imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
请按以下方式完成此过程。
应用规范:
kubectl apply -f example-grpc-client.yaml
向服务账号授予所需角色:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \ ${PROJNUM}-compute@developer.gserviceaccount.com gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \ --role roles/trafficdirector.client
验证客户端 pod 正在运行:
kubectl get pods
该命令会返回类似于以下内容的文本:
NAMESPACE NAME READY STATUS RESTARTS AGE default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 104s [..skip..]
运行服务器
在您之前创建的服务器 pod 中构建并运行启用 xDS 的 helloworld
服务器。
Java
获取为
example-grpc-server
服务创建的 pod 的名称:kubectl get pods | grep example-grpc-server
您会看到如下所示的反馈:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
打开一个连接至服务器 pod 的 shell:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
在 shell 中,验证
/tmp/grpc-xds/td-grpc-bootstrap.json
中的引导文件与引导文件部分中所述的架构匹配。下载 gRPC Java 1.42.1 版并构建
xds-hello-world
服务器应用。curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz cd grpc-java-1.42.1/examples/example-xds ../gradlew --no-daemon installDist
使用
--xds-creds
标志运行服务器,以指示启用 xDS 的安全设置,使用50051
作为侦听端口,xds-server
作为服务器标识名称:./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
服务器从 Cloud Service Mesh 获取必要的配置后,您会看到以下输出:
Listening on port 50051 plain text health service listening on port 50052
C++
获取为
example-grpc-server
服务创建的 pod 的名称:kubectl get pods | grep example-grpc-server
您会看到如下所示的反馈:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
打开一个连接至服务器 pod 的 shell:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
在 shell 中,验证
/tmp/grpc-xds/td-grpc-bootstrap.json
中的引导文件与引导文件部分中所述的架构匹配。下载 gRPC C++ 并构建
xds-hello-world
服务器应用。apt-get update -y && \ apt-get install -y \ build-essential \ clang \ python3 \ python3-dev curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz cd grpc-master tools/bazel build examples/cpp/helloworld:xds_greeter_server
运行服务器,使用
50051
作为侦听端口,xds_greeter_server
作为服务器标识名称:bazel-bin/examples/cpp/helloworld/xds_greeter_server --port=50051 --maintenance_port=50052 --secure
如需不使用凭据运行服务器,您可以指定以下内容:
bazel-bin/examples/cpp/helloworld/xds_greeter_server --nosecure
服务器从 Cloud Service Mesh 获取必要的配置后,您会看到以下输出:
Listening on port 50051 plain text health service listening on port 50052
Python
获取为
example-grpc-server
服务创建的 pod 的名称:kubectl get pods | grep example-grpc-server
您会看到如下所示的反馈:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
打开一个连接至服务器 pod 的 shell:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
在 shell 中,验证
/tmp/grpc-xds/td-grpc-bootstrap.json
中的引导文件与引导文件部分中所述的架构匹配。下载 gRPC Python 1.41.0 版并构建示例应用。
apt-get update -y
apt-get install -y python3 python3-pip
curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz
cd grpc-1.41.x/examples/python/xds/
python3 -m virtualenv venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
使用
--xds-creds
标志运行服务器,以指示启用 xDS 的安全设置,使用50051
作为侦听端口。python3 server.py 50051 --xds-creds
服务器从 Cloud Service Mesh,您将看到以下输出:
2021-05-06 16:10:34,042: INFO Running with xDS Server credentials 2021-05-06 16:10:34,043: INFO Greeter server listening on port 50051 2021-05-06 16:10:34,046: INFO Maintenance server listening on port 50052
Go
获取为
example-grpc-server
服务创建的 pod 的名称:kubectl get pods | grep example-grpc-server
您会看到如下所示的反馈:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
打开一个连接至服务器 pod 的 shell:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
在 shell 中,验证
/tmp/grpc-xds/td-grpc-bootstrap.json
中的引导文件与引导文件部分中所述的架构匹配。下载 gRPC Go 1.41.0 版,并导航到包含
xds-hello-world
服务器应用的目录。apk add curl curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz cd grpc-go-1.42.0/examples/features/xds/server
使用
--xds_creds
标志构建并使用50051
作为侦听端口来运行服务器以指示启用 xDS 的安全性:GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -port 50051
服务器从 Cloud Service Mesh 获取必要的配置后,您会看到以下输出:
Using xDS credentials... Serving GreeterService on 0.0.0.0:50051 and HealthService on 0.0.0.0:50052
健康检查过程需要 3 到 5 分钟,才能显示服务在服务器启动后运行状况良好。
运行客户端并验证该配置
在您之前创建的客户端 pod 中构建并运行启用 xDS 的 helloworld
客户端。
Java
获取客户端 pod 的名称:
kubectl get pods | grep example-grpc-client
您会看到如下所示的反馈:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
打开一个连接至客户端 pod 的 shell:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
在命令 shell 中,下载 gRPC Java 1.42.1 版并构建
xds-hello-world
客户端应用。curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz cd grpc-java-1.42.1/examples/example-xds ../gradlew --no-daemon installDist
使用
--xds-creds
标志运行客户端,以指示启用 xDS 的安全设置、客户端名称和目标连接字符串:./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke:8000
您应该会看到如下所示的输出:
Greeting: Hello xds-client, from xds-server
C++
获取客户端 pod 的名称:
kubectl get pods | grep example-grpc-client
您会看到如下所示的反馈:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
打开一个连接至客户端 pod 的 shell:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
在 shell 中,下载 gRPC C++ 并构建
xds-hello-world
客户端应用。apt-get update -y && \ apt-get install -y \ build-essential \ clang \ python3 \ python3-dev
curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz
cd grpc-master
tools/bazel build examples/cpp/helloworld:xds_greeter_client
使用
--xds-creds
标志运行客户端,以指示启用 xDS 的安全设置、客户端名称和目标连接字符串:bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000
如需不使用凭据运行客户端,请使用以下命令:
bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000 --nosecure
您应该会看到如下所示的输出:
Greeter received: Hello world
Python
获取客户端 pod 的名称:
kubectl get pods | grep example-grpc-client
您会看到如下所示的反馈:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
打开一个连接至客户端 pod 的 shell:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
进入 shell 后,下载 gRPC Python 1.41.0 版并构建示例客户端应用。
apt-get update -y apt-get install -y python3 python3-pip python3 -m pip install virtualenv curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz cd grpc-1.41.x/examples/python/xds/ python3 -m virtualenv venv source venv/bin/activate python3 -m pip install -r requirements.txt
使用
--xds-creds
标志运行客户端,以指示启用 xDS 的安全设置、客户端名称和目标连接字符串:python3 client.py xds:///helloworld-gke:8000 --xds-creds
您应该会看到如下所示的输出:
Greeter client received: Hello you from example-host!
Go
获取客户端 pod 的名称:
kubectl get pods | grep example-grpc-client
您会看到如下所示的反馈:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
打开一个连接至客户端 pod 的 shell:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
进入 shell 后,下载 gRPC Go 1.42.0 版,然后转到包含
xds-hello-world
客户端应用的目录。apk add curl curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz cd grpc-go-1.42.0/examples/features/xds/client
使用
--xds_creds
标志构建并运行客户端,以指示已启用 xDS 的安全性、客户端名称和目标连接字符串:GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke:8000
您应该会看到如下所示的输出:
Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
使用授权政策配置服务级访问权限
授权政策支持需要 gRFC A41 支持。您可以在 github 上找到所需的语言版本
按照以下说明使用授权政策配置服务级层访问权限。在创建授权政策之前,请阅读使用授权限制访问权限中的注意事项。
为了更轻松地验证配置,请创建一个额外的主机名,供客户端用来引用 helloworld-gke
服务。
gcloud compute url-maps add-host-rule grpc-gke-url-map \ --path-matcher-name grpc-gke-path-matcher \ --hosts helloworld-gke-noaccess:8000
以下说明会创建一个授权政策,该政策允许主机名为 helloworld-gke:8000
且端口为 50051
的 example-grpc-client
账号发送请求。
gcloud
通过创建名为
helloworld-gke-authz-policy.yaml
的文件创建授权政策。action: ALLOW name: helloworld-gke-authz-policy rules: - sources: - principals: - spiffe://PROJECT_ID.svc.id.goog/ns/default/sa/example-grpc-client destinations: - hosts: - helloworld-gke:8000 ports: - 50051
导入该政策。
gcloud network-security authorization-policies import \ helloworld-gke-authz-policy \ --source=helloworld-gke-authz-policy.yaml \ --location=global
通过将以下内容附加到文件
ep-mtls-psms.yaml
,将端点政策更新为引用新的授权政策。authorizationPolicy: projects/${PROJECT_ID}/locations/global/authorizationPolicies/helloworld-gke-authz-policy
端点政策现在指定,必须对其 gRPC 引导文件包含
app:helloworld
标签的 Pod 的入站请求强制执行 mTLS 和授权政策。导入政策:
gcloud network-services endpoint-policies import ep-mtls-psms \ --source=ep-mtls-psms.yaml --location=global
验证授权政策
按照以下说明确认授权政策是否正常工作。
Java
打开连接至您之前使用的客户端 pod 的 shell。
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
在命令 shell 中,运行以下命令以验证设置。
cd grpc-java-1.42.1/examples/example-xds ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke:8000
您应该会看到如下所示的输出:
Greeting: Hello xds-client, from xds-server
使用备用服务器名称再次运行客户端。请注意,这是一种失败案例。由于授权政策仅允许访问
helloworld-gke:8000
主机名,因此请求无效。./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke-noaccess:8000
您应该会看到如下所示的输出:
WARNING: RPC failed: Status{code=PERMISSION_DENIED}
如果您没有看到此输出,则表示授权政策可能尚未使用。等待几分钟,然后再次尝试执行整个验证过程。
Go
打开连接至您之前使用的客户端 pod 的 shell。
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
在命令 shell 中,运行以下命令以验证设置。
cd grpc-go-1.42.0/examples/features/xds/client GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke:8000
您应该会看到如下所示的输出:
Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
使用备用服务器名称再次运行客户端。请注意,这是一种失败案例。由于授权政策仅允许访问
helloworld-gke:8000
主机名,因此请求无效。GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke-noaccess:8000
您应该会看到如下所示的输出:
could not greet: rpc error: code = PermissionDenied desc = Incoming RPC is not allowed: rpc error: code = PermissionDenied desc = incoming RPC did not match an allow policy exit status 1
如果您没有看到此输出,则说明授权政策可能未包含在内。 。等待几分钟,然后再次尝试执行整个验证过程。
使用 TLS 而非 mTLS
在本示例中使用 TLS 只需稍做更改即可。
在
ServerTlsPolicy
中,删除mtlsPolicy
:cat << EOF > server-tls-policy.yaml name: "server-tls-policy" serverCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe EOF
在
EndpointPolicy
中改为使用此政策:cat << EOF > ep-tls-psms.yaml name: "ep-mtls-psms" type: "GRPC_SERVER" serverTlsPolicy: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-tls-policy" trafficPortSelector: ports: - "50051" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: "MATCH_ALL" metadataLabels: [] EOF
mTLS 的
ClientTlsPolicy
也适用于 TLS 的情况,但政策的clientCertificate
部分可以删除,因为 TLS 不需要该部分:cat << EOF > client-tls-policy.yaml name: "client-tls-policy" serverValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffe EOF
将服务安全性和 Wallet 示例结合使用
本部分简要介绍了如何为 Java、C++ 和 Go 启用服务安全性和 Wallet 示例。
Java
您可以在 github 中找到 Java 的示例源代码。当您配置无代理安全性时,代码已使用 XdsChannel
和 XdsServer
凭据。
以下说明介绍了如何使用 Go 配置 Wallet 示例。此过程与 Java 类似。这些说明使用从 Google Cloud 容器代码库获取的已有 Docker 映像。
如需创建此示例,请按照以下说明操作:
- 克隆代码库并获取 gRPC 示例目录中的文件。
- 修改文件
00-common-env.sh
。注释掉将WALLET_DOCKER_IMAGE
的值设置为 Go Docker 映像的现有行,并取消注释将WALLET_DOCKER_IMAGE
的值设置为 Java Docker 映像的行。 - 按照创建和配置 Cloud Router 实例中的说明,或使用脚本
10.apis.sh
中的函数create_cloud_router_instances
创建和配置 Cloud Router 实例。 - 使用
hello world
示例说明或脚本20-cluster.sh
中的函数create_cluster
创建集群。 - 按照 CA 服务说明或使用脚本
30-private-ca-setup.sh
创建私有证书授权机构。 - 使用脚本
40-k8s-resources.sh
为所有服务创建 Kubernetes 资源,包括服务账号、命名空间、Kubernetes 服务、NEG 和服务器端部署:account
、stats
、stats_premium
、wallet_v1
、wallet_v2
。 - 对于您创建的每项服务,请使用脚本
50-td-components.sh
中的create_health_check
和create_backend_service
创建健康检查和后端服务。 - 使用以下命令创建 Cloud Service Mesh 路由组件
脚本
60-routing-components.sh
中的create_routing_components
。 - 为每个后端服务创建 Cloud Service Mesh 安全组件
在脚本
70-security-components.sh
中使用create_security_components
。 - 使用脚本
75-client-deployment.sh
中的create_client_deployment
创建 Wallet 客户端部署。 - 按照使用 grpc-钱包客户端验证中的说明启动客户端,验证配置。
C++
您可以在 github 找到 C++ 的示例源代码。当您配置无代理安全性时,代码已使用 XdsChannel
和 XdsServer
凭据。
以下说明介绍了如何使用 Go 配置 Wallet 示例。此过程与 C++ 类似。这些说明使用从 Google Cloud 容器代码库获取的现有 Docker 映像。
如需创建此示例,请按照以下说明操作:
- 克隆代码库并获取 gRPC 示例目录中的文件。
- 修改文件
00-common-env.sh
。注释掉将WALLET_DOCKER_IMAGE
的值设置为 Go Docker 映像的现有行,并取消注释将WALLET_DOCKER_IMAGE
的值设置为 C++ Docker 映像的行。 - 按照创建和配置 Cloud Router 实例中的说明,或使用脚本
10.apis.sh
中的函数create_cloud_router_instances
创建和配置 Cloud Router 实例。 - 使用
hello world
示例说明或脚本20-cluster.sh
中的函数create_cluster
创建集群。 - 按照 CA 服务说明或使用脚本
30-private-ca-setup.sh
创建私有证书授权机构。 - 使用脚本
40-k8s-resources.sh
为所有服务创建 Kubernetes 资源,包括服务账号、命名空间、Kubernetes 服务、NEG 和服务器端部署:account
、stats
、stats_premium
、wallet_v1
、wallet_v2
。 - 对于您创建的每项服务,请使用脚本
50-td-components.sh
中的create_health_check
和create_backend_service
创建健康检查和后端服务。 - 使用以下命令创建 Cloud Service Mesh 路由组件
脚本
60-routing-components.sh
中的create_routing_components
。 - 为每个后端服务创建 Cloud Service Mesh 安全组件
在脚本
70-security-components.sh
中使用create_security_components
。 - 使用脚本
75-client-deployment.sh
中的create_client_deployment
创建 Wallet 客户端部署。 - 按照使用 grpc-钱包客户端验证中的说明启动客户端,验证配置。
Go
您可以在 github 找到 Go 的示例源代码。当您配置无代理安全性时,代码已使用 XdsChannel
和 XdsServer
凭据。
这些说明使用从 Google Cloud 容器代码库获取的已有 Docker 映像。
如需创建此示例,请按照以下说明操作:
- 克隆代码库并获取 gRPC 示例目录中的文件。
- 修改文件
00-common-env.sh
以正确设置环境变量的值。 - 按照创建和配置 Cloud Router 实例中的说明,或使用脚本
10.apis.sh
中的函数create_cloud_router_instances
创建和配置 Cloud Router 实例。 - 使用
hello world
示例说明或脚本20-cluster.sh
中的函数create_cluster
创建集群。 - 按照 CA 服务说明或使用脚本
30-private-ca-setup.sh
创建私有证书授权机构。 - 使用脚本
40-k8s-resources.sh
为所有服务创建 Kubernetes 资源,包括服务账号、命名空间、Kubernetes 服务、NEG 和服务器端部署:account
、stats
、stats_premium
、wallet_v1
、wallet_v2
。 - 对于您创建的每项服务,请使用脚本
50-td-components.sh
中的create_health_check
和create_backend_service
创建健康检查和后端服务。 - 使用以下命令创建 Cloud Service Mesh 路由组件
脚本
60-routing-components.sh
中的create_routing_components
。 - 为每个后端服务创建 Cloud Service Mesh 安全组件
在脚本
70-security-components.sh
中使用create_security_components
。 - 使用脚本
75-client-deployment.sh
中的create_client_deployment
创建 Wallet 客户端部署。 - 按照使用 grpc-钱包客户端验证中的说明启动客户端,验证配置。
引导文件
本指南中的设置过程使用引导生成器来创建所需的引导文件。本部分提供有关引导文件本身的参考信息。
引导文件包含无代理 gRPC 代码所需的配置信息,包括 xDS 服务器的连接信息。引导文件包含无代理 gRPC 安全功能所需的安全配置。gRPC 服务器需要一个额外的字段,如 后续部分。引导加载程序文件示例如下所示:
{ "xds_servers": [ { "server_uri": "trafficdirector.googleapis.com:443", "channel_creds": [ { "type": "google_default" } ], "server_features": [ "xds_v3" ] } ], "node": { "cluster": "cluster", "id": "projects/9876012345/networks/default/nodes/client1", "metadata": { "TRAFFICDIRECTOR_GCP_PROJECT_NUMBER": "9876012345", "TRAFFICDIRECTOR_NETWORK_NAME": "default", "INSTANCE_IP": "10.0.0.3" }, "locality": { "zone": "us-central1-a" } }, "server_listener_resource_name_template": "grpc/server?xds.resource.listening_address=%s", "certificate_providers": { "google_cloud_private_spiffe": { "plugin_name": "file_watcher", "config": { "certificate_file": "/var/run/secrets/workload-spiffe-credentials/certificates.pem", "private_key_file": "/var/run/secrets/workload-spiffe-credentials/private_key.pem", "ca_certificate_file": "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem", "refresh_interval": "600s" } } } }
针对安全服务的引导文件更新
以下字段反映了与安全和 xDS v3 用法相关的修改:
node
内的 id
字段向 Cloud Service Mesh 提供 gRPC 客户端的唯一身份。您必须按以下格式使用节点 ID 提供 Google Cloud 项目编号和网络名称:
projects/{project number}/networks/{network name}/nodes/[UNIQUE_ID]
以下是使用项目编号 1234 和默认网络的示例:
projects/1234/networks/default/nodes/client1
INSTANCE_IP
字段是 pod 的 IP 地址,或者为 0.0.0.0
,表示 INADDR_ANY
。gRPC 服务器使用此字段从 Cloud Service Mesh 提取监听器资源,用于服务器端安全设置。
引导文件中的安全配置字段
JSON 键 | 类型 | 值 | 备注 |
---|---|---|---|
server_listener_resource_name_template |
字符串 | grpc/server?xds.resource.listening_address=%s |
对于 gRPC 服务器而言是必需的。gRPC 使用此值构成资源名称,从 Cloud Service Mesh 提取“Listener”资源,以实现服务器端安全性和其他配置。gRPC 使用它来构建资源名称字符串 |
certificate_providers |
JSON struct | google_cloud_private_spiffe |
必需。此值是一个 JSON struct,表示名称与证书提供商实例的映射。证书提供商实例用于提取身份和根证书。示例引导文件包含名称 google_cloud_private_spiffe ,其值为证书提供商实例 JSON struct。每个证书提供商实例 JSON struct 都有两个字段:
|
file_watcher
插件的 config
JSON 结构的内容如下:
certificate_file
:必需的字符串。此值是身份证书的位置。private_key_file
:必需的字符串。此值是私钥文件的位置,应与身份证书匹配。ca_certificate_file
:必需的字符串。此值是根证书(也称为信任软件包)的位置。refresh_interval
:可选字符串。此值表示使用“时长”的 JSON 映射的字符串表示形式指定的刷新间隔。默认值为“600s”,即 10 分钟的时长。
引导生成器
您可从 gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
获取引导生成器容器映像,其源代码是
可在 https://github.com/GoogleCloudPlatform/traffic-director-grpc-bootstrap
找到。
最常用的命令行选项包括:
--output
:使用此选项指定输出引导文件的写入位置,例如,--output /tmp/bootstrap/td-grpc-bootstrap.json
命令将引导文件生成到 pod 的文件系统中的/tmp/bootstrap/td-grpc-bootstrap.json
。--node-metadata
:使用此标志在引导文件中填充节点元数据。在EndpointPolicy
(Cloud Service Mesh 在其中使用标签数据) (在引导文件的节点元数据部分提供)。此参数以 key=value 格式提供,例如:--node-metadata version=prod --node-metadata type=grpc
这些选项会在引导文件的节点元数据部分中添加以下内容:
{ "node": { ... "metadata": { "version": "prod", "type": "grpc", ... }, ... }, ... }
删除部署
您可以选择运行这些命令,删除使用本指南创建的部署。
如需删除集群,请运行以下命令:
gcloud container clusters delete CLUSTER_NAME --zone ZONE --quiet
如需删除您创建的资源,请运行以下命令:
gcloud compute backend-services delete grpc-gke-helloworld-service --global --quiet cloud compute network-endpoint-groups delete example-grpc-server --zone ZONE --quiet gcloud compute firewall-rules delete grpc-gke-allow-health-checks --quiet gcloud compute health-checks delete grpc-gke-helloworld-hc --quiet gcloud network-services endpoint-policies delete ep-mtls-psms \ --location=global --quiet gcloud network-security authorization-policies delete helloworld-gke-authz-policy \ --location=global --quiet gcloud network-security client-tls-policies delete client-mtls-policy \ --location=global --quiet gcloud network-security server-tls-policies delete server-tls-policy \ --location=global --quiet gcloud network-security server-tls-policies delete server-mtls-policy \ --location=global --quiet
问题排查
以下说明可帮助您解决安全部署问题。
工作负载无法从 Cloud Service Mesh 获取配置
如果您看到类似以下内容的错误:
PERMISSION_DENIED: Request had insufficient authentication scopes.
为此,您需要确保实现以下各项安排:
- 使用参数
--scopes=cloud-platform
创建了 GKE 集群。 - 已将
roles/trafficdirector.client
分配给 Kuberneters 服务账号。 - 已将
roles/trafficdirector.client
分配给默认 Google Cloud 服务账号(上文的 ${GSA_EMAIL})。 - 启用了
trafficdirector.googleapis.com
服务 (API)。
即使 Cloud Service Mesh 配置正确,gRPC 服务器也不使用 TLS 或 mTLS
请务必在端点政策配置中指定 GRPC_SERVER
。如果指定 SIDECAR_PROXY
,gRPC 会忽略配置。
无法使用所请求的集群版本创建 GKE 集群
GKE 集群创建命令可能失败,并显示如下错误:
Node version "1.20.5-gke.2000" is unsupported.
请确保在集群创建命令中使用了 --release-channel rapid
参数。您需要使用快速发布版本来获得此版本的正确版本。
显示 No usable endpoint
错误
如果客户端因 No usable endpoint
错误而无法与服务器通信,健康检查程序可能已将服务器后端标记为健康状况不佳。如需检查后端的运行状况,请运行此 gcloud
命令:
gcloud compute backend-services get-health grpc-gke-helloworld-service --global
如果该命令返回后端状态为运行状况不佳,则可能是以下某个原因导致的:
- 未创建防火墙或者防火墙未包含正确的源 IP 地址范围。
- 防火墙上的目标标记与您创建的集群上的标记不匹配。
工作负载无法在安全设置中通信
如果在您为无代理服务网格设置安全机制后,工作负载无法通信,请按照以下说明确定原因。
- 停用无代理安全机制,并消除无代理服务网格负载平衡使用场景中的问题。要停用网格中的安全机制,请执行以下操作之一:
- 在客户端和服务器端使用明文凭据,或者
- 不要在 Cloud Service Mesh 配置中为后端服务和端点政策配置安全机制。
按照排查无代理 Cloud Service Mesh 部署问题中的步骤操作。 因为您的部署中没有安全设置。
修改工作负载,使用明文形式的 xDS 凭据或者不安全凭据作为回退凭据。保留 Cloud Service Mesh 停用安全配置。在此示例中 虽然 gRPC 允许 Cloud Service Mesh 配置安全性, 在这种情况下,Cloud Service Mesh 不会发送安全信息 应回退到有效的纯文本(或不安全)凭据 这与之前介绍的第一种情况类似。如果上述情况不奏效 执行以下操作:
- 提高客户端和服务器端的日志记录级别,以便您可以 可以查看 gRPC 和 Cloud Service Mesh 之间交换的 xDS 消息。
- 确保 Cloud Service Mesh 在发送给工作负载的 CDS 和 LDS 响应中没有启用安全机制。
- 确保工作负载未在其通道中使用 TLS 或 mTLS 模式。如果您看到任何与 TLS 握手相关的日志消息,请检查应用源代码,并确保使用不安全或明文凭据作为回退凭据。如果应用源代码正确无误,则可能是 gRPC 库中的错误
按照该用户指南中的问题排查步骤,验证 CA Service 与 GKE 的集成可正确用于您的 GKE 集群。确保该功能提供的证书和密钥在指定的目录
/var/run/secrets/workload-spiffe-credentials/
中可用。如上文所述在网格中启用 TLS(而非 mTLS),然后重启客户端和服务器工作负载。
- 在客户端和服务器端提高日志记录级别以便能够 查看 gRPC 和 Cloud Service Mesh 之间交换的 xDS 消息。
- 确保 Cloud Service Mesh 在发送给工作负载的 CDS 和 LDS 响应中启用了安全机制。
客户端失败并显示 CertificateException
和消息 Peer certificate SAN check failed
这表示 SecuritySettings
消息中的 subjectAltNames
值存在问题。请注意,这些值基于您为后端服务创建的 Kubernetes 服务。您创建的每个此类 Kubernetes 服务都有一个相关联的 SPIFFE ID,格式如下:
spiffe://${WORKLOAD_POOL}/ns/${K8S_NAMESPACE}/sa/${SERVICE_ACCOUNT}
这些值是:
WORKLOAD_POOL
:集群的工作负载池,即${PROJECT_ID}.svc.id.goog
K8S_NAMESPACE
:您在服务部署中使用的 Kubernetes 命名空间SERVICE_ACCOUNT
:您在服务部署中使用的 Kubernetes 服务账号
对于作为网络端点组附加到后端服务的每个 Kubernetes 服务,请确保正确计算 SPIFFE ID,并将该 SPIFFE ID 添加到 SecuritySettings
消息的 subjectAltNames
字段。
应用无法将 mTLS 证书用于 gRPC 库
如果应用无法将 mTLS 证书用于 gRPC 库,请执行以下操作:
验证 pod 规范包含使用 NEG 创建无代理 gRPC 服务中所述的
security.cloud.google.com/use-workload-certificates
注释。验证可以从 pod 中访问以下路径中的包含证书链和叶证书的文件、私钥和可信 CA 证书:
- 证书链以及叶证书:“/var/run/secrets/workload-spiffe-credentials/certificates.pem”
- 私钥:“/var/run/secrets/workload-spiffe-credentials/private_key.pem”
- CA 软件包:“/var/run/secrets/workload-spinff-credentials/ca_certificates.pem”
如果上一步中的证书不可用,请执行以下操作:
gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME
--location=LOCATION验证 GKE 的控制层面具有正确的 IAM 角色绑定,从而授予其访问 CA Service 的权限:
# Get the IAM policy for the CA gcloud privateca roots get-iam-policy ROOT_CA_POOL_NAME # Verify that there is an IAM binding granting access in the following format - members: - serviceAccount:service-projnumber@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.certificateManager # Where projnumber is the project number (e.g. 2915810291) for the GKE cluster.
验证证书未过期。这是位于
/var/run/secrets/workload-spiffe-credentials/certificates.pem
的证书链和叶证书。要进行检查,请运行以下命令:cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
通过运行以下命令验证您的应用支持该密钥类型:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
验证您的 gRPC Java 应用在
WorkloadCertificateConfig
YAML 文件中具有以下keyAlgorithm
:
keyAlgorithm: rsa: modulusSize: 4096
验证 CA 与证书密钥使用相同的密钥系列。
应用的证书被客户端、服务器或对等应用拒绝
- 验证对等应用使用同一信任软件包来验证证书。
- 验证所用证书未过期(证书链以及叶证书:“/var/run/secrets/workload-spinff-credentials/certificates.pem”)。
Pod 保持待处理状态
如果 Pod 在设置过程中保持待处理状态,请增加部署规范中 Pod 的 CPU 和内存资源。
无法使用 --enable-mesh-certificates
标志创建集群
确保您运行的是最新版本的 gcloud CLI:
gcloud components update
请注意,--enable-mesh-certificates
标志仅适用于 gcloud beta
。
pod 无法启动
如果证书预配失败,使用 GKE 网格证书的 pod 可能无法启动。在以下情况下可能发生此问题:
WorkloadCertificateConfig
或TrustConfig
配置错误或缺失。- CSR 未被批准。
您可以通过检查 pod 事件来检查证书预配是否失败。
检查 pod 的状态:
kubectl get pod -n POD_NAMESPACE POD_NAME
请替换以下内容:
POD_NAMESPACE
:您的 pod 的命名空间。POD_NAME
:您的 pod 的名称。
检查 pod 的近期事件:
kubectl describe pod -n POD_NAMESPACE POD_NAME
如果证书预配失败,您将看到一个事件具有
Type=Warning
、Reason=FailedMount
、From=kubelet
以及以MountVolume.SetUp failed for volume "gke-workload-certificates"
开头的Message
字段。Message
字段包含问题排查信息。Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedMount 13s (x7 over 46s) kubelet MountVolume.SetUp failed for volume "gke-workload-certificates" : rpc error: code = Internal desc = unable to mount volume: store.CreateVolume, err: unable to create volume "csi-4d540ed59ef937fbb41a9bf5380a5a534edb3eedf037fe64be36bab0abf45c9c": caPEM is nil (check active WorkloadCertificateConfig)
如果 pod 无法启动的原因是对象配置错误或 CSR 被拒,请参阅以下问题排查步骤。
WorkloadCertificateConfig
或 TrustConfig
配置错误
确保您已正确创建 WorkloadCertificateConfig
和 TrustConfig
对象。您可以使用 kubectl
诊断这两个对象的配置错误。
检索当前状态。
对于
WorkloadCertificateConfig
:kubectl get WorkloadCertificateConfig default -o yaml
对于
TrustConfig
:kubectl get TrustConfig default -o yaml
检查状态输出。有效对象的条件将包含
type: Ready
和status: "True"
。status: conditions: - lastTransitionTime: "2021-03-04T22:24:11Z" message: WorkloadCertificateConfig is ready observedGeneration: 1 reason: ConfigReady status: "True" type: Ready
无效对象则会显示
status: "False"
。reason
和message
字段包含更多问题排查详细信息。
CSR 未被批准
如果 CSR 审批流程中出现问题,您可以在 CSR 的 type: Approved
和 type: Issued
条件中查看错误详细信息。
使用
kubectl
列出相关 CSR:kubectl get csr \ --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'
选择一个
Approved
并且未Issued
,或者未Approved
的 CSR。使用 kubectl 获取所选 CSR 的详细信息:
kubectl get csr CSR_NAME -o yaml
将
CSR_NAME
替换为您选择的 CSR 的名称。
有效 CSR 的条件包含 type: Approved
和 status: "True"
,且 status.certificate
字段中为有效证书:
status:
certificate: <base64-encoded data>
conditions:
- lastTransitionTime: "2021-03-04T21:58:46Z"
lastUpdateTime: "2021-03-04T21:58:46Z"
message: Approved CSR because it is a valid SPIFFE SVID for the correct identity.
reason: AutoApproved
status: "True"
type: Approved
message
和 reason
字段中会显示无效 CSR 的问题排查信息。
pod 缺少证书
获取 pod 的 pod 规范:
kubectl get pod -n POD_NAMESPACE POD_NAME -o yaml
请替换以下内容:
POD_NAMESPACE
:您的 pod 的命名空间。POD_NAME
:您的 pod 的名称。
验证 pod 规范包含配置 pod 以接收 mTLS 凭据中所述的
security.cloud.google.com/use-workload-certificates
注释。验证 GKE 网格证书准入控制器是否已将
workloadcertificates.security.cloud.google.com
类型的 CSI 驱动程序卷成功注入到 pod 规范中:volumes: ... -csi: driver: workloadcertificates.security.cloud.google.com name: gke-workload-certificates ...
检查每个容器中是否存在卷装载:
containers: - name: ... ... volumeMounts: - mountPath: /var/run/secrets/workload-spiffe-credentials name: gke-workload-certificates readOnly: true ...
验证 pod 中的以下位置提供以下证书软件包和私钥:
- 证书链软件包:
/var/run/secrets/workload-spiffe-credentials/certificates.pem
- 私钥:
/var/run/secrets/workload-spiffe-credentials/private_key.pem
- CA 信任锚软件包:
/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem
- 证书链软件包:
如果文件不可用,请执行以下步骤:
检索集群的 CA Service(预览版)实例:
kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'
检索 CA Service(预览版)实例的状态:
gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \ --location ISSUING_CA_LOCATION
请替换以下内容:
ISSUING_CA_TYPE
:发证 CA 类型,必须为subordinates
或roots
。ISSUING_CA_NAME
:发证 CA 的名称。ISSUING_CA_LOCATION
:发证 CA 的区域。
获取根 CA 的 IAM 政策:
gcloud privateca roots get-iam-policy ROOT_CA_NAME
将
ROOT_CA_NAME
替换为您的根 CA 的名称。在 IAM 政策中,验证存在
privateca.auditor
政策绑定:... - members: - serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.auditor ...
在此示例中,
PROJECT_NUMBER
是您的集群的项目编号。获取从属 CA 的 IAM 政策:
gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAME
将
SUBORDINATE_CA_NAME
替换为从属 CA 名称。在 IAM 政策中,验证存在
privateca.certificateManager
政策绑定:... - members: - serviceAccount: service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.certificateManager ...
在此示例中,
PROJECT_NUMBER
是您的集群的项目编号。
应用无法使用已颁发的 mTLS 凭据
验证证书未过期:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
检查应用是否支持您使用的密钥类型。
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
检查发证 CA 是否使用与证书密钥相同的密钥系列。
获取 CA Service(预览版)实例的状态:
gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \ --location ISSUING_CA_LOCATION
请替换以下内容:
ISSUING_CA_TYPE
:发证 CA 类型,必须为subordinates
或roots
。ISSUING_CA_NAME
:发证 CA 的名称。ISSUING_CA_LOCATION
:发证 CA 的区域。
检查输出中的
keySpec.algorithm
是否与您在WorkloadCertificateConfig
YAML 清单中定义的密钥算法相同。输出如下所示:config: ... subjectConfig: commonName: td-sub-ca subject: organization: TestOrgLLC subjectAltName: {} createTime: '2021-05-04T05:37:58.329293525Z' issuingOptions: includeCaCertUrl: true keySpec: algorithm: RSA_PKCS1_2048_SHA256 ...
证书遭拒
- 验证对等应用使用同一信任软件包来验证证书。
验证证书未过期:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
如果未使用 gRPC Go Credentials Reloading API,验证客户端代码是否定期刷新来自文件系统的凭据。
验证工作负载与 CA 位于同一信任网域。GKE 网格证书支持单个信任网域中的工作负载之间的通信。
限制
只有 GKE 支持 Cloud Service Mesh 服务安全。您无法使用 Compute Engine 部署服务安全。
如果有两个或更多端点政策资源与同一个端点同等匹配(例如,两个政策具有相同的标签和端口,或者两个或更多政策具有不同的标签,但这些标签与同一个端点的标签同等匹配),Cloud Service Mesh 不支持这一场景。如需详细了解端点政策如何与端点标签匹配,请参阅 EndpointPolicy.EndpointMatcher.MetadataLabelMatcher 的 API。在这种情况下,Cloud Service Mesh 不会生成安全配置 来自任何存在冲突的政策