设置使用 Envoy 和负载均衡 API 的服务安全(旧版)

按照本指南中的说明,使用负载均衡 API 为通过 Cloud Service Mesh 和 Envoy 代理部署的服务配置身份验证和授权。如果您使用的是服务路由 API,请阅读设置使用 Envoy 的服务安全

如需全面了解,请参阅使用负载均衡 API 的 Cloud Service Mesh 服务安全

本文档适用于使用负载均衡 API 的配置。这是旧版文档。

使用要求

在使用 Envoy 为 Cloud Service Mesh 配置服务安全之前,请确保您的设置符合以下前提条件:

准备设置

以下部分介绍了在设置 Cloud Service Mesh 安全服务之前需要完成的任务。这些任务是:

  • 更新 Google Cloud CLI
  • 设置变量
  • 启用 Cloud Service Mesh 与 Certificate Authority Service 搭配使用所需的 API

更新 gcloud 命令行工具

如需更新 Google Cloud CLI,请在本地机器上运行以下命令:

gcloud components update

设置变量

请设置以下变量,以便在执行本文档中的示例时复制和粘贴具有一致值的代码。请使用以下值:

  • PROJECT_ID:替换项目的 ID。
  • CLUSTER_NAME:替换为您要使用的集群名称,例如 secure-td-cluster
  • ZONE:替换集群所在的可用区。
  • GKE_CLUSTER_URL:替换为 https://container.googleapis.com/v1/projects/PROJECT_ID/locations/ZONE/clusters/CLUSTER_NAME
  • WORKLOAD_POOL:替换为 PROJECT_ID.svc.id.goog
  • K8S_NAMESPACE:替换为 default
  • DEMO_CLIENT_KSA:替换为您的客户端 Kubernetes 服务账号的名称。
  • DEMO_SERVER_KSA:替换为服务器 Kubernetes 服务账号的名称。
  • PROJNUM:替换为您的项目的编号(您可以在 Google Cloud 控制台中或使用以下命令确定项目编号):

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
    
  • SA_GKE:替换为 service-PROJNUM@container-engine-robot.iam.gserviceaccount.com

  • CLUSTER_VERSION:替换为可用的最新版本。您可以在快速渠道版本说明中找到此信息。所需的最低版本为 1.21.4-gke.1801。这是要在此示例中使用的 GKE 集群版本。

在此处设置值:

# Substitute your project ID
PROJECT_ID=PROJECT_ID

# GKE cluster name and zone for this example.
CLUSTER_NAME=CLUSTER_NAME
ZONE=ZONE

# 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=K8S_NAMESPACE
DEMO_CLIENT_KSA=DEMO_CLIENT_KSA
DEMO_SERVER_KSA=DEMO_SERVER_KSA

# Compute other values
# Project number for your project
PROJNUM=PROJNUM

CLUSTER_VERSION=CLUSTER_VERSION
SA_GKE=service-PROJNUM@container-engine-robot.iam.gserviceaccount.com

启用 API

使用 gcloud services enable 命令启用通过 Certificate Authority Service 设置 Cloud Service Mesh 安全所需的所有 API。

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

创建或更新 GKE 集群

Cloud Service Mesh 服务安全取决于 CA Service 与 GKE 的集成。除了设置要求之外,GKE 集群还必须满足以下要求:

  • 使用的最低集群版本为 1.21.4-gke.1801。如果您需要更高版本的功能,则可以从快速发布渠道中获取该版本。
  • 必须使用网格证书启用和配置 GKE 集群,如创建证书授权机构以颁发证书中所述。
  1. 创建使用适用于 GKE 的工作负载身份联合的新集群。如果您要更新现有集群,请跳至下一步。您为 --tags 指定的值必须与使用 Cloud Load Balancing 组件配置 Cloud Service Mesh 部分中传递给 firewall-rules create 命令的 --target-tags 标志的名称匹配。

    # 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
    

    集群创建可能需要几分钟才能完成。

  2. 如果您使用的是现有集群,请开启适用于 GKE 的工作负载身份联合和 GKE 网格证书。确保使用 --enable-ip-alias 标志创建集群,该标志无法与 update 命令一起使用。

    gcloud container clusters update CLUSTER_NAME \
      --enable-mesh-certificates
    
  3. 运行以下命令切换到作为 kubectl 命令的默认集群的新集群:

    gcloud container clusters get-credentials CLUSTER_NAME \
      --zone ZONE
    

在多集群环境中部署

如果您要在多集群环境中进行部署,请按照本部分中所述的常规步骤操作。以下说明假定客户端 Pod 在一个集群中运行,而服务器 Pod 在另一个集群中运行。

  1. 按照上一部分中的说明创建或更新集群。

  2. 使用以下命令捕获每个集群的 Pod IP 地址范围:

    gcloud compute firewall-rules list \
      --filter="name~gke-{CLUSTER_NAME}-[0-9a-z]*-all" \
      --format="value(sourceRanges)"
    

    例如,对于名为 cluster-acluster-b 的集群,该命令会返回如下结果:

    cluster-a, pod CIDR: 10.4.0.0/14, node network tag: gke-cluster-a-9cd18751-node
    cluster-b, pod CIDR: 10.8.0.0/14, node network tag: gke-cluster-b-acd14479-node
    
  3. 创建允许集群相互通信的 VPC 防火墙规则。例如,以下命令会创建一条防火墙规则,允许 cluster-a pod IP 地址与 cluster-b 节点通信:

    gcloud compute firewall-rules create per-cluster-a-pods \
      --allow="tcp,udp,icmp,esp,ah,sctp" \
      --target-tags="gke-cluster-b-acd14479-node"
    

    以下命令会创建一条防火墙规则,允许 cluster-b pod IP 地址与 cluster-a 节点通信:

    gcloud compute firewall-rules create per-cluster-b-pods \
      --allow="tcp,udp,icmp,esp,ah,sctp" \
      --target-tags="gke-cluster-a-9cd18751-node"
    

向舰队注册集群

向舰队注册您在创建 GKE 集群中创建或更新的集群。通过注册集群,您可以更轻松地跨多个项目配置集群。

请注意,每个步骤最长可能需要十分钟才能完成。

  1. 向舰队注册集群:

    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.
  2. 将生成的清单文件应用于您的集群:

    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
    
  3. 从集群获取成员资格资源:

    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
  1. 将 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
    
  2. 将 CA 角色 role/privateca.admin 授予需要修改 IAM 政策的个人,其中 MEMBER 是需要此访问权限的个人,具体而言是执行以下步骤的个人这些角色可授予 privateca.auditorprivateca.certificateManager 角色:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=MEMBER \
      --role=roles/privateca.admin
    
  3. 创建根 CA 服务池。

    gcloud privateca pools create ROOT_CA_POOL_NAME \
      --location ROOT_CA_POOL_LOCATION \
      --tier enterprise
    
  4. 创建根 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"
  5. 创建从属池和从属 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
  6. 授予根 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"
    
  7. 授予从属 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"
    
  8. 保存以下 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
  9. 保存以下 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
  10. 将配置应用到您的集群:

    kubectl apply -f WorkloadCertificateConfig.yaml
    kubectl apply -f TrustConfig.yaml
    

配置身份和访问权限管理

如要创建设置所需的资源,您必须具有 compute.NetworkAdmin 角色。此角色包含创建、更新、删除、列出和使用所需资源(即在其他资源中引用)的所有必要权限。如果您是项目的所有者编辑者,则会自动拥有此角色。

请注意,在后端服务和目标 HTTPS 代理资源中引用这些资源时,系统不会强制执行 networksecurity.googleapis.com.clientTlsPolicies.usenetworksecurity.googleapis.com.serverTlsPolicies.use

如果这些权限在以后强制执行,并且您使用的是 compute.NetworkAdmin 角色,则在强制执行此检查时不会注意到任何问题。

如果您使用的是自定义角色,并且此检查将强制执行,那么您必须确保添加相应的 .use 权限。否则,将来,您可能会发现自定义角色没有必要的权限,分别引用后端服务或目标 HTTPS 代理中的 clientTlsPolicyserverTlsPolicy

以下说明使默认服务账号能够访问 Cloud Service Mesh Security API 并创建 Kubernetes 服务账号。

  1. 配置 IAM 以允许默认服务账号访问 Cloud Service Mesh 安全 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
    
  2. 设置 Kubernetes 服务账号。以下部分中的客户端和服务器部署使用 Kubernetes 服务器和客户端服务账号的 Knames。

    kubectl create serviceaccount --namespace K8S_NAMESPACE DEMO_SERVER_KSA
    kubectl create serviceaccount --namespace K8S_NAMESPACE DEMO_CLIENT_KSA
    
  3. 通过在 Kubernetes 服务账号与默认 Compute Engine 服务账号之间创建 IAM 政策绑定,允许前者模拟后者。此绑定允许 Kubernetes 服务账号充当默认 Compute Engine 服务账号。

    gcloud iam service-accounts add-iam-policy-binding  \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/DEMO_SERVER_KSA]" ${GSA_EMAIL}
    
    gcloud iam service-accounts add-iam-policy-binding  \
      --role roles/iam.workloadIdentityUser  \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/DEMO_CLIENT_KSA]" ${GSA_EMAIL}
    
  4. 为 Kubernetes 服务账号添加注解,以将其与默认的 Compute Engine 服务账号相关联。

    kubectl annotate --namespace K8S_NAMESPACE \
      serviceaccount DEMO_SERVER_KSA \
      iam.gke.io/gcp-service-account=${GSA_EMAIL}
    
    kubectl annotate --namespace K8S_NAMESPACE \
      serviceaccount DEMO_CLIENT_KSA \
      iam.gke.io/gcp-service-account=${GSA_EMAIL}
    

设置 Cloud Service Mesh

按照以下说明安装 Sidecar 注入器、设置测试服务并完成其他部署任务。

在集群中安装 Envoy Sidecar 注入器

按照针对启用自动 Envoy 注入的 GKE pod 的 Cloud Service Mesh 设置中以下两个部分中的说明在集群中部署和启用 Envoy Sidecar 注入:

在设置测试服务之前,请务必按照这两组说明完成操作。

设置测试服务

安装 Envoy Sidecar 注入器后,请按照以下说明为您的部署设置测试服务。

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/service_sample.yaml | sed -e s/DEMO_SERVER_KSA_PLACEHOLDER/DEMO_SERVER_KSA/g > service_sample.yaml

kubectl apply -f service_sample.yaml

文件 service_sample.yaml 包含演示服务器应用的 podspec。有一些注释是专门针对 Cloud Service Mesh 安全的。

Cloud Service Mesh 代理元数据

podspec 指定 proxyMetadata 注释:

spec:
...
      annotations:
        cloud.google.com/proxyMetadata: '{"app": "payments"}'
...

pod 初始化后,边车代理会提取此注解并将其传输到 Cloud Service Mesh。然后,Cloud Service Mesh 可以使用此信息发回经过过滤的配置:

  • 请注意,在本指南的后面部分,端点政策会指定端点匹配器。
  • 端点匹配器指定仅提供名称为 app 且值为 payments 的标签的客户端接收过滤后的配置。

使用由 CA Service 签名的网格证书和密钥

podspec 指定 enableManagedCerts 注释:

spec:
...
      annotations:
        ...
        cloud.google.com/enableManagedCerts: "true"
...

pod 初始化后,CA Service 签名的证书和密钥会自动装载到本地边车代理文件系统上。

配置入站流量拦截端口

podspec 指定 includeInboundPorts 注释:

spec:
...
      annotations:
        ...
        cloud.google.com/includeInboundPorts: "8000"
...

这是服务器应用监听连接的端口。pod 初始化后,边车代理会提取此注解并将其传输到 Cloud Service Mesh。然后,Cloud Service Mesh 可以使用此信息发回经过过滤的配置,该配置会拦截到此端口的所有传入流量,并且可以对其应用安全政策。

健康检查端口必须与应用端口不同。否则,相同的安全政策将应用于健康检查端口的传入连接,这可能会导致连接被拒,进而导致服务器错误地被标记为健康状况不佳。

使用 NEG 配置 GKE 服务

GKE 服务必须通过网络端点组 (NEG) 公开,以便您可以将它们配置为 Cloud Service Mesh 后端服务的后端。本设置指南提供的 service_sample.yaml 软件包在以下注释中使用 NEG 名称 service-test-neg

...
metadata:
  annotations:
    cloud.google.com/neg: '{"exposed_ports": {"80":{"name": "service-test-neg"}}}'
spec:
  ports:
  - port: 80
    name: service-test
    protocol: TCP
    targetPort: 8000

您无需更改 service_sample.yaml 文件。

保存 NEG 的名称

将 NEG 的名称保存在 NEG_NAME 变量中:

NEG_NAME="service-test-neg"

将客户端应用部署到 GKE

运行以下命令,启动将 Envoy 代理作为 Sidecar 的演示客户端,以展示安全功能。

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/client_sample.yaml | sed -e s/DEMO_CLIENT_KSA_PLACEHOLDER/DEMO_CLIENT_KSA/g > client_sample.yaml

kubectl apply -f client_sample.yaml

客户端 podspec 仅包含 enableManagedCerts 注释。装载由 CA Service 实例签名的 GKE 代管式网格证书和密钥所需的卷时,需要此注解。

配置 Cloud Service Mesh Google Cloud 资源

按照使用 Cloud Load Balancing 组件配置 Cloud Service Mesh 中的步骤操作。确保验证来自示例客户端的流量被路由到示例服务。

Cloud Service Mesh 配置已完成,您现在可以配置身份验证和授权政策。

设置服务到服务的安全性

按照以下部分中的说明设置服务间安全。

在网格中启用 mTLS

要在网格中设置 mTLS,您必须保护到后端服务的出站流量以及到端点的入站流量。

政策引用的格式

请注意引用服务器 TLS、客户端 TLS 和授权政策的以下必需格式:

projects/PROJECT_ID/locations/global/[serverTlsPolicies|clientTlsPolicies|authorizationPolicies]/[server-tls-policy|client-mtls-policy|authz-policy]

例如:

projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy
projects/PROJECT_ID/locations/global/authorizationPolicies/authz-policy

保护到后端服务的出站流量

要保护出站流量,您首先需要创建执行以下操作的客户端 TLS 政策:

  • 使用 google_cloud_private_spiffe 作为 clientCertificate 的插件,此插件将 Envoy 编程为使用 GKE 代管式网格证书作为客户端身份。
  • 使用 google_cloud_private_spiffe 作为 serverValidationCa 的插件,此插件将 Envoy 编程为将 GKE 代管式网格证书用于服务器验证。

接下来,将客户端 TLS 政策附加到后端服务。该命令将执行以下操作:

  • 将客户端 TLS 政策中的身份验证政策应用于到后端服务端点的出站连接。
  • SAN(主题备用名称)指示客户端声明其要连接的服务器的确切身份。
  1. 在文件 client-mtls-policy.yaml 中创建客户端 TLS 政策:

    name: "client-mtls-policy"
    clientCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. 导入客户端 TLS 政策:

    gcloud network-security client-tls-policies import client-mtls-policy \
        --source=client-mtls-policy.yaml --location=global
    
  3. 将客户端 TLS 政策附加到后端服务。这会对从客户端到此后端服务的所有出站请求强制执行 mTLS 身份验证。

    gcloud compute backend-services export td-gke-service \
        --global --destination=demo-backend-service.yaml
    

    将以下行添加到 demo-backend-service.yaml

    securitySettings:
      clientTlsPolicy: projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy
      subjectAltNames:
        - "spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA"
    
  4. 导入值:

    gcloud compute backend-services import td-gke-service \
        --global --source=demo-backend-service.yaml
    
  5. (可选)运行以下命令检查请求是否失败。失败是预期现象,因为客户端要求来自端点的证书,但端点未编程为使用安全政策。

    # Get the name of the Podrunning Busybox.
    BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')
    
    # Command to execute that tests connectivity to the service service-test.
    TEST_CMD="wget -q -O - service-test; echo"
    
    # Execute the test command on the pod.
    kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"
    

    您会看到如下输出:

    wget: server returned error: HTTP/1.1 503 Service Unavailable
    

保护到端点的入站流量

要保护入站流量,您首先要创建一个执行以下操作的服务器 TLS 政策:

  • 使用 google_cloud_private_spiffe 作为 serverCertificate 的插件,此插件将 Envoy 编程为使用 GKE 代管式网格证书作为服务器端身份。
  • 使用 google_cloud_private_spiffe 作为 clientValidationCa 的插件,此插件将 Envoy 编程为将 GKE 代管式网格证书用于客户端验证。
  1. 将服务器 TLS 政策值保存在名为 server-mtls-policy.yaml 的文件中。

    name: "server-mtls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    mtlsPolicy:
      clientValidationCa:
      - certificateProviderInstance:
          pluginInstance: google_cloud_private_spiffe
    
  2. 创建服务器 TLS 政策:

    gcloud network-security server-tls-policies import server-mtls-policy \
        --source=server-mtls-policy.yaml --location=global
    
  3. 创建一个名为 ep_mtls.yaml 且包含端点匹配器的文件,并附加服务器 TLS 政策。

    endpointMatcher:
      metadataLabelMatcher:
        metadataLabelMatchCriteria: MATCH_ALL
        metadataLabels:
        - labelName: app
          labelValue: payments
    name: "ep"
    serverTlsPolicy: projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy
    type: SIDECAR_PROXY
    
  4. 导入端点匹配器。

    gcloud network-services endpoint-policies import ep \
        --source=ep_mtls.yaml --location=global
    

验证设置

运行以下 curl 命令:如果请求成功完成,您会在输出中看到 x-forwarded-client-cert。只有当连接是 mTLS 连接时,才会输出标头。

# Get the name of the Podrunning Busybox.
BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')

# Command to execute that tests connectivity to the service service-test.
TEST_CMD="wget -q -O - service-test; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

输出将如下所示:

GET /get HTTP/1.1
Host: service-test
content-length: 0
x-envoy-internal: true
accept: */*
x-forwarded-for: 10.48.0.6
x-envoy-expected-rq-timeout-ms: 15000
user-agent: curl/7.35.0
x-forwarded-proto: http
x-request-id: redacted
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA

请注意,x-forwarded-client-cert 标头由服务器端 Envoy 插入,包含自己的身份(服务器)和源客户端的身份。我们可以看到客户端和服务器身份,表明这是 mTLS 连接。

使用授权政策配置服务级访问权限

以下说明会创建一项授权政策,该政策允许 DEMO_CLIENT_KSA 账号发送的请求,其中主机名为 service-test,端口为 8000,HTTP 方法为 GET。在创建授权政策之前,请阅读使用授权限制访问权限中的注意事项。

  1. 通过创建名为 authz-policy.yaml 的文件创建授权政策。

    action: ALLOW
    name: authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
      destinations:
      - hosts:
        - service-test
        ports:
        - 8000
        methods:
        - GET
    
  2. 导入政策:

    gcloud network-security authorization-policies import authz-policy \
      --source=authz-policy.yaml \
      --location=global
    
  3. 通过将以下内容附加到文件 ep_mtls.yaml,将端点政策更新为引用新的授权政策:

    authorizationPolicy: projects/PROJECT_ID/locations/global/authorizationPolicies/authz-policy
    

    端点政策现在指定,必须对以下 pod 的入站请求强制执行 mTLS 和授权政策:该 pod 的 Envoy Sidecar 代理提供标签 app:payments

  4. 导入政策:

    gcloud network-services endpoint-policies import ep \
        --source=ep_mtls.yaml --location=global
    

验证设置

运行以下命令来验证设置。

# Get the name of the Podrunning Busybox.
BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')

# Command to execute that tests connectivity to the service service-test.
# This is a valid request and will be allowed.
TEST_CMD="wget -q -O - service-test; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

预期输出如下所示:

GET /get HTTP/1.1
Host: service-test
content-length: 0
x-envoy-internal: true
accept: */*
x-forwarded-for: redacted
x-envoy-expected-rq-timeout-ms: 15000
user-agent: curl/7.35.0
x-forwarded-proto: http
x-request-id: redacted
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA

运行以下命令测试授权政策是否正确拒绝无效请求:

# Failure case
# Command to execute that tests connectivity to the service service-test.
# This is an invalid request and server will reject because the server
# authorization policy only allows GET requests.
TEST_CMD="wget -q -O - service-test --post-data='' ; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

预期输出如下所示:

<RBAC: access denied HTTP/1.1 403 Forbidden>

设置入站流量网关安全性

本部分假定您已完成服务到服务的安全部分,包括使用 Sidecar 自动注入器设置 GKE 集群、创建证书授权机构和创建端点政策。

在本部分中,您将 Envoy 代理部署为入站网关,该网关终止 TLS 连接并向来自集群内部客户端的请求授权。

在入站网关处终止 TLS(点击可放大)
在入站网关处终止 TLS(点击可放大)

要设置入站网关以终止 TLS,请执行以下操作:

  1. 部署一个可使用集群内部 IP 地址访问的 Kubernetes 服务。
    1. 部署包含一个独立的 Envoy 代理,该代理公开为 Kubernetes 服务并连接到 Cloud Service Mesh。
  2. 创建终止 TLS 的服务器 TLS 政策。
  3. 创建向传入请求授权的授权政策。

将入站流量网关服务部署到 GKE

运行以下命令,在 GKE 上部署入站网关服务:

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/gateway_sample_xdsv3.yaml | sed -e s/PROJECT_NUMBER_PLACEHOLDER/PROJNUM/g | sed -e s/NETWORK_PLACEHOLDER/default/g | sed -e s/DEMO_CLIENT_KSA_PLACEHOLDER/DEMO_CLIENT_KSA/g > gateway_sample.yaml

kubectl apply -f gateway_sample.yaml

文件 gateway_sample.yaml 是入站网关的规范。以下部分介绍一些可以添加到该规范的内容。

停用 Cloud Service Mesh Sidecar 注入

gateway_sample.yaml 规范将 Envoy 代理部署为唯一容器。在之前的步骤中,Envoy 被作为 Sidecar 注入应用容器。为避免多个 Envoy 处理请求,您可以使用以下语句为此 Kubernetes 服务停用 Sidecar 注入:

sidecar.istio.io/inject: "false"

装载正确的卷

gateway_sample.yaml 规范装载卷 gke-workload-certificates。此卷也在 Sidecar 部署中使用,但当 Sidecar 注入器看到注释 cloud.google.com/enableManagedCerts: "true" 时,会自动添加该卷。gke-workload-certificates 卷包含您设置的 CA Service 实例签名的 GKE 代管式 SPIFFE 证书和密钥。

设置集群的内部 IP 地址

使用 ClusterInternal 类型的服务配置入站网关。这会为 mesh-gateway 创建一个内部可解析的 DNS 主机名。当客户端向 mesh-gateway:443 发送请求时,Kubernetes 会立即将请求路由到入站网关 Envoy 部署的端口 8080

在入站流量网关上启用 TLS

按照以下说明在入站网关上启用 TLS。

  1. 使用名为 server-tls-policy.yaml 的文件中的值创建服务器 TLS 政策资源以终止 TLS 连接:

    description: tls server policy
    name: server-tls-policy
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. 导入服务器 TLS 政策:

    gcloud network-security server-tls-policies import server-tls-policy \
        --source=server-tls-policy.yaml --location=global
    
  3. 创建将所有请求路由到 td-gke-service 后端服务的新网址映射。入站网关会处理传入请求,并将其发送到属于 td-gke-service 后端服务的 pod。

    gcloud compute url-maps create td-gke-ig-url-map \
       --default-service=td-gke-service
    
  4. td-gke-https-proxy.yaml 文件中创建新的目标 HTTPS 代理,并附加之前创建的网址映射和服务器 TLS 政策。这会将 Envoy 代理入站网关配置为终止传入的 TLS 流量。

    kind: compute#targetHttpsProxy
    name: td-gke-https-proxy
    proxyBind: true
    urlMap: https://www.googleapis.com/compute/beta/projects/PROJECT_ID/global/urlMaps/td-gke-ig-url-map
    serverTlsPolicy: projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
    
  5. 导入政策:

    gcloud compute target-https-proxies import td-gke-https-proxy \
       --global --source=td-gke-https-proxy.yaml
    
  6. 创建新的转发规则并附加目标 HTTPS 代理。这会将 Envoy 代理配置为监听端口 8080 并应用 td-gke-https-proxy 中定义的路由和安全政策。

    gcloud compute forwarding-rules create td-gke-gateway-forwarding-rule --global \
      --load-balancing-scheme=INTERNAL_SELF_MANAGED --address=0.0.0.0 \
      --target-https-proxy=td-gke-https-proxy --ports 8080 \
      --network default
    
  7. (可选)更新后端上的授权政策,以允许满足以下所有条件的请求:

    • DEMO_CLIENT_KSA 发送的请求。(入站网关部署使用 DEMO_CLIENT_KSA 服务账号。)
    • 主机 mesh-gatewayservice-test 的请求
    • 端口:8000

    除非您为后端配置了授权政策,否则无需运行这些命令。如果端点上没有授权政策,或者授权政策中不包含主机或来源主账号匹配,则无需此步骤即可允许请求。将这些值添加到 authz-policy.yaml 中。

    action: ALLOW
    name: authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
      destinations:
      - hosts:
        - service-test
        - mesh-gateway
        ports:
        - 8000
        methods:
        - GET
    
  8. 导入政策:

    gcloud network-security authorization-policies import authz-policy \
      --source=authz-policy.yaml \
      --location=global
    

验证入站流量网关部署

您可以使用名为 debug 的新容器向入站网关发送请求,以验证部署。

在以下规范中,注解 "sidecar.istio.io/inject":"false" 会防止 Cloud Service Mesh Sidecar 注入器自动注入 Sidecar 代理。没有 Sidecar 帮助 debug 容器路由请求。该容器必须连接到入站网关才能路由。

规范包含 --no-check-certificate 标志,此标志会忽略服务器证书验证。debug 容器不具有由 CA Service 签名的有效证书所需的证书授权机构验证证书,入站网关需要使用该证书来终止 TLS。

在生产环境中,我们建议您下载 CA Service 验证证书,并将其装载或安装到您的客户端上。安装验证证书后,移除 wget 命令的 --no-check-certificate 选项。

运行以下命令:

kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway; echo"

您将看到如下所示的输出:

GET / HTTP/1.1
Host: 10.68.7.132
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
x-envoy-expected-rq-timeout-ms: 15000
x-envoy-internal: true
x-request-id: 5ae429e7-0e18-4bd9-bb79-4e4149cf8fef
x-forwarded-for: 10.64.0.53
x-forwarded-proto: https
content-length: 0
user-agent: Wget

运行以下反向测试命令:

# Negative test
# Expect this to fail because gateway expects TLS.
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - http://mesh-gateway:443/headers; echo"

您将看到类似如下所示的输出:

wget: error getting response: Connection reset by peer

运行以下反向测试命令:

# Negative test.
# AuthorizationPolicy applied on the endpoints expect a GET request. Otherwise
# the request is denied authorization.
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway --post-data=''; echo"

您将看到类似如下所示的输出:

HTTP/1.1 403 Forbidden
wget: server returned error: HTTP/1.1 403 Forbidden

为入站网关设置授权政策

您在此处设置的授权政策使入站网关允许满足以下所有条件的请求进入网格:

  • 主机:mesh-gateway
  • 端口:8080
  • 路径:*
  • HTTP 方法 GET
  1. 在文件 authz-gateway-policy.yaml 中创建授权政策:

    action: ALLOW
    name: authz-gateway-policy
    rules:
    - destinations:
      - hosts:
        - mesh-gateway
        ports:
        - 8080
        methods:
        - GET
    
  2. 导入文件中的值:

    gcloud network-security authorization-policies import authz-gateway-policy \
       --source=authz-gateway-policy.yaml  --location=global
    
  3. 修改 td-gke-https-proxy.yaml 文件,将以下内容添加到该文件:

    authorizationPolicy: projects/PROJECT_ID/locations/global/authorizationPolicies/authz-gateway-policy
    
  4. 再次导入文件 td-gke-https-proxy.yaml:

    gcloud compute target-https-proxies import td-gke-https-proxy \
       --global --source=td-gke-https-proxy.yaml
    

验证部署

运行以下命令验证部署。

# On your localhost.
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway; echo"

您将看到类似如下所示的输出:

GET / HTTP/1.1
Host: 35.196.50.2
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
x-envoy-expected-rq-timeout-ms: 15000
user-agent: curl/7.72.0
x-forwarded-proto: https
content-length: 0
x-envoy-internal: true
x-request-id: 98bec135-6df8-4082-8edc-b2c23609295a
accept: */*
x-forwarded-for: 10.142.0.7

运行以下反向测试命令:

# Negative test. Expect failure because only POST method is allowed by \
# authz-gateway-policy
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway/ --post-data=''; echo"

您将看到类似如下所示的输出:

wget: server returned error: HTTP/1.1 403 Forbidden

删除部署

您可以选择运行这些命令,删除使用本指南创建的部署。

如需删除集群,请运行以下命令:

gcloud container clusters delete CLUSTER_NAME --zone ZONE --quiet

如需删除您创建的资源,请运行以下命令:

gcloud compute forwarding-rules delete td-gke-forwarding-rule --global --quiet
gcloud compute forwarding-rules delete td-gke-gateway-forwarding-rule --global \
    --quiet
gcloud compute target-http-proxies delete td-gke-proxy  --quiet
gcloud compute target-https-proxies delete td-gke-https-proxy  --quiet
gcloud compute url-maps delete td-gke-url-map  --quiet
gcloud compute url-maps delete td-gke-ig-url-map  --quiet
gcloud compute backend-services delete td-gke-service --global --quiet
cloud compute network-endpoint-groups delete service-test-neg --zone ZONE --quiet
gcloud compute firewall-rules delete fw-allow-health-checks --quiet
gcloud compute health-checks delete td-gke-health-check --quiet
gcloud network-services endpoint-policies delete ep \
    --location=global --quiet
gcloud network-security authorization-policies delete authz-gateway-policy \
   --location=global --quiet
gcloud network-security authorization-policies delete 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

限制

只有 GKE 支持 Cloud Service Mesh 服务安全。您无法使用 Compute Engine 部署服务安全。

问题排查

本部分介绍如何修复在安全服务设置期间遇到的问题。

连接失败

如果连接失败并显示 upstream connect 错误或 disconnect/reset before headers 错误,请检查 Envoy 日志,您可能会看到以下某条日志消息:

gRPC config stream closed: 5, Requested entity was not found

gRPC config stream closed: 2, no credential token is found

如果您在 Envoy 日志中看到这些错误,则可能是因为服务账号令牌未正确装载和/或它使用了不同的 audience

如需了解详情,请参阅 Envoy 日志中的错误消息指示配置问题

pod 未创建

如需排查此问题,请参阅排查 GKE pod 的自动部署问题

Envoy 未向 Cloud Service Mesh 进行身份验证

Envoy (envoy-proxy) 连接到 Cloud Service Mesh 以提取 xDS 配置时,它使用适用于 GKE 的工作负载身份联合和 Compute Engine 虚拟机默认服务账号(除非更改了引导文件)。如果身份验证失败,则 Envoy 不会进入就绪状态。

无法使用 --workload-identity-certificate-authority flag 创建集群

如果您看到此错误,请确保您运行的是最新版本的 Google Cloud CLI:

gcloud components update

Pod 仍处于待处理状态

如果 Pod 在设置过程中保持待处理状态,请增加部署规范中 Pod 的 CPU 和内存资源。

无法使用 --enable-mesh-certificates 标志创建集群

确保您运行的是最新版本的 gcloud CLI:

gcloud components update

请注意,--enable-mesh-certificates 标志仅适用于 gcloud beta

pod 无法启动

如果证书预配失败,使用 GKE 网格证书的 pod 可能无法启动。在以下情况下可能发生此问题:

  • WorkloadCertificateConfigTrustConfig 配置错误或缺失。
  • CSR 未被批准。

您可以通过检查 pod 事件来检查证书预配是否失败。

  1. 检查 pod 的状态:

    kubectl get pod -n POD_NAMESPACE POD_NAME
    

    请替换以下内容:

    • POD_NAMESPACE:您的 pod 的命名空间。
    • POD_NAME:您的 pod 的名称。
  2. 检查 pod 的近期事件:

    kubectl describe pod -n POD_NAMESPACE POD_NAME
    
  3. 如果证书预配失败,您将看到一个事件具有 Type=WarningReason=FailedMountFrom=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)
    
  4. 如果 pod 无法启动的原因是对象配置错误或 CSR 被拒,请参阅以下问题排查步骤。

WorkloadCertificateConfigTrustConfig 配置错误

确保您已正确创建 WorkloadCertificateConfigTrustConfig 对象。您可以使用 kubectl 诊断这两个对象的配置错误。

  1. 检索当前状态。

    对于 WorkloadCertificateConfig

    kubectl get WorkloadCertificateConfig default -o yaml
    

    对于 TrustConfig

    kubectl get TrustConfig default -o yaml
    
  2. 检查状态输出。有效对象的条件将包含 type: Readystatus: "True"

    status:
      conditions:
      - lastTransitionTime: "2021-03-04T22:24:11Z"
        message: WorkloadCertificateConfig is ready
        observedGeneration: 1
        reason: ConfigReady
        status: "True"
        type: Ready
    

    无效对象则会显示 status: "False"reasonmessage 字段包含更多问题排查详细信息。

CSR 未被批准

如果 CSR 审批流程中出现问题,您可以在 CSR 的 type: Approvedtype: Issued 条件中查看错误详细信息。

  1. 使用 kubectl 列出相关 CSR:

    kubectl get csr \
      --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'
    
  2. 选择一个 Approved 并且未 Issued,或者未 Approved 的 CSR。

  3. 使用 kubectl 获取所选 CSR 的详细信息:

    kubectl get csr CSR_NAME -o yaml
    

    CSR_NAME 替换为您选择的 CSR 的名称。

有效 CSR 的条件包含 type: Approvedstatus: "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

messagereason 字段中会显示无效 CSR 的问题排查信息。

应用无法使用已颁发的 mTLS 凭据

  1. 验证证书未过期:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  2. 检查应用是否支持您使用的密钥类型。

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
    
  3. 检查发证 CA 是否使用与证书密钥相同的密钥系列。

    1. 获取 CA Service(预览版)实例的状态:

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

      请替换以下内容:

      • ISSUING_CA_TYPE:发证 CA 类型,必须为 subordinatesroots
      • ISSUING_CA_NAME:发证 CA 的名称。
      • ISSUING_CA_LOCATION:发证 CA 的区域。
    2. 检查输出中的 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
       ...
      

证书遭拒

  1. 验证对等应用使用同一信任软件包来验证证书。
  2. 验证证书未过期:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  3. 如果未使用 gRPC Go Credentials Reloading API,验证客户端代码是否定期刷新来自文件系统的凭据。

  4. 验证工作负载与 CA 位于同一信任网域。GKE 网格证书支持单个信任网域中的工作负载之间的通信。