使用無 Proxy gRPC (舊版) 設定服務安全性

本指南說明如何為無 Proxy gRPC 服務網格設定安全性服務。

本文僅適用於搭配負載平衡 API 使用的 Cloud Service Mesh。這是舊版文件。

需求條件

為無 Proxy gRPC 服務網格設定服務安全性前,請確認您符合下列需求。

設定身分與存取權管理

您必須具備使用 Google Kubernetes Engine 所需的權限。您至少必須具備下列角色:

  • roles/container.clusterAdmin GKE 角色
  • roles/compute.instanceAdmin Compute Engine 角色
  • roles/iam.serviceAccountUser 角色

如要建立設定所需的資源,您必須具備 compute.NetworkAdmin 角色。這個角色包含所有必要權限,可用於建立、更新、刪除、列出及使用 (也就是在其他資源中參照) 必要資源。如果您是專案的擁有者/編輯者,就會自動獲得這個角色。

請注意,如果您在後端服務和目標 HTTPS Proxy 資源中參照這些資源,系統就不會強制執行 networksecurity.googleapis.com.clientTlsPolicies.usenetworksecurity.googleapis.com.serverTlsPolicies.use

如果日後實施這項規定,且您使用的是 compute.NetworkAdmin 角色,則在實施這項檢查時,您不會發現任何問題。

如果您使用的是自訂角色,且日後會強制執行這項檢查,請務必加入相應的 .use 權限。否則,您日後可能會發現自訂角色沒有必要的權限,無法分別從後端服務或指定的 HTTPS Proxy 參照 clientTlsPolicyserverTlsPolicy

準備設定

根據無 Proxy gRPC 服務說明文件的說明,無 Proxy 服務網格 (PSM) 安全性可為負載平衡而設定的服務網格提供安全性。在無 Proxy 服務網狀結構中,gRPC 用戶端會使用 URI 中的配置 xds: 來存取服務,進而啟用 PSM 負載平衡和端點探索功能。

將 gRPC 用戶端和伺服器更新為正確的版本

使用語言支援的最低 gRPC 版本建構或重建應用程式。

更新 Bootstrap 檔案

gRPC 應用程式會使用單一啟動檔案,該檔案必須包含 gRPC 用戶端和伺服器端程式碼所需的所有欄位。引導程式產生器會自動產生引導程式檔案,以便納入 PSM 安全性所需的旗標和值。詳情請參閱「引導檔案」一節,其中包含引導檔案範例。

設定總覽

這個設定程序是使用 GKE 和無 Proxy gRPC 服務的 Cloud Service Mesh 設定的延伸功能。在適用的情況下,系統會參照該設定程序中現有的未修改步驟。

透過 GKE 設定 Cloud Service Mesh 的主要增強功能如下:

  1. 設定 CA 服務,建立私人 CA 集區和必要的憑證授權單位。
  2. 使用 GKE Workload Identity Federation for GKE 和網格憑證功能,以及 CA 服務整合功能建立 GKE 叢集。
  3. 在叢集上設定網格憑證核發作業。
  4. 建立用戶端和伺服器服務帳戶。
  5. 設定範例伺服器,使用 xDS API 和 xDS 伺服器憑證,從 Cloud Service Mesh 取得安全性設定。
  6. 設定使用 xDS 憑證的範例用戶端
  7. 更新 Cloud Service Mesh 設定,納入安全性設定。

您可以在下列位置查看使用 xDS 憑證的程式碼範例:

更新 Google Cloud CLI

如要更新 Google Cloud CLI,請執行下列指令:

gcloud components update

設定環境變數

在本指南中,您將使用 Cloud 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 的存取權。

  1. 執行下列指令,啟用 Cloud Service Mesh 和其他 API,以便無 Proxy 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
    
  2. 執行下列指令,允許預設服務帳戶存取 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
    

建立或更新 GKE 叢集

Cloud Service Mesh 服務安全性取決於 CA 服務與 GKE 的整合方式。除了設定需求外,GKE 叢集還必須符合下列條件:

  • 叢集版本至少須為 1.21.4-gke.1801。如果您需要後續版本中的功能,可以透過快速發布管道取得該版本。
  • 您必須啟用 GKE 叢集,並使用網格憑證進行設定,如建立憑證授權單位以核發憑證一文所述。
  1. 建立使用 Workload Identity Federation for 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. 如果您使用現有叢集,請啟用 Workload Identity Federation for 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
    

向機群註冊叢集

將您在「建立 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
    

    輸出內容應包含車隊指派的工作負載身分池,其中 PROJECT_ID 是您的專案 ID:

    workload_identity_pool: PROJECT_ID.svc.id.goog
    

    這表示叢集已成功註冊。

建立憑證授權單位以核發憑證

如要為 Pod 核發憑證,請建立 CA 服務集區和下列憑證授權單位 (CA):

  • 根 CA。這是所有核發的 Mesh 憑證的信任根。如果您有現有的根 CA,可以使用該 CA。在 enterprise 層級建立根 CA,這類 CA 適用於長期且數量較少的憑證核發作業。
  • 從屬 CA。這個 CA 會為工作負載核發憑證。在部署叢集的區域中建立子 CA。在 devops 層級建立子 CA,這類 CA 用於核發短期大量憑證。

建立從屬 CA 是可選的做法,但我們強烈建議您建立一個,而非使用根 CA 核發 GKE 網格憑證。如果您決定使用根 CA 核發網格憑證,請確認預設的以設定為準核發模式仍可使用。

子 CA 可以位於與叢集不同的區域,但我們強烈建議您在與叢集相同的區域中建立子 CA,以便提升效能。不過,您可以在不同的區域建立根 CA 和從屬 CA,不會影響效能或可用性。

CA 服務支援以下地區:

地區名稱 地區說明
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。如果該使用者是目前的使用者,您可以使用殼層指令 $(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
    • 核發網格憑證 (ISSUING_CA_POOL_URI) 的 CA 完整 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 集區 (ROOT_CA_POOL_URI) 的完整 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
    

使用 NEG 建立無 Proxy gRPC 服務

如要使用 PSM 安全性,您需要使用無 Proxy gRPC 伺服器,才能使用 xDS 從 Cloud Service Mesh 取得安全性設定。這個步驟類似於 PSM 負載平衡設定指南中的「使用 NEG 設定 GKE 服務」,但您會使用 grpc-java 存放區中的 xDS 範例中支援 xDS 的 helloworld 伺服器,而非 java-example-hostname 映像檔。

您可以在由 openjdk:8-jdk 映像檔建構的容器中建構及執行此伺服器。您也使用命名的 NEG 功能,可讓您為 NEG 指定名稱。這樣一來,後續步驟就會簡化,因為部署作業會知道 NEG 的名稱,而不需要查詢。

以下是 gRPC 伺服器 Kubernetes 規格的完整範例。請注意下列事項:

  • 規格會建立 Kubernetes 服務帳戶 example-grpc-server,供 gRPC 伺服器 Pod 使用。
  • 規格會使用服務 cloud.google.com/neg 註解中的 name 欄位,指定 NEG 名稱 example-grpc-server
  • 變數 ${PROJNUM} 代表專案的專案號碼。
  • 規格會使用 initContainers 區段執行啟動產生器,填入無 Proxy 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

  1. 執行下列指令,確認專案編號設定正確無誤:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立規格:

    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++

  1. 執行下列指令,確認專案編號設定正確無誤:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立規格:

    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

  1. 執行下列指令,確認專案編號設定正確無誤:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立規格:

    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

  1. 執行下列指令,確認專案編號設定正確無誤:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立規格:

    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
    

    請按照下列步驟完成程序。

  1. 套用規格:

    kubectl apply -f example-grpc-server.yaml
    
  2. 將必要角色授予服務帳戶:

    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
    
  3. 執行下列指令,確認服務和 Pod 已正確建立:

    kubectl get deploy/example-grpc-server
    kubectl get svc/example-grpc-server
    
  4. 確認 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 做為純文字健康狀態檢查通訊埠。由於 50051 是 gRPC 應用程式伺服器通訊埠,因此本範例會使用 50052 做為健康狀態檢查通訊埠。

在第二種方法中,您可以設定健康狀態檢查,只檢查應用程式服務通訊埠的 TCP 連線。這項檢查只會檢查連線情形,而且在 TLS 握手失敗時,也會產生不必要的伺服器流量。因此,我們建議您採用第一種方法。

  1. 建立健康狀態檢查。請注意,您必須建立並啟動伺服器,系統才會開始進行健康狀態檢查。

    • 如果您要建立專用服務通訊埠來進行健康檢查 (這是我們建議的方法),請使用以下指令:

      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
      
  2. 建立防火牆。請確認 --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
    
  3. 建立後端服務:

    gcloud compute backend-services create grpc-gke-helloworld-service \
       --global \
       --load-balancing-scheme=INTERNAL_SELF_MANAGED \
       --protocol=GRPC \
       --health-checks grpc-gke-helloworld-hc
    
  4. 將 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 Kubernetes Engine 和無 Proxy 的 gRPC 服務設定 Cloud Service Mesh建立路由規則對應的方式類似。

  1. 建立網址對應:

    gcloud compute url-maps create grpc-gke-url-map \
       --default-service grpc-gke-helloworld-service
    
  2. 將路徑比對器新增至網址對應:

    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
    
  3. 建立目標 gRPC Proxy:

    gcloud compute target-grpc-proxies create grpc-gke-proxy \
       --url-map grpc-gke-url-map --validate-for-proxyless
    
  4. 建立轉送規則:

    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
    

使用無 Proxy 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 伺服器端使用 certificateProvicerInstance 外掛程式設定,該設定會以 google_cloud_private_spiffe 名稱識別身分憑證,而這項憑證是 serverCertificate 的一部分。mtlsPolicy 區段會指出 mTLS 安全性,並使用與 clientValidationCa 的插件設定相同的 google_cloud_private_spiffe,這是根 (驗證) 憑證規格。

接下來,請建立端點政策。這會指定後端 (例如 gRPC 伺服器) 使用通訊埠 50051 和任何中繼資料標籤 (或不使用任何中繼資料標籤) 時,會收到名為 server-mtls-policy 的附加伺服器 TLS 政策。您可以使用 MATCH_ALL 指定中繼資料標籤。您可以使用暫時性檔案 ep-mtls-psms.yaml 建立端點政策,該檔案包含使用您已定義的政策的端點政策資源值。

  1. 在目前目錄中,使用伺服器 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
    
  2. 匯入暫時性檔案 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
    
  3. 建立臨時檔案 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
    
  4. 匯入 ep-mtls-psms.yaml 檔案,建立端點政策資源:

    gcloud beta network-services endpoint-policies import ep-mtls-psms \
      --source=ep-mtls-psms.yaml --location=global
    

在用戶端設定 mTLS

用戶端安全性政策已附加至後端服務。當用戶端透過後端服務存取後端 (gRPC 伺服器) 時,系統會將附加的用戶端安全性政策傳送至用戶端。

  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. 匯入暫時性檔案 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
    
  3. 在暫存檔案中建立程式碼片段,以便參照這項政策,並在 SecuritySettings 訊息中新增 subjectAltNames 的詳細資料,如以下範例所示。將 ${PROJECT_ID} 替換為您的專案 ID 值,也就是先前所述 ${PROJECT_ID} 環境變數的值。請注意,subjectAltNames 中的 example-grpc-server 是 Kubernetes 服務帳戶名稱,用於部署規格中的 gRPC 伺服器 Pod。

    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
    
  4. 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 設定現已完成,包括伺服器和用戶端安全性。接下來,您將準備及執行伺服器和用戶端工作負載。這樣就完成範例。

建立無 Proxy 的 gRPC 用戶端

這個步驟與前一個部分「建立無 Proxy gRPC 服務」類似。您會使用 grpc-java 存放區中 xDS 範例目錄中的 xDS 支援 helloworld 用戶端。您會在以 openjdk:8-jdk 映像檔建構的容器中建構及執行用戶端。gRPC 用戶端 Kubernetes 規格會執行下列操作。

  • 它會建立 Kubernetes 服務帳戶 example-grpc-client,供 gRPC 用戶端 Pod 使用。
  • ${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

  1. 執行下列指令,確認專案編號設定正確無誤:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立以下規格:

    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++

  1. 執行下列指令,確認專案編號設定正確無誤:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立以下規格:

    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

  1. 執行下列指令,確保已正確設定專案編號:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立以下規格:

    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

  1. 執行下列指令,確保已正確設定專案編號:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 建立以下規格:

    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
    

請按照下列步驟完成程序。

  1. 套用規格:

    kubectl apply -f example-grpc-client.yaml
    
  2. 將必要角色授予服務帳戶:

    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
    
  3. 確認用戶端 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

  1. 取得為 example-grpc-server 服務建立的 Pod 名稱:

    kubectl get pods | grep example-grpc-server
    

    您會看到類似以下的意見回饋:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. 開啟一個通往伺服器 Pod 的殼層:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. 在 Shell 中,確認 /tmp/grpc-xds/td-grpc-bootstrap.json 中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。

  4. 下載 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
    
  5. 使用 --xds-creds 標記執行伺服器,以表示啟用 xDS 的安全性,並使用 50051 做為監聽通訊埠,以及 xds-server 做為伺服器識別名稱:

    ./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
    
  6. 伺服器從 Cloud Service Mesh 取得必要設定後,您會看到以下輸出內容:

    Listening on port 50051
    plain text health service listening on port 50052
    

C++

  1. 取得為 example-grpc-server 服務建立的 Pod 名稱:

    kubectl get pods | grep example-grpc-server
    

    您會看到類似以下的意見回饋:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. 開啟一個通往伺服器 Pod 的殼層:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. 在 Shell 中,確認 /tmp/grpc-xds/td-grpc-bootstrap.json 中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。

  4. 下載 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
    
  5. 使用 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
    
  6. 伺服器從 Cloud Service Mesh 取得必要設定後,您會看到以下輸出內容:

    Listening on port 50051
    plain text health service listening on port 50052
    

Python

  1. 取得為 example-grpc-server 服務建立的 Pod 名稱:

    kubectl get pods | grep example-grpc-server
    

    您會看到類似以下的意見回饋:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. 開啟一個通往伺服器 Pod 的殼層:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. 在 Shell 中,確認 /tmp/grpc-xds/td-grpc-bootstrap.json 中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。

  4. 下載 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
    

  5. 請使用 --xds-creds 標記執行伺服器,以便指示啟用 xDS 的安全性,並使用 50051 做為接聽通訊埠。

    python3 server.py 50051 --xds-creds
    
  6. 伺服器從 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

  1. 取得為 example-grpc-server 服務建立的 Pod 名稱:

    kubectl get pods | grep example-grpc-server
    

    您會看到類似以下的意見回饋:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. 開啟一個通往伺服器 Pod 的殼層:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
    
  3. 在 Shell 中,確認 /tmp/grpc-xds/td-grpc-bootstrap.json 中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。

  4. 下載 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
    
    
  5. 使用 --xds_creds 標記建構及執行伺服器,以便指出啟用 xDS 的安全性,並使用 50051 做為監聽通訊埠:

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \
      go run main.go \
      -xds_creds \
      -port 50051
    
  6. 伺服器從 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

  1. 取得用戶端 Pod 的名稱:

    kubectl get pods | grep example-grpc-client
    

    您會看到類似以下的意見回饋:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. 開啟一個通往用戶端 Pod 的殼層:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. 在指令碼 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
    
  4. 使用 --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++

  1. 取得用戶端 Pod 的名稱:

    kubectl get pods | grep example-grpc-client
    

    您會看到類似以下的意見回饋:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. 開啟一個通往用戶端 Pod 的殼層:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. 進入 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
    
  4. 使用 --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

  1. 取得用戶端 Pod 的名稱:

    kubectl get pods | grep example-grpc-client
    

    您會看到類似以下的意見回饋:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. 開啟一個通往用戶端 Pod 的殼層:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. 進入殼層後,請下載 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
    
  4. 使用 --xds-creds 標記執行用戶端,以表示啟用 xDS 的安全性、用戶端名稱和目標連結字串:

    python3 client.py xds:///helloworld-gke:8000 --xds-creds
    

    畫面會顯示類似以下的輸出:

    Greeter client received: Hello you from example-host!
    

Go

  1. 取得用戶端 Pod 的名稱:

    kubectl get pods | grep example-grpc-client
    

    您會看到類似以下的意見回饋:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. 開啟一個通往用戶端 Pod 的殼層:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
    
  3. 進入殼層後,請下載 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
    
  4. 使用 --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

以下操作說明會建立授權政策,允許 example-grpc-client 帳戶傳送要求,其中主機名稱為 helloworld-gke:8000,且連接埠為 50051

gcloud

  1. 建立名為 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
    
  2. 匯入政策。

    gcloud network-security authorization-policies import \
      helloworld-gke-authz-policy \
      --source=helloworld-gke-authz-policy.yaml \
      --location=global
    
  3. 將下列內容附加至檔案 ep-mtls-psms.yaml,藉此更新端點政策,以便參照新的授權政策。

    authorizationPolicy: projects/${PROJECT_ID}/locations/global/authorizationPolicies/helloworld-gke-authz-policy
    

    端點政策現在會指定,對於 gRPC 啟動檔案包含 app:helloworld 標籤的 Pod 傳入要求,必須同時套用 mTLS 和授權政策。

  4. 匯入政策:

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

驗證授權政策

請按照這些操作說明,確認授權政策是否正常運作。

Java

  1. 開啟一個通往先前用過的用戶端 Pod 的殼層。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. 在指令介面中執行下列指令,驗證設定。

    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
    
  3. 請再次使用其他伺服器名稱執行用戶端。請注意,這是失敗案例。由於授權政策只允許存取 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

  1. 開啟一個通往先前用過的用戶端 Pod 的殼層。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. 在指令介面中執行下列指令,驗證設定。

    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
    
  3. 請再次使用其他伺服器名稱執行用戶端。請注意,這是失敗案例。由於授權政策只允許存取 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 只需要進行一些小變更。

  1. ServerTlsPolicy 中放置 mtlsPolicy

    cat << EOF > server-tls-policy.yaml
    name: "server-tls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    
  2. 請改為在 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
    
  3. mTLS 的 ClientTlsPolicy 也適用於 TLS 情況,但政策的 clientCertificate 部分可以刪除,因為 TLS 不需要這個部分:

    cat << EOF > client-tls-policy.yaml
    name: "client-tls-policy"
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    

在錢包範例中使用服務安全性

本節將概略說明如何在 Java、C++ 和 Go 中,透過服務安全性啟用錢包範例

Java

您可以在 github 上找到 Java 的範例原始碼。設定無 Proxy 安全性時,程式碼已使用 XdsChannelXdsServer 憑證。

這些操作說明說明如何使用 Go 設定錢包範例。Java 的程序類似。這些操作說明會使用您從 Google Cloud 容器存放區取得的現有 Docker 映像檔。

如要建立範例,請按照下列操作說明進行:

  1. 複製存放區,並取得 gRPC 範例目錄中的檔案。
  2. 編輯 00-common-env.sh 檔案。將設定 WALLET_DOCKER_IMAGE 值為 Go Docker 映像檔的現有行註解,並取消註解設定 WALLET_DOCKER_IMAGE 值為 Java Docker 映像檔的行。
  3. 按照「建立及設定 Cloud Router 執行個體」一文中的指示,建立及設定 Cloud Router 執行個體,或是使用 10.apis.sh 指令碼中的 create_cloud_router_instances 函式。
  4. 使用hello world 範例的操作說明或指令碼 20-cluster.sh 中的函式 create_cluster 建立叢集。
  5. 使用CA 服務的操作說明或指令碼 30-private-ca-setup.sh 建立私人憑證授權單位。
  6. 使用指令碼 40-k8s-resources.sh,為所有服務建立 Kubernetes 資源,包括服務帳戶、命名空間、Kubernetes 服務、NEG 和伺服器端部署:accountstatsstats_premiumwallet_v1wallet_v2
  7. 針對您建立的每項服務,請在 50-td-components.sh 指令碼中使用 create_health_checkcreate_backend_service 建立健康狀態檢查和後端服務。
  8. 在指令碼 60-routing-components.sh 中使用 create_routing_components 建立 Cloud Service Mesh 路由元件。
  9. 70-security-components.sh 指令碼中使用 create_security_components,為每項後端服務建立 Cloud Service Mesh 安全性元件。
  10. 在指令碼 75-client-deployment.sh 中使用 create_client_deployment 建立 Wallet 用戶端部署作業。
  11. 使用 grpc-wallet 用戶端驗證一文所述,啟動用戶端即可驗證設定。

C++

您可以在 github 上找到 C++ 的範例原始碼。設定無 Proxy 安全性時,程式碼已使用 XdsChannelXdsServer 憑證。

這些操作說明說明如何使用 Go 設定錢包範例。C++ 的程序類似。這些操作說明會使用您從 Google Cloud 容器存放區取得的現有 Docker 映像檔。

如要建立範例,請按照下列操作說明進行:

  1. 複製存放區,並取得 gRPC 範例目錄中的檔案。
  2. 編輯 00-common-env.sh 檔案。將設定 WALLET_DOCKER_IMAGE 值為 Go Docker 映像檔的現有行註解,並取消註解設定 WALLET_DOCKER_IMAGE 值為 C++ Docker 映像檔的行。
  3. 按照「建立及設定 Cloud Router 執行個體」一文中的指示,建立及設定 Cloud Router 執行個體,或是使用 10.apis.sh 指令碼中的 create_cloud_router_instances 函式。
  4. 使用hello world 範例的操作說明或指令碼 20-cluster.sh 中的函式 create_cluster 建立叢集。
  5. 使用CA 服務的操作說明或指令碼 30-private-ca-setup.sh 建立私人憑證授權單位。
  6. 使用指令碼 40-k8s-resources.sh,為所有服務建立 Kubernetes 資源,包括服務帳戶、命名空間、Kubernetes 服務、NEG 和伺服器端部署:accountstatsstats_premiumwallet_v1wallet_v2
  7. 針對您建立的每項服務,請在 50-td-components.sh 指令碼中使用 create_health_checkcreate_backend_service 建立健康狀態檢查和後端服務。
  8. 在指令碼 60-routing-components.sh 中使用 create_routing_components 建立 Cloud Service Mesh 路由元件。
  9. 70-security-components.sh 指令碼中使用 create_security_components,為每項後端服務建立 Cloud Service Mesh 安全性元件。
  10. 在指令碼 75-client-deployment.sh 中使用 create_client_deployment 建立 Wallet 用戶端部署作業。
  11. 使用 grpc-wallet 用戶端驗證一文所述,啟動用戶端即可驗證設定。

Go

您可以在 github 上找到 Go 的原始碼範例。設定無 Proxy 安全性時,程式碼已使用 XdsChannelXdsServer 憑證。

操作說明會使用您從 Google Cloud 容器存放區取得的現有 Docker 映像檔。

如要建立範例,請按照下列操作說明進行:

  1. 複製存放區,並取得 gRPC 範例目錄中的檔案。
  2. 編輯 00-common-env.sh 檔案,為環境變數設定正確的值。
  3. 按照「建立及設定 Cloud Router 執行個體」一文中的指示,建立及設定 Cloud Router 執行個體,或是使用 10.apis.sh 指令碼中的 create_cloud_router_instances 函式。
  4. 使用hello world 範例的操作說明或指令碼 20-cluster.sh 中的函式 create_cluster 建立叢集。
  5. 使用CA 服務的操作說明或指令碼 30-private-ca-setup.sh 建立私人憑證授權單位。
  6. 使用指令碼 40-k8s-resources.sh,為所有服務建立 Kubernetes 資源,包括服務帳戶、命名空間、Kubernetes 服務、NEG 和伺服器端部署:accountstatsstats_premiumwallet_v1wallet_v2
  7. 針對您建立的每項服務,請在 50-td-components.sh 指令碼中使用 create_health_checkcreate_backend_service 建立健康狀態檢查和後端服務。
  8. 在指令碼 60-routing-components.sh 中使用 create_routing_components 建立 Cloud Service Mesh 路由元件。
  9. 70-security-components.sh 指令碼中使用 create_security_components,為每項後端服務建立 Cloud Service Mesh 安全性元件。
  10. 在指令碼 75-client-deployment.sh 中使用 create_client_deployment 建立 Wallet 用戶端部署作業。
  11. 使用 grpc-wallet 用戶端驗證一文所述,啟動用戶端即可驗證設定。

啟動檔案

本指南中的設定程序會使用啟動產生器建立所需的啟動檔案。本節提供引導檔案本身的參考資訊。

這個啟動檔案包含無 Proxy 的 gRPC 程式碼所需的設定資訊,包括 xDS 伺服器的連線資訊。這個啟動檔案包含無 Proxy gRPC 安全性功能所需的安全性設定。gRPC 伺服器需要額外一個欄位,請參閱下列各節。以下是 Bootstrap 檔案範例:

{
  "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 第 3 版使用方式的變更:

node 中的 id 欄位會為 gRPC 用戶端提供 Cloud Service Mesh 的專屬 ID。您必須使用節點 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 擷取 Listener 資源,以便執行伺服器端安全性。

引導檔案中的安全性設定欄位

JSON 金鑰 類型 附註
server_listener_resource_name_template 字串 grpc/server?xds.resource.listening_address=%s 這是 gRPC 伺服器的必要值。gRPC 會使用這個值來組成資源名稱,以便從 Cloud Service Mesh 擷取「Listener」資源,用於伺服器端安全性和其他設定。gRPC 會使用這個值來組成資源名稱字串
certificate_providers JSON 結構 google_cloud_private_spiffe 這是必要旗標,這個值是 JSON 結構體,代表將名稱對應至憑證提供者執行個體的對應項目。憑證提供者執行個體用於擷取身分和根憑證。範例啟動檔案包含一個名稱:google_cloud_private_spiffe,其中證書提供者執行個體 JSON 結構體為值。每個憑證提供者例項 JSON 結構體都有兩個欄位:
  • plugin_name:這個必要值會指出要使用的憑證提供者外掛程式,以符合 gRPC 憑證提供者外掛程式架構的要求。gRPC 內建支援這個設定中使用的檔案監視器外掛程式。plugin_name 為 file_watcher
  • config:這是必要值,可識別 file_watcher 外掛程式的 JSON 設定檔案。結構定義和內容取決於外掛程式。

file_watcher 外掛程式的 config JSON 結構內容如下:

  • certificate_file:必要字串。這個值是身分憑證的位置。
  • private_key_file:必要字串。這個值是私密金鑰檔案的位置,應與身分憑證相符。
  • ca_certificate_file:必要字串。這個值是根憑證的位置,也稱為信任組合。
  • refresh_interval:選用字串。這個值會指出重新整理間隔,並使用 Duration 的 JSON 對應字串表示法指定。預設值為「600s」,即 10 分鐘。

Bootstrap 產生器

引導程序產生器容器映像檔可在 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:使用這個標記,在 Bootstrap 檔案中填入節點中繼資料。在 EndpointPolicy 中使用中繼資料標籤比對工具時,必須執行這項操作,因為 Cloud Service Mesh 會使用引導檔案節點中繼資料部分提供的標籤資料。引數以「鍵=值」的格式提供,例如:--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 範圍。
  • 防火牆上的目標標記與您建立的叢集中的標記不符。

工作負載無法在安全性設定中進行通訊

如果在為無 Proxy 服務網格設定安全性後,工作負載無法進行通訊,請按照下列操作說明找出原因。

  1. 停用無 Proxy 安全性,並解決無 Proxy 服務網狀負載平衡用例中的問題。如要停用網格的安全性功能,請執行下列任一操作:
    1. 在用戶端和伺服器端使用純文字憑證,或
    2. 請勿在 Cloud Service Mesh 設定中為後端服務和端點政策設定安全性。

因為部署中沒有安全性設定,請按照排解無 Proxy 的 Cloud Service Mesh 部署問題中的步驟操作。

  1. 修改工作負載,以便使用含有平文或不安全憑證的 xDS 憑證做為備用憑證。如先前所述,請保留 Cloud Service Mesh 設定,並停用安全性功能。在這種情況下,雖然 gRPC 允許 Cloud Service Mesh 設定安全性,但 Cloud Service Mesh 不會傳送安全性資訊,因此 gRPC 應改用純文字 (或不安全) 憑證,這應與先前所述的第一種情況類似。如果這個做法無法解決問題,請執行下列操作:

    1. 請在用戶端和伺服器端提高記錄層級,以便查看 gRPC 和 Cloud Service Mesh 之間交換的 xDS 訊息。
    2. 請確認 Cloud Service Mesh 在傳送至工作負載的 CDS 和 LDS 回應中未啟用安全性。
    3. 請確認工作負載不會在管道中使用 TLS 或 mTLS 模式。如果您看到任何與 TLS 握手相關的記錄訊息,請檢查應用程式原始碼,並確認您使用不安全或純文字做為備用憑證。如果應用程式原始碼正確,這可能是 gRPC 程式庫中的錯誤
  2. 請按照使用者指南中的疑難排解步驟,確認 CA 服務與 GKE 的整合功能是否正常運作。請確認該功能提供的憑證和金鑰是否已在指定目錄 /var/run/secrets/workload-spiffe-credentials/ 中提供。

  3. 如先前所述,在網格中啟用 TLS (而非 mTLS),然後重新啟動用戶端和伺服器工作負載。

    1. 請提高用戶端和伺服器端的記錄層級,以便查看 gRPC 和 Cloud Service Mesh 之間交換的 xDS 訊息。
    2. 請確認 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 程式庫,請執行下列操作:

  1. 確認 Pod 規格包含 使用 NEG 建立無 Proxy gRPC 服務一文所述的 security.cloud.google.com/use-workload-certificates 註解。

  2. 請確認包含憑證鏈結的檔案,以及葉憑證、私密金鑰和信任的 CA 憑證,可透過 Pod 中的以下路徑存取:

    1. 憑證鏈結和分葉憑證:"/var/run/secrets/workload-spiffe-credentials/certificates.pem"
    2. 私密金鑰:「/var/run/secrets/workload-spiffe-credentials/private_key.pem」
    3. CA 套件:"/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem"
  3. 如果無法取得上一個步驟中的憑證,請執行下列操作:

      gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME 
    --location=LOCATION

    1. 確認 GKE 控制層已繫結正確的 IAM 角色,並授予該角色存取 CA 服務的權限:

      # 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.
      
    2. 確認憑證未過期。這是 /var/run/secrets/workload-spiffe-credentials/certificates.pem 中的憑證鏈和分葉憑證。如要檢查,請執行下列指令:

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
      

    3. 請執行以下指令,確認應用程式支援的金鑰類型:

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
      

    4. 請確認 gRPC Java 應用程式在 WorkloadCertificateConfig YAML 檔案中具有下列 keyAlgorithm

      keyAlgorithm:
        rsa:
          modulusSize: 4096
    
  4. 確認 CA 使用與憑證金鑰相同的金鑰系列。

應用程式憑證遭到用戶端、伺服器或對等端拒絕

  1. 確認對等應用程式使用相同信任套件來驗證憑證。
  2. 確認使用的憑證未過期 (憑證鏈結和分葉憑證:"/var/run/secrets/workload-spiffe-credentials/certificates.pem")。

Pod 仍處於待處理狀態

如果 Pod 在設定程序期間維持在待處理狀態,請在部署規格中增加 Pod 的 CPU 和記憶體資源。

無法使用 --enable-mesh-certificates 標記建立叢集

請確認您執行的是最新版的 gcloud 指令列:

gcloud components update

請注意,--enable-mesh-certificates 標記僅適用於 gcloud beta

Pod 無法啟動

如果憑證佈建失敗,使用 GKE 網格憑證的 Pod 可能無法啟動。這可能發生在以下情況:

  • WorkloadCertificateConfigTrustConfig 設定錯誤或遺漏。
  • 客戶服務回應未獲核准。

您可以檢查 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. 選擇 CSR,該 CSR 必須為 Approved 且不是 Issued,或不是 Approved

  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 的疑難排解資訊。

Pod 缺少憑證

  1. 取得 Pod 的 Pod 規格:

    kubectl get pod -n POD_NAMESPACE POD_NAME -o yaml
    

    更改下列內容:

    • POD_NAMESPACE:Pod 的命名空間。
    • POD_NAME:Pod 名稱。
  2. 請確認 Pod 規格包含「設定 Pod 以接收 mTLS 憑證」一文中所述的 security.cloud.google.com/use-workload-certificates 註解。

  3. 確認 GKE 網格憑證的存取控制器是否已成功將 workloadcertificates.security.cloud.google.com 類型的 CSI 驅動程式磁碟區注入 Pod 規格:

    volumes:
    ...
    -csi:
      driver: workloadcertificates.security.cloud.google.com
      name: gke-workload-certificates
    ...
    
  4. 檢查每個容器中是否有磁碟區掛接:

    containers:
    - name: ...
      ...
      volumeMounts:
      - mountPath: /var/run/secrets/workload-spiffe-credentials
        name: gke-workload-certificates
        readOnly: true
      ...
    
  5. 請確認下列憑證套件和私密金鑰是否可在 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
  6. 如果檔案無法使用,請執行下列步驟:

    1. 擷取叢集的 CA 服務 (預先發布版) 例項:

      kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'
      
    2. 擷取 CA 服務 (預先發布版) 執行個體的狀態:

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

      更改下列內容:

      • ISSUING_CA_TYPE:核發憑證授權單位類型,必須是 subordinatesroots
      • ISSUING_CA_NAME:核發 CA 的名稱。
      • ISSUING_CA_LOCATION:核發 CA 的區域。
    3. 取得根 CA 的 IAM 政策:

      gcloud privateca roots get-iam-policy ROOT_CA_NAME
      

      ROOT_CA_NAME 替換為根 CA 的名稱。

    4. 在 IAM 政策中,確認 privateca.auditor 政策繫結是否存在:

      ...
      - members:
        - serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.auditor
      ...
      

      在本例中,PROJECT_NUMBER 是叢集的專案編號。

    5. 取得子 CA 的 IAM 政策:

      gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAME
      

      SUBORDINATE_CA_NAME 替換為子 CA 名稱。

    6. 在 IAM 政策中,確認是否有 privateca.certificateManager 政策繫結:

      ...
      - members:
        - serviceAccount: service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.certificateManager
      ...
      

      在本例中,PROJECT_NUMBER 是叢集的專案編號。

應用程式無法使用核發的 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 服務 (預先發布版) 執行個體的狀態:

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

      更改下列內容:

      • ISSUING_CA_TYPE:核發憑證授權單位類型,必須是 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 憑證重新載入 API

  4. 請確認工作負載與 CA 位於相同的信任網域。GKE 網格憑證可支援單一信任網域中工作負載之間的通訊。

限制

只有 GKE 支援 Cloud Service Mesh 服務安全性。您無法使用 Compute Engine 部署服務安全性。

Cloud Service Mesh 不支援以下情況:有兩個以上的端點政策資源與端點相符,例如兩個具有相同標籤和連接埠的政策,或是兩個以上具有不同標籤的政策,且這些政策與端點的標籤相符。如要進一步瞭解如何將端點政策與端點的標籤進行比對,請參閱 EndpointPolicy.EndpointMatcher.MetadataLabelMatcher 的 API。在這種情況下,Cloud Service Mesh 不會根據任何衝突的政策產生安全性設定。