设置使用 Envoy 的服务安全

按照本指南中的说明,为使用 Cloud Service Mesh 和 Envoy 代理部署的服务配置身份验证和授权。如需完整 有关 Cloud Service Mesh 服务安全性的信息,请参阅 Cloud Service Mesh 服务安全性

使用要求

在使用 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 Service 的 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 角色。此角色包含创建、更新、删除、列出和使用所需资源(即在其他资源中引用)的所有必要权限。如果您是项目的所有者编辑者,则会自动拥有此角色。

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

如果以后强制执行了这些权限,而您在使用 compute.NetworkAdmin 角色,那么进行此项检查时您不会发现任何问题 。

如果您使用的是自定义角色,并且此检查将强制执行,那么您必须确保添加相应的 .use 权限。否则,将来您可能会发现自定义角色没有必要的权限,无法引用后端服务或端点政策中的 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 初始化后,Sidecar 代理会提取此注解并将其传输到 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 创建健康检查、防火墙规则和后端服务资源。

  1. 创建健康检查

    gcloud compute health-checks create http td-gke-health-check \
      --use-serving-port
    
  2. 创建防火墙规则以允许健康检查器 IP 地址范围。

    gcloud compute firewall-rules create fw-allow-health-checks \
       --action ALLOW \
       --direction INGRESS \
       --source-ranges 35.191.0.0/16,130.211.0.0/22 \
      --rules tcp
    
  3. 创建后端服务并将健康检查与后端服务相关联。

    gcloud compute backend-services create td-gke-service \
      --global \
      --health-checks td-gke-health-check \
      --load-balancing-scheme INTERNAL_SELF_MANAGED
    
  4. 将之前创建的 NEG 作为后端添加到后端服务。

    gcloud compute backend-services add-backend td-gke-service \
      --global \
      --network-endpoint-group ${NEG_NAME} \
      --network-endpoint-group-zone ZONE \
      --balancing-mode RATE \
     --max-rate-per-endpoint 5
    

配置 MeshHTTPRoute 资源

在本部分中,您将创建 MeshHTTPRoute 资源。

  1. 创建 Mesh 资源规范并将其保存在名为 mesh.yaml 的文件中。

    name: sidecar-mesh
    interceptionPort: 15001
    

    如果您未在 mesh.yaml 文件中指定拦截端口,则默认为 15001

  2. 使用 mesh.yaml 规范创建 Mesh 资源。

    gcloud network-services meshes import sidecar-mesh \
      --source=mesh.yaml \
      --location=global
    
  3. 创建 HTTPRoute 规范并将其保存到名为 http_route.yaml 的文件中。

    您可以使用 PROJECT_IDPROJECT_NUMBER

    name: helloworld-http-route
    hostnames:
    - service-test
    meshes:
    - projects/PROJNUM/locations/global/meshes/sidecar-mesh
    rules:
    - action:
       destinations:
       - serviceName: "projects/PROJNUM/locations/global/backendServices/td-gke-service"
    
  4. 使用 http_route.yaml 文件中的规范来创建 HTTPRoute 资源。

    gcloud network-services http-routes import helloworld-http-route \
      --source=http_route.yaml \
      --location=global
    

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>

在 GKE 上为 Sidecar 设置授权政策

本部分介绍了如何设置不同类型的 授权政策

您必须先安装 GCPAuthzPolicy CustomResourceDefinition (CRD),然后才能创建授权政策:

curl https://github.com/GoogleCloudPlatform/gke-networking-recipes/blob/main/gateway-api/config/mesh/crd/experimental/gcpauthzpolicy.yaml \
| kubectl apply -f -

用于拒绝请求的授权政策

如果您的工作负载应仅进行出站调用(例如 cron 作业),您可以配置授权政策,以拒绝向该工作负载发送任何传入 HTTP 请求。以下示例会拒绝向工作负载 example-app 发送传入 HTTP 请求。

如需创建和应用拒绝授权政策,请执行以下步骤:

  1. 通过创建名为 deny-all-authz-policy.yaml 的文件创建自定义政策:

    cat >deny-all-authz-policy.yaml <<EOF
    apiVersion: networking.gke.io/v1
    kind: GCPAuthzPolicy
    metadata:
      name: my-workload-authz
      namespace: ns1
    spec:
    targetRefs:
    - kind: Deployment
      name: example-app
    httpRules:
    - to:
        operations:
        - paths:
          - type: Prefix
            value: "/"
    action: DENY
    EOF
    
  2. 应用政策:

    kubectl apply -f deny-all-authz-policy.yaml
    

用于允许请求的授权政策

您还可以配置一项允许政策,仅允许与 同时拒绝其余的过滤条件以下示例在 example-app 部署上配置了授权政策,以仅允许来自具有身份 spiffee://cluster.local/ns1/pod1 的 Pod 的 mTLS 请求。

请按以下步骤创建并应用允许授权政策:

  1. 通过创建名为 allow-authz-policy.yaml 的文件创建自定义政策:

    cat >allow-authz-policy.yaml <<EOF
    apiVersion: networking.gke.io/v1
    kind: GCPAuthzPolicy
    metadata:
      name: my-workload-authz
      namespace: ns1
    spec:
    targetRefs:
    - kind: Deployment
      name: example-app
    httpRules:
    - from:
        sources:
        - principals:
          - type: Exact
            value: "spiffee://cluster.local/ns1/pod1"
    action: ALLOW
    EOF
    
  2. 应用政策:

    kubectl apply -f allow-authz-policy.yaml
    

设置入站流量网关安全性

本部分假定您已完成服务到服务的安全部分,包括使用 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. 创建一个新的目标 Gateway 并将其保存在文件 td-gke-gateway.yaml 中。这会附加服务器 TLS 政策并将 Envoy 代理入站流量网关配置为终结传入的 TLS 流量。

    name: td-gke-gateway
    scope: gateway-proxy
    ports:
    - 8080
    type: OPEN_MESH
    serverTLSPolicy: projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
    
  4. 导入网关:

    gcloud network-services gateways import td-gke-gateway \
      --source=td-gke-gateway.yaml \
      --location=global
    
  5. 创建并保存新的名为 td-gke-routeHTTPRoute,它引用网关并将所有请求路由到 td-gke-service

    name: td-gke-route
    hostnames:
    - mesh-gateway
    gateways:
    - projects/PROJECT_NUMBER/locations/global/gateways/td-gke-gateway
    rules:
    - action:
        destinations:
        - serviceName: "projects/PROJECT_NUMBER/locations/global/backendServices/td-gke-service"
    
  6. 导入 HTTPRoute

    gcloud network-services httproutes import td-gke-route \
      --source=td-gke-route.yaml \
      --location=global
    
    
  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

删除部署

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

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

gcloud container clusters delete CLUSTER_NAME --zone ZONE --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 网格证书支持单个信任网域中的工作负载之间的通信。