使用無 Proxy gRPC (舊版) 設定服務安全性
本指南說明如何為無 Proxy gRPC 服務網格設定安全性服務。
本文僅適用於搭配負載平衡 API 使用的 Cloud Service Mesh。這是舊版文件。
需求條件
為無 Proxy gRPC 服務網格設定服務安全性前,請確認您符合下列需求。
- 您的部署作業符合「準備使用無 Proxy gRPC 設定 Cloud Service Mesh」一文中的規定。
- 您必須使用 xDS 第 3 版。
- 您可以使用下列任一語言存取所需的 xDS 版本和憑證提供者函式:
- gRPC Java
- gRPC C++
- gRPC Python
- gRPC Go 您可以在 github 上找到所需語言版本
- 您可以使用 Bootstrap Generator 0.13.0 版。引導程序產生器映像檔位於 Google Cloud 容器存放區中。
- 您已符合 gRPC 無 Proxy 服務網格負載平衡的所有必要條件。
- 您具備足夠的權限,可建立或更新 Cloud Service Mesh 和Google Cloud 服務網格資源,以便使用無 Proxy 服務網格 (PSM) 安全性。如需有關所需權限的完整資訊,請參閱準備使用無 Proxy gRPC 服務設定 Cloud Service Mesh。
- 您具備使用憑證授權單位服務的必要權限,詳情請參閱「建立憑證授權單位以核發憑證」
設定身分與存取權管理
您必須具備使用 Google Kubernetes Engine 所需的權限。您至少必須具備下列角色:
roles/container.clusterAdmin
GKE 角色roles/compute.instanceAdmin
Compute Engine 角色roles/iam.serviceAccountUser
角色
如要建立設定所需的資源,您必須具備 compute.NetworkAdmin
角色。這個角色包含所有必要權限,可用於建立、更新、刪除、列出及使用 (也就是在其他資源中參照) 必要資源。如果您是專案的擁有者/編輯者,就會自動獲得這個角色。
請注意,如果您在後端服務和目標 HTTPS Proxy 資源中參照這些資源,系統就不會強制執行 networksecurity.googleapis.com.clientTlsPolicies.use
和 networksecurity.googleapis.com.serverTlsPolicies.use
。
如果日後實施這項規定,且您使用的是 compute.NetworkAdmin
角色,則在實施這項檢查時,您不會發現任何問題。
如果您使用的是自訂角色,且日後會強制執行這項檢查,請務必加入相應的 .use
權限。否則,您日後可能會發現自訂角色沒有必要的權限,無法分別從後端服務或指定的 HTTPS Proxy 參照 clientTlsPolicy
或 serverTlsPolicy
。
準備設定
根據無 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 的主要增強功能如下:
- 設定 CA 服務,建立私人 CA 集區和必要的憑證授權單位。
- 使用 GKE Workload Identity Federation for GKE 和網格憑證功能,以及 CA 服務整合功能建立 GKE 叢集。
- 在叢集上設定網格憑證核發作業。
- 建立用戶端和伺服器服務帳戶。
- 設定範例伺服器,使用 xDS API 和 xDS 伺服器憑證,從 Cloud Service Mesh 取得安全性設定。
- 設定使用 xDS 憑證的範例用戶端。
- 更新 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 的存取權。
執行下列指令,啟用 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
執行下列指令,允許預設服務帳戶存取 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 叢集,並使用網格憑證進行設定,如建立憑證授權單位以核發憑證一文所述。
建立使用 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
叢集建立作業可能需要幾分鐘才能完成。
如果您使用現有叢集,請啟用 Workload Identity Federation for GKE 和 GKE 網格憑證。請確認叢集是使用
--enable-ip-alias
旗標建立的,因為update
指令無法使用該旗標。gcloud container clusters update CLUSTER_NAME \ --enable-mesh-certificates
執行下列指令,將新叢集設為
kubectl
指令的預設叢集:gcloud container clusters get-credentials CLUSTER_NAME \ --zone ZONE
向機群註冊叢集
將您在「建立 GKE 叢集」中建立或更新的叢集註冊至機群。註冊叢集後,您就能更輕鬆地在多個專案中設定叢集。
請注意,每個步驟最多可能需要十分鐘才能完成。
向機群註冊叢集:
gcloud container fleet memberships register CLUSTER_NAME \ --gke-cluster=ZONE/CLUSTER_NAME \ --enable-workload-identity --install-connect-agent \ --manifest-output-file=MANIFEST-FILE_NAME
請依下列方式替換變數:
- CLUSTER_NAME:叢集名稱。
- ZONE:叢集所在的可用區。
- MANIFEST-FILE_NAME:這些指令產生註冊資訊清單的路徑。
註冊程序成功後,您會看到類似以下的訊息:
Finished registering the cluster CLUSTER_NAME with the fleet.
將產生的資訊清單檔案套用至叢集:
kubectl apply -f MANIFEST-FILE_NAME
申請程序成功後,您會看到類似以下的訊息:
namespace/gke-connect created serviceaccount/connect-agent-sa created podsecuritypolicy.policy/gkeconnect-psp created role.rbac.authorization.k8s.io/gkeconnect-psp:role created rolebinding.rbac.authorization.k8s.io/gkeconnect-psp:rolebinding created role.rbac.authorization.k8s.io/agent-updater created rolebinding.rbac.authorization.k8s.io/agent-updater created role.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created clusterrole.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created clusterrolebinding.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created clusterrolebinding.rbac.authorization.k8s.io/gke-connect-feature-authorizer-20210416-01-00 created rolebinding.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created role.rbac.authorization.k8s.io/gke-connect-namespace-getter created rolebinding.rbac.authorization.k8s.io/gke-connect-namespace-getter created secret/http-proxy created deployment.apps/gke-connect-agent-20210416-01-00 created service/gke-connect-monitoring created secret/creds-gcp create
從叢集取得會員資源:
kubectl get memberships membership -o yaml
輸出內容應包含車隊指派的工作負載身分池,其中 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
將 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
將 CA 服務的
role/privateca.admin
角色授予需要修改 IAM 政策的使用者,其中MEMBER
是需要此存取權的使用者,具體來說,是指執行下列授予privateca.auditor
和privateca.certificateManager
角色步驟的任何使用者:gcloud projects add-iam-policy-binding PROJECT_ID \ --member=MEMBER \ --role=roles/privateca.admin
建立根 CA 服務集區。
gcloud privateca pools create ROOT_CA_POOL_NAME \ --location ROOT_CA_POOL_LOCATION \ --tier enterprise
建立根 CA。
gcloud privateca roots create ROOT_CA_NAME --pool ROOT_CA_POOL_NAME \ --subject "CN=ROOT_CA_NAME, O=ROOT_CA_ORGANIZATION" \ --key-algorithm="ec-p256-sha256" \ --max-chain-length=1 \ --location ROOT_CA_POOL_LOCATION
在這個示範設定中,請使用下列值做為變數:
- ROOT_CA_POOL_NAME=td_sec_pool
- ROOT_CA_NAME=pkcs2-ca
- ROOT_CA_POOL_LOCATION=us-east1
- ROOT_CA_ORGANIZATION="TestCorpLLC"
建立從屬集區和從屬 CA。確認預設的設定為發布模式仍可使用。
gcloud privateca pools create SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --tier devops
gcloud privateca subordinates create SUBORDINATE_CA_NAME \ --pool SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --issuer-pool ROOT_CA_POOL_NAME \ --issuer-location ROOT_CA_POOL_LOCATION \ --subject "CN=SUBORDINATE_CA_NAME, O=SUBORDINATE_CA_ORGANIZATION" \ --key-algorithm "ec-p256-sha256" \ --use-preset-profile subordinate_mtls_pathlen_0
在這個示範設定中,請使用下列值做為變數:
- SUBORDINATE_CA_POOL_NAME="td-ca-pool"
- SUBORDINATE_CA_POOL_LOCATION=us-east1
- SUBORDINATE_CA_NAME="td-ca"
- SUBORDINATE_CA_ORGANIZATION="TestCorpLLC"
- ROOT_CA_POOL_NAME=td_sec_pool
- ROOT_CA_POOL_LOCATION=us-east1
授予根 CA 集區的 IAM
privateca.auditor
角色,允許 GKE 服務帳戶存取:gcloud privateca pools add-iam-policy-binding ROOT_CA_POOL_NAME \ --location ROOT_CA_POOL_LOCATION \ --role roles/privateca.auditor \ --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
為子 CA 資源池授予 IAM
privateca.certificateManager
角色,允許 GKE 服務帳戶存取:gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_NAME \ --location SUBORDINATE_CA_POOL_LOCATION \ --role roles/privateca.certificateManager \ --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
儲存下列
WorkloadCertificateConfig
YAML 設定,告訴叢集如何核發網格憑證:apiVersion: security.cloud.google.com/v1 kind: WorkloadCertificateConfig metadata: name: default spec: # Required. The CA service that issues your certificates. certificateAuthorityConfig: certificateAuthorityServiceConfig: endpointURI: ISSUING_CA_POOL_URI # Required. The key algorithm to use. Choice of RSA or ECDSA. # # To maximize compatibility with various TLS stacks, your workloads # should use keys of the same family as your root and subordinate CAs. # # To use RSA, specify configuration such as: # keyAlgorithm: # rsa: # modulusSize: 4096 # # Currently, the only supported ECDSA curves are "P256" and "P384", and the only # supported RSA modulus sizes are 2048, 3072 and 4096. keyAlgorithm: rsa: modulusSize: 4096 # Optional. Validity duration of issued certificates, in seconds. # # Defaults to 86400 (1 day) if not specified. validityDurationSeconds: 86400 # Optional. Try to start rotating the certificate once this # percentage of validityDurationSeconds is remaining. # # Defaults to 50 if not specified. rotationWindowPercentage: 50
更改下列內容:
- 叢集執行所在專案的專案 ID:
PROJECT_ID
- 核發網格憑證 (ISSUING_CA_POOL_URI) 的 CA 完整 URI。這可以是從屬 CA (建議) 或根 CA。格式如下:
//privateca.googleapis.com/projects/PROJECT_ID/locations/SUBORDINATE_CA_POOL_LOCATION/caPools/SUBORDINATE_CA_POOL_NAME
- 叢集執行所在專案的專案 ID:
儲存下列
TrustConfig
YAML 設定,告訴叢集如何信任核發的憑證:apiVersion: security.cloud.google.com/v1 kind: TrustConfig metadata: name: default spec: # You must include a trustStores entry for the trust domain that # your cluster is enrolled in. trustStores: - trustDomain: PROJECT_ID.svc.id.goog # Trust identities in this trustDomain if they appear in a certificate # that chains up to this root CA. trustAnchors: - certificateAuthorityServiceURI: ROOT_CA_POOL_URI
更改下列內容:
- 叢集執行所在專案的專案 ID:
PROJECT_ID
- 根 CA 集區 (ROOT_CA_POOL_URI) 的完整 URI。格式如下:
//privateca.googleapis.com/projects/PROJECT_ID/locations/ROOT_CA_POOL_LOCATION/caPools/ROOT_CA_POOL_NAME
- 叢集執行所在專案的專案 ID:
將設定套用至叢集:
kubectl apply -f WorkloadCertificateConfig.yaml kubectl apply -f TrustConfig.yaml
使用 NEG 建立無 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
執行下列指令,確認專案編號設定正確無誤:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立規格:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: openjdk:8-jdk imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 800m memory: 512Mi requests: cpu: 100m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
C++
執行下列指令,確認專案編號設定正確無誤:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立規格:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Python
執行下列指令,確認專案編號設定正確無誤:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立規格:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Go
執行下列指令,確認專案編號設定正確無誤:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立規格:
cat << EOF > example-grpc-server.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-server namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: v1 kind: Service metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server annotations: cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}' spec: ports: - name: helloworld port: 8080 protocol: TCP targetPort: 50051 selector: k8s-app: example-grpc-server type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-server namespace: default labels: k8s-app: example-grpc-server spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-server strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-server spec: containers: - image: golang:1.16-alpine imagePullPolicy: IfNotPresent name: example-grpc-server command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" ports: - protocol: TCP containerPort: 50051 resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" - --node-metadata=app=helloworld resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-server volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
請按照下列步驟完成程序。
套用規格:
kubectl apply -f example-grpc-server.yaml
將必要角色授予服務帳戶:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \ ${PROJNUM}-compute@developer.gserviceaccount.com gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \ --role roles/trafficdirector.client
執行下列指令,確認服務和 Pod 已正確建立:
kubectl get deploy/example-grpc-server kubectl get svc/example-grpc-server
確認 NEG 名稱是否正確:
gcloud compute network-endpoint-groups list \ --filter "name=example-grpc-server" --format "value(name)"
先前的指令應會傳回 NEG 名稱
example-grpc-server
。
使用 Google Cloud 負載平衡器元件設定 Cloud Service Mesh
本節的步驟與使用負載平衡器元件設定 Cloud Service Mesh 的步驟類似,但有些變更,請參閱下文。
建立健康狀態檢查、防火牆規則和後端服務
當 gRPC 伺服器設定為使用 mTLS 時,gRPC 健康狀態檢查無法運作,因為健康狀態檢查用戶端無法向伺服器提供有效的用戶端憑證。您可以透過下列兩種方式解決這個問題。
在第一種方法中,您可以讓伺服器建立額外的服務通訊埠,並指定為健康檢查通訊埠。這會附加至特殊的健康狀態檢查服務,以純文字或 TLS 形式傳送至該通訊埠。
xDS helloworld
範例伺服器會使用 PORT_NUMBER
+ 1 做為純文字健康狀態檢查通訊埠。由於 50051 是 gRPC 應用程式伺服器通訊埠,因此本範例會使用 50052 做為健康狀態檢查通訊埠。
在第二種方法中,您可以設定健康狀態檢查,只檢查應用程式服務通訊埠的 TCP 連線。這項檢查只會檢查連線情形,而且在 TLS 握手失敗時,也會產生不必要的伺服器流量。因此,我們建議您採用第一種方法。
建立健康狀態檢查。請注意,您必須建立並啟動伺服器,系統才會開始進行健康狀態檢查。
如果您要建立專用服務通訊埠來進行健康檢查 (這是我們建議的方法),請使用以下指令:
gcloud compute health-checks create grpc grpc-gke-helloworld-hc \ --enable-logging --port 50052
如果您要建立 TCP 健康狀態檢查 (我們不建議這麼做),請使用下列指令:
gcloud compute health-checks create tcp grpc-gke-helloworld-hc \ --use-serving-port
建立防火牆。請確認
--target-tags
的值與您在「建立或更新 GKE 叢集」一節中為--tags
提供的值相符。gcloud compute firewall-rules create grpc-gke-allow-health-checks \ --network default --action allow --direction INGRESS \ --source-ranges 35.191.0.0/16,130.211.0.0/22 \ --target-tags allow-health-checks \ --rules tcp:50051-50052
建立後端服務:
gcloud compute backend-services create grpc-gke-helloworld-service \ --global \ --load-balancing-scheme=INTERNAL_SELF_MANAGED \ --protocol=GRPC \ --health-checks grpc-gke-helloworld-hc
將 NEG 附加至後端服務:
gcloud compute backend-services add-backend grpc-gke-helloworld-service \ --global \ --network-endpoint-group example-grpc-server \ --network-endpoint-group-zone ${ZONE} \ --balancing-mode RATE \ --max-rate-per-endpoint 5
建立轉送規則對應關係
這與使用 Google Kubernetes Engine 和無 Proxy 的 gRPC 服務設定 Cloud Service Mesh 中建立路由規則對應的方式類似。
建立網址對應:
gcloud compute url-maps create grpc-gke-url-map \ --default-service grpc-gke-helloworld-service
將路徑比對器新增至網址對應:
gcloud compute url-maps add-path-matcher grpc-gke-url-map \ --default-service grpc-gke-helloworld-service \ --path-matcher-name grpc-gke-path-matcher \ --new-hosts helloworld-gke:8000
建立目標 gRPC Proxy:
gcloud compute target-grpc-proxies create grpc-gke-proxy \ --url-map grpc-gke-url-map --validate-for-proxyless
建立轉送規則:
gcloud compute forwarding-rules create grpc-gke-forwarding-rule \ --global \ --load-balancing-scheme=INTERNAL_SELF_MANAGED \ --address=0.0.0.0 \ --target-grpc-proxy=grpc-gke-proxy \ --ports 8000 \ --network default
使用無 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
建立端點政策,該檔案包含使用您已定義的政策的端點政策資源值。
在目前目錄中,使用伺服器 TLS 政策資源的值建立臨時檔案
server-mtls-policy.yaml
:name: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-mtls-policy" serverCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe mtlsPolicy: clientValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffe
匯入暫時性檔案
server-mtls-policy.yaml
,建立名為server-mtls-policy
的伺服器 TLS 政策資源:gcloud network-security server-tls-policies import server-mtls-policy \ --source=server-mtls-policy.yaml --location=global
建立臨時檔案
ep-mtls-psms.yaml
以建立端點政策:name: "ep-mtls-psms" type: "GRPC_SERVER" serverTlsPolicy: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-mtls-policy" trafficPortSelector: ports: - "50051" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: "MATCH_ALL" metadataLabels: - labelName: app labelValue: helloworld
匯入
ep-mtls-psms.yaml
檔案,建立端點政策資源:gcloud beta network-services endpoint-policies import ep-mtls-psms \ --source=ep-mtls-psms.yaml --location=global
在用戶端設定 mTLS
用戶端安全性政策已附加至後端服務。當用戶端透過後端服務存取後端 (gRPC 伺服器) 時,系統會將附加的用戶端安全性政策傳送至用戶端。
在目前目錄中,使用名為
client-mtls-policy.yaml
的暫存檔案建立用戶端 TLS 政策資源內容:name: "client-mtls-policy" clientCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe serverValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffe
匯入暫時性檔案
client-mtls-policy.yaml
,建立名為client-mtls-policy
的用戶端 TLS 政策資源:gcloud network-security client-tls-policies import client-mtls-policy \ --source=client-mtls-policy.yaml --location=global
在暫存檔案中建立程式碼片段,以便參照這項政策,並在
SecuritySettings
訊息中新增subjectAltNames
的詳細資料,如以下範例所示。將${PROJECT_ID}
替換為您的專案 ID 值,也就是先前所述${PROJECT_ID}
環境變數的值。請注意,subjectAltNames
中的example-grpc-server
是 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
將
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
執行下列指令,確認專案編號設定正確無誤:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立以下規格:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: openjdk:8-jdk imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 800m memory: 512Mi requests: cpu: 100m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
C++
執行下列指令,確認專案編號設定正確無誤:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立以下規格:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Python
執行下列指令,確保已正確設定專案編號:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立以下規格:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: phusion/baseimage:18.04-1.0.0 imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
Go
執行下列指令,確保已正確設定專案編號:
if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
建立以下規格:
cat << EOF > example-grpc-client.yaml apiVersion: v1 kind: ServiceAccount metadata: name: example-grpc-client namespace: default annotations: iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: example-grpc-client namespace: default labels: k8s-app: example-grpc-client spec: replicas: 1 selector: matchLabels: k8s-app: example-grpc-client strategy: {} template: metadata: annotations: security.cloud.google.com/use-workload-certificates: "" labels: k8s-app: example-grpc-client spec: containers: - image: golang:1.16-alpine imagePullPolicy: IfNotPresent name: example-grpc-client command: - /bin/sleep - inf env: - name: GRPC_XDS_BOOTSTRAP value: "/tmp/grpc-xds/td-grpc-bootstrap.json" resources: limits: cpu: 8 memory: 8Gi requests: cpu: 300m memory: 512Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/grpc-xds/ initContainers: - name: grpc-td-init image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0 imagePullPolicy: Always args: - --output - "/tmp/bootstrap/td-grpc-bootstrap.json" resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 100Mi volumeMounts: - name: grpc-td-conf mountPath: /tmp/bootstrap/ serviceAccountName: example-grpc-client volumes: - name: grpc-td-conf emptyDir: medium: Memory EOF
請按照下列步驟完成程序。
套用規格:
kubectl apply -f example-grpc-client.yaml
將必要角色授予服務帳戶:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \ ${PROJNUM}-compute@developer.gserviceaccount.com gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \ --role roles/trafficdirector.client
確認用戶端 Pod 是否正在執行:
kubectl get pods
指令會傳回類似以下的文字:
NAMESPACE NAME READY STATUS RESTARTS AGE default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 104s [..skip..]
執行伺服器
在先前建立的伺服器 Pod 中,建構並執行支援 xDS 的 helloworld
伺服器。
Java
取得為
example-grpc-server
服務建立的 Pod 名稱:kubectl get pods | grep example-grpc-server
您會看到類似以下的意見回饋:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
開啟一個通往伺服器 Pod 的殼層:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
在 Shell 中,確認
/tmp/grpc-xds/td-grpc-bootstrap.json
中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。下載 gRPC Java 1.42.1 版,並建構
xds-hello-world
伺服器應用程式。curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz cd grpc-java-1.42.1/examples/example-xds ../gradlew --no-daemon installDist
使用
--xds-creds
標記執行伺服器,以表示啟用 xDS 的安全性,並使用50051
做為監聽通訊埠,以及xds-server
做為伺服器識別名稱:./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
伺服器從 Cloud Service Mesh 取得必要設定後,您會看到以下輸出內容:
Listening on port 50051 plain text health service listening on port 50052
C++
取得為
example-grpc-server
服務建立的 Pod 名稱:kubectl get pods | grep example-grpc-server
您會看到類似以下的意見回饋:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
開啟一個通往伺服器 Pod 的殼層:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
在 Shell 中,確認
/tmp/grpc-xds/td-grpc-bootstrap.json
中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。下載 gRPC C++,並建構
xds-hello-world
伺服器應用程式。apt-get update -y && \ apt-get install -y \ build-essential \ clang \ python3 \ python3-dev curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz cd grpc-master tools/bazel build examples/cpp/helloworld:xds_greeter_server
使用
50051
做為監聽埠,並使用xds_greeter_server
做為伺服器識別名稱,執行伺服器:bazel-bin/examples/cpp/helloworld/xds_greeter_server --port=50051 --maintenance_port=50052 --secure
如要不使用憑證執行伺服器,您可以指定下列項目:
bazel-bin/examples/cpp/helloworld/xds_greeter_server --nosecure
伺服器從 Cloud Service Mesh 取得必要設定後,您會看到以下輸出內容:
Listening on port 50051 plain text health service listening on port 50052
Python
取得為
example-grpc-server
服務建立的 Pod 名稱:kubectl get pods | grep example-grpc-server
您會看到類似以下的意見回饋:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
開啟一個通往伺服器 Pod 的殼層:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
在 Shell 中,確認
/tmp/grpc-xds/td-grpc-bootstrap.json
中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。下載 gRPC Python 1.41.0 版,並建構範例應用程式。
apt-get update -y
apt-get install -y python3 python3-pip
curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz
cd grpc-1.41.x/examples/python/xds/
python3 -m virtualenv venv
source venv/bin/activate
python3 -m pip install -r requirements.txt
請使用
--xds-creds
標記執行伺服器,以便指示啟用 xDS 的安全性,並使用50051
做為接聽通訊埠。python3 server.py 50051 --xds-creds
伺服器從 Cloud Service Mesh 取得必要設定後,您會看到以下輸出內容:
2021-05-06 16:10:34,042: INFO Running with xDS Server credentials 2021-05-06 16:10:34,043: INFO Greeter server listening on port 50051 2021-05-06 16:10:34,046: INFO Maintenance server listening on port 50052
Go
取得為
example-grpc-server
服務建立的 Pod 名稱:kubectl get pods | grep example-grpc-server
您會看到類似以下的意見回饋:
default example-grpc-server-77548868d-l9hmf 1/1 Running 0 105s
開啟一個通往伺服器 Pod 的殼層:
kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
在 Shell 中,確認
/tmp/grpc-xds/td-grpc-bootstrap.json
中的啟動檔案是否符合「啟動檔案」一節所述的結構定義。下載 gRPC Go 1.41.0 版,然後前往包含
xds-hello-world
伺服器應用程式的目錄。apk add curl curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz cd grpc-go-1.42.0/examples/features/xds/server
使用
--xds_creds
標記建構及執行伺服器,以便指出啟用 xDS 的安全性,並使用50051
做為監聽通訊埠:GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -port 50051
伺服器從 Cloud Service Mesh 取得必要設定後,您會看到以下輸出內容:
Using xDS credentials... Serving GreeterService on 0.0.0.0:50051 and HealthService on 0.0.0.0:50052
健康檢查程序需要 3 到 5 分鐘,才能在伺服器啟動後顯示服務處於健康狀態。
執行用戶端並驗證設定
在先前建立的用戶端 Pod 中,建構及執行支援 xDS 的 helloworld
用戶端。
Java
取得用戶端 Pod 的名稱:
kubectl get pods | grep example-grpc-client
您會看到類似以下的意見回饋:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
開啟一個通往用戶端 Pod 的殼層:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
在指令碼 Shell 中,下載 gRPC Java 1.42.1 版,並建構
xds-hello-world
用戶端應用程式。curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz cd grpc-java-1.42.1/examples/example-xds ../gradlew --no-daemon installDist
使用
--xds-creds
標記執行用戶端,以表示啟用 xDS 的安全性、用戶端名稱和目標連結字串:./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke:8000
畫面會顯示類似以下的輸出:
Greeting: Hello xds-client, from xds-server
C++
取得用戶端 Pod 的名稱:
kubectl get pods | grep example-grpc-client
您會看到類似以下的意見回饋:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
開啟一個通往用戶端 Pod 的殼層:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
進入 Shell 後,請下載 gRPC C++ 並建構
xds-hello-world
用戶端應用程式。apt-get update -y && \ apt-get install -y \ build-essential \ clang \ python3 \ python3-dev
curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz
cd grpc-master
tools/bazel build examples/cpp/helloworld:xds_greeter_client
使用
--xds-creds
標記執行用戶端,以表示啟用 xDS 的安全性、用戶端名稱和目標連結字串:bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000
如要在不使用憑證的情況下執行用戶端,請使用下列指令:
bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000 --nosecure
畫面會顯示類似以下的輸出:
Greeter received: Hello world
Python
取得用戶端 Pod 的名稱:
kubectl get pods | grep example-grpc-client
您會看到類似以下的意見回饋:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
開啟一個通往用戶端 Pod 的殼層:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
進入殼層後,請下載 gRPC Python 1.41.0 版,並建構範例用戶端應用程式。
apt-get update -y apt-get install -y python3 python3-pip python3 -m pip install virtualenv curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz cd grpc-1.41.x/examples/python/xds/ python3 -m virtualenv venv source venv/bin/activate python3 -m pip install -r requirements.txt
使用
--xds-creds
標記執行用戶端,以表示啟用 xDS 的安全性、用戶端名稱和目標連結字串:python3 client.py xds:///helloworld-gke:8000 --xds-creds
畫面會顯示類似以下的輸出:
Greeter client received: Hello you from example-host!
Go
取得用戶端 Pod 的名稱:
kubectl get pods | grep example-grpc-client
您會看到類似以下的意見回饋:
default example-grpc-client-7c969bb997-9fzjv 1/1 Running 0 105s
開啟一個通往用戶端 Pod 的殼層:
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
進入殼層後,請下載 gRPC Go 1.42.0 版,然後前往包含
xds-hello-world
用戶端應用程式的目錄。apk add curl curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz cd grpc-go-1.42.0/examples/features/xds/client
使用
--xds_creds
標記建構及執行用戶端,以表示啟用 xDS 的安全性、用戶端名稱和目標連結字串:GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke:8000
畫面會顯示類似以下的輸出:
Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
使用授權政策設定服務層級存取權
授權政策支援功能需要 gRFC A41 支援。您可以在 github 上找到所需語言的版本。
請按照這些操作說明,設定服務層級存取權和授權政策。建立授權政策前,請先詳閱「使用授權功能限制存取權」中的警告。
為方便驗證設定,請建立額外的電腦名稱,讓用戶端用於參照 helloworld-gke
服務。
gcloud compute url-maps add-host-rule grpc-gke-url-map \ --path-matcher-name grpc-gke-path-matcher \ --hosts helloworld-gke-noaccess:8000
以下操作說明會建立授權政策,允許 example-grpc-client
帳戶傳送要求,其中主機名稱為 helloworld-gke:8000
,且連接埠為 50051
。
gcloud
建立名為
helloworld-gke-authz-policy.yaml
的檔案,以建立授權政策。action: ALLOW name: helloworld-gke-authz-policy rules: - sources: - principals: - spiffe://PROJECT_ID.svc.id.goog/ns/default/sa/example-grpc-client destinations: - hosts: - helloworld-gke:8000 ports: - 50051
匯入政策。
gcloud network-security authorization-policies import \ helloworld-gke-authz-policy \ --source=helloworld-gke-authz-policy.yaml \ --location=global
將下列內容附加至檔案
ep-mtls-psms.yaml
,藉此更新端點政策,以便參照新的授權政策。authorizationPolicy: projects/${PROJECT_ID}/locations/global/authorizationPolicies/helloworld-gke-authz-policy
端點政策現在會指定,對於 gRPC 啟動檔案包含
app:helloworld
標籤的 Pod 傳入要求,必須同時套用 mTLS 和授權政策。匯入政策:
gcloud network-services endpoint-policies import ep-mtls-psms \ --source=ep-mtls-psms.yaml --location=global
驗證授權政策
請按照這些操作說明,確認授權政策是否正常運作。
Java
開啟一個通往先前用過的用戶端 Pod 的殼層。
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
在指令介面中執行下列指令,驗證設定。
cd grpc-java-1.42.1/examples/example-xds ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke:8000
畫面會顯示類似以下的輸出:
Greeting: Hello xds-client, from xds-server
請再次使用其他伺服器名稱執行用戶端。請注意,這是失敗案例。由於授權政策只允許存取
helloworld-gke:8000
主機名稱,因此要求無效。./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \ xds:///helloworld-gke-noaccess:8000
畫面會顯示類似以下的輸出:
WARNING: RPC failed: Status{code=PERMISSION_DENIED}
如果沒有看到這項輸出內容,表示授權政策可能尚未開始使用。請稍候片刻,然後再次嘗試整個驗證程序。
Go
開啟一個通往先前用過的用戶端 Pod 的殼層。
kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
在指令介面中執行下列指令,驗證設定。
cd grpc-go-1.42.0/examples/features/xds/client GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke:8000
畫面會顯示類似以下的輸出:
Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
請再次使用其他伺服器名稱執行用戶端。請注意,這是失敗案例。由於授權政策只允許存取
helloworld-gke:8000
主機名稱,因此要求無效。GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY="info" \ go run main.go \ -xds_creds \ -name xds-client \ -target xds:///helloworld-gke-noaccess:8000
畫面會顯示類似以下的輸出:
could not greet: rpc error: code = PermissionDenied desc = Incoming RPC is not allowed: rpc error: code = PermissionDenied desc = incoming RPC did not match an allow policy exit status 1
如果沒有看到這項輸出內容,表示授權政策可能尚未開始使用。請稍候片刻,然後再次嘗試整個驗證程序。
使用 TLS 而非 mTLS
在本例中使用 TLS 只需要進行一些小變更。
在
ServerTlsPolicy
中放置mtlsPolicy
:cat << EOF > server-tls-policy.yaml name: "server-tls-policy" serverCertificate: certificateProviderInstance: pluginInstance: google_cloud_private_spiffe EOF
請改為在
EndpointPolicy
中使用這項政策:cat << EOF > ep-tls-psms.yaml name: "ep-mtls-psms" type: "GRPC_SERVER" serverTlsPolicy: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-tls-policy" trafficPortSelector: ports: - "50051" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: "MATCH_ALL" metadataLabels: [] EOF
mTLS 的
ClientTlsPolicy
也適用於 TLS 情況,但政策的clientCertificate
部分可以刪除,因為 TLS 不需要這個部分:cat << EOF > client-tls-policy.yaml name: "client-tls-policy" serverValidationCa: - certificateProviderInstance: pluginInstance: google_cloud_private_spiffe EOF
在錢包範例中使用服務安全性
本節將概略說明如何在 Java、C++ 和 Go 中,透過服務安全性啟用錢包範例。
Java
您可以在 github 上找到 Java 的範例原始碼。設定無 Proxy 安全性時,程式碼已使用 XdsChannel
和 XdsServer
憑證。
這些操作說明說明如何使用 Go 設定錢包範例。Java 的程序類似。這些操作說明會使用您從 Google Cloud 容器存放區取得的現有 Docker 映像檔。
如要建立範例,請按照下列操作說明進行:
- 複製存放區,並取得 gRPC 範例目錄中的檔案。
- 編輯
00-common-env.sh
檔案。將設定WALLET_DOCKER_IMAGE
值為 Go Docker 映像檔的現有行註解,並取消註解設定WALLET_DOCKER_IMAGE
值為 Java Docker 映像檔的行。 - 按照「建立及設定 Cloud Router 執行個體」一文中的指示,建立及設定 Cloud Router 執行個體,或是使用
10.apis.sh
指令碼中的create_cloud_router_instances
函式。 - 使用
hello world
範例的操作說明或指令碼20-cluster.sh
中的函式create_cluster
建立叢集。 - 使用CA 服務的操作說明或指令碼
30-private-ca-setup.sh
建立私人憑證授權單位。 - 使用指令碼
40-k8s-resources.sh
,為所有服務建立 Kubernetes 資源,包括服務帳戶、命名空間、Kubernetes 服務、NEG 和伺服器端部署:account
、stats
、stats_premium
、wallet_v1
、wallet_v2
。 - 針對您建立的每項服務,請在
50-td-components.sh
指令碼中使用create_health_check
和create_backend_service
建立健康狀態檢查和後端服務。 - 在指令碼
60-routing-components.sh
中使用create_routing_components
建立 Cloud Service Mesh 路由元件。 - 在
70-security-components.sh
指令碼中使用create_security_components
,為每項後端服務建立 Cloud Service Mesh 安全性元件。 - 在指令碼
75-client-deployment.sh
中使用create_client_deployment
建立 Wallet 用戶端部署作業。 - 如使用 grpc-wallet 用戶端驗證一文所述,啟動用戶端即可驗證設定。
C++
您可以在 github 上找到 C++ 的範例原始碼。設定無 Proxy 安全性時,程式碼已使用 XdsChannel
和 XdsServer
憑證。
這些操作說明說明如何使用 Go 設定錢包範例。C++ 的程序類似。這些操作說明會使用您從 Google Cloud 容器存放區取得的現有 Docker 映像檔。
如要建立範例,請按照下列操作說明進行:
- 複製存放區,並取得 gRPC 範例目錄中的檔案。
- 編輯
00-common-env.sh
檔案。將設定WALLET_DOCKER_IMAGE
值為 Go Docker 映像檔的現有行註解,並取消註解設定WALLET_DOCKER_IMAGE
值為 C++ Docker 映像檔的行。 - 按照「建立及設定 Cloud Router 執行個體」一文中的指示,建立及設定 Cloud Router 執行個體,或是使用
10.apis.sh
指令碼中的create_cloud_router_instances
函式。 - 使用
hello world
範例的操作說明或指令碼20-cluster.sh
中的函式create_cluster
建立叢集。 - 使用CA 服務的操作說明或指令碼
30-private-ca-setup.sh
建立私人憑證授權單位。 - 使用指令碼
40-k8s-resources.sh
,為所有服務建立 Kubernetes 資源,包括服務帳戶、命名空間、Kubernetes 服務、NEG 和伺服器端部署:account
、stats
、stats_premium
、wallet_v1
、wallet_v2
。 - 針對您建立的每項服務,請在
50-td-components.sh
指令碼中使用create_health_check
和create_backend_service
建立健康狀態檢查和後端服務。 - 在指令碼
60-routing-components.sh
中使用create_routing_components
建立 Cloud Service Mesh 路由元件。 - 在
70-security-components.sh
指令碼中使用create_security_components
,為每項後端服務建立 Cloud Service Mesh 安全性元件。 - 在指令碼
75-client-deployment.sh
中使用create_client_deployment
建立 Wallet 用戶端部署作業。 - 如使用 grpc-wallet 用戶端驗證一文所述,啟動用戶端即可驗證設定。
Go
您可以在 github 上找到 Go 的原始碼範例。設定無 Proxy 安全性時,程式碼已使用 XdsChannel
和 XdsServer
憑證。
操作說明會使用您從 Google Cloud 容器存放區取得的現有 Docker 映像檔。
如要建立範例,請按照下列操作說明進行:
- 複製存放區,並取得 gRPC 範例目錄中的檔案。
- 編輯
00-common-env.sh
檔案,為環境變數設定正確的值。 - 按照「建立及設定 Cloud Router 執行個體」一文中的指示,建立及設定 Cloud Router 執行個體,或是使用
10.apis.sh
指令碼中的create_cloud_router_instances
函式。 - 使用
hello world
範例的操作說明或指令碼20-cluster.sh
中的函式create_cluster
建立叢集。 - 使用CA 服務的操作說明或指令碼
30-private-ca-setup.sh
建立私人憑證授權單位。 - 使用指令碼
40-k8s-resources.sh
,為所有服務建立 Kubernetes 資源,包括服務帳戶、命名空間、Kubernetes 服務、NEG 和伺服器端部署:account
、stats
、stats_premium
、wallet_v1
、wallet_v2
。 - 針對您建立的每項服務,請在
50-td-components.sh
指令碼中使用create_health_check
和create_backend_service
建立健康狀態檢查和後端服務。 - 在指令碼
60-routing-components.sh
中使用create_routing_components
建立 Cloud Service Mesh 路由元件。 - 在
70-security-components.sh
指令碼中使用create_security_components
,為每項後端服務建立 Cloud Service Mesh 安全性元件。 - 在指令碼
75-client-deployment.sh
中使用create_client_deployment
建立 Wallet 用戶端部署作業。 - 如使用 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 結構體都有兩個欄位:
|
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 服務網格設定安全性後,工作負載無法進行通訊,請按照下列操作說明找出原因。
- 停用無 Proxy 安全性,並解決無 Proxy 服務網狀負載平衡用例中的問題。如要停用網格的安全性功能,請執行下列任一操作:
- 在用戶端和伺服器端使用純文字憑證,或
- 請勿在 Cloud Service Mesh 設定中為後端服務和端點政策設定安全性。
因為部署中沒有安全性設定,請按照排解無 Proxy 的 Cloud Service Mesh 部署問題中的步驟操作。
修改工作負載,以便使用含有平文或不安全憑證的 xDS 憑證做為備用憑證。如先前所述,請保留 Cloud Service Mesh 設定,並停用安全性功能。在這種情況下,雖然 gRPC 允許 Cloud Service Mesh 設定安全性,但 Cloud Service Mesh 不會傳送安全性資訊,因此 gRPC 應改用純文字 (或不安全) 憑證,這應與先前所述的第一種情況類似。如果這個做法無法解決問題,請執行下列操作:
- 請在用戶端和伺服器端提高記錄層級,以便查看 gRPC 和 Cloud Service Mesh 之間交換的 xDS 訊息。
- 請確認 Cloud Service Mesh 在傳送至工作負載的 CDS 和 LDS 回應中未啟用安全性。
- 請確認工作負載不會在管道中使用 TLS 或 mTLS 模式。如果您看到任何與 TLS 握手相關的記錄訊息,請檢查應用程式原始碼,並確認您使用不安全或純文字做為備用憑證。如果應用程式原始碼正確,這可能是 gRPC 程式庫中的錯誤
請按照使用者指南中的疑難排解步驟,確認 CA 服務與 GKE 的整合功能是否正常運作。請確認該功能提供的憑證和金鑰是否已在指定目錄
/var/run/secrets/workload-spiffe-credentials/
中提供。如先前所述,在網格中啟用 TLS (而非 mTLS),然後重新啟動用戶端和伺服器工作負載。
- 請提高用戶端和伺服器端的記錄層級,以便查看 gRPC 和 Cloud Service Mesh 之間交換的 xDS 訊息。
- 請確認 Cloud Service Mesh 已在傳送至工作負載的 CDS 和 LDS 回應中啟用安全性功能。
用戶端失敗,並傳回 CertificateException
和訊息 Peer certificate SAN check failed
這表示 SecuritySettings
訊息中的 subjectAltNames
值有問題。請注意,這些值取決於您為後端服務建立的 Kubernetes 服務。每個建立的 Kubernetes 服務都會有一個相關聯的 SPIFFE ID,格式如下:
spiffe://${WORKLOAD_POOL}/ns/${K8S_NAMESPACE}/sa/${SERVICE_ACCOUNT}
這些值如下:
WORKLOAD_POOL
:叢集的工作負載集區,即${PROJECT_ID}.svc.id.goog
K8S_NAMESPACE
:您在服務部署作業中使用的 Kubernetes 命名空間SERVICE_ACCOUNT
:您在服務部署作業中使用的 Kubernetes 服務帳戶
針對您以網路端點群組形式附加至後端服務的每項 Kubernetes 服務,請確認您已正確計算 SPIFFE ID,並將該 SPIFFE ID 新增至 SecuritySettings
訊息中的 subjectAltNames
欄位。
應用程式無法使用 mTLS 憑證搭配 gRPC 程式庫
如果應用程式無法使用 mTLS 憑證與 gRPC 程式庫,請執行下列操作:
確認 Pod 規格包含 使用 NEG 建立無 Proxy gRPC 服務一文所述的
security.cloud.google.com/use-workload-certificates
註解。請確認包含憑證鏈結的檔案,以及葉憑證、私密金鑰和信任的 CA 憑證,可透過 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"
如果無法取得上一個步驟中的憑證,請執行下列操作:
gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME
--location=LOCATION確認 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.
確認憑證未過期。這是
/var/run/secrets/workload-spiffe-credentials/certificates.pem
中的憑證鏈和分葉憑證。如要檢查,請執行下列指令:cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
請執行以下指令,確認應用程式支援的金鑰類型:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
請確認 gRPC Java 應用程式在
WorkloadCertificateConfig
YAML 檔案中具有下列keyAlgorithm
:
keyAlgorithm: rsa: modulusSize: 4096
確認 CA 使用與憑證金鑰相同的金鑰系列。
應用程式憑證遭到用戶端、伺服器或對等端拒絕
- 確認對等應用程式使用相同信任套件來驗證憑證。
- 確認使用的憑證未過期 (憑證鏈結和分葉憑證:"/var/run/secrets/workload-spiffe-credentials/certificates.pem")。
Pod 仍處於待處理狀態
如果 Pod 在設定程序期間維持在待處理狀態,請在部署規格中增加 Pod 的 CPU 和記憶體資源。
無法使用 --enable-mesh-certificates
標記建立叢集
請確認您執行的是最新版的 gcloud 指令列:
gcloud components update
請注意,--enable-mesh-certificates
標記僅適用於 gcloud beta
。
Pod 無法啟動
如果憑證佈建失敗,使用 GKE 網格憑證的 Pod 可能無法啟動。這可能發生在以下情況:
WorkloadCertificateConfig
或TrustConfig
設定錯誤或遺漏。- 客戶服務回應未獲核准。
您可以檢查 Pod 事件,確認憑證佈建是否失敗。
檢查 Pod 的狀態:
kubectl get pod -n POD_NAMESPACE POD_NAME
更改下列內容:
POD_NAMESPACE
:Pod 的命名空間。POD_NAME
:Pod 名稱。
查看 Pod 的近期事件:
kubectl describe pod -n POD_NAMESPACE POD_NAME
如果憑證佈建失敗,您會看到含有
Type=Warning
、Reason=FailedMount
、From=kubelet
的事件,以及以MountVolume.SetUp failed for volume "gke-workload-certificates"
開頭的Message
欄位。Message
欄位包含疑難排解資訊。Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedMount 13s (x7 over 46s) kubelet MountVolume.SetUp failed for volume "gke-workload-certificates" : rpc error: code = Internal desc = unable to mount volume: store.CreateVolume, err: unable to create volume "csi-4d540ed59ef937fbb41a9bf5380a5a534edb3eedf037fe64be36bab0abf45c9c": caPEM is nil (check active WorkloadCertificateConfig)
如果 Pod 無法啟動的原因是物件設定錯誤,或 CSR 遭到拒絕,請參閱以下疑難排解步驟。
WorkloadCertificateConfig
或 TrustConfig
設定有誤
請確認您已正確建立 WorkloadCertificateConfig
和 TrustConfig
物件。您可以使用 kubectl
診斷這兩種物件中的任何一個物件設定錯誤。
擷取目前狀態。
針對
WorkloadCertificateConfig
:kubectl get WorkloadCertificateConfig default -o yaml
針對
TrustConfig
:kubectl get TrustConfig default -o yaml
檢查狀態輸出內容。有效物件會包含含有
type: Ready
和status: "True"
的條件。status: conditions: - lastTransitionTime: "2021-03-04T22:24:11Z" message: WorkloadCertificateConfig is ready observedGeneration: 1 reason: ConfigReady status: "True" type: Ready
如果是無效物件,則會顯示
status: "False"
。reason
和message
欄位則包含其他疑難排解詳細資料。
CSR 未獲核准
如果 CSR 核准程序發生錯誤,您可以查看 CSR 的 type: Approved
和 type: Issued
條件中的錯誤詳細資料。
使用
kubectl
列出相關的 CSR:kubectl get csr \ --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'
選擇 CSR,該 CSR 必須為
Approved
且不是Issued
,或不是Approved
。使用 kubectl 取得所選 CSR 的詳細資料:
kubectl get csr CSR_NAME -o yaml
將
CSR_NAME
替換為您選擇的 CSR 名稱。
有效的 CSR 會包含 type: Approved
和 status: "True"
的條件,並在 status.certificate
欄位中提供有效的憑證:
status:
certificate: <base64-encoded data>
conditions:
- lastTransitionTime: "2021-03-04T21:58:46Z"
lastUpdateTime: "2021-03-04T21:58:46Z"
message: Approved CSR because it is a valid SPIFFE SVID for the correct identity.
reason: AutoApproved
status: "True"
type: Approved
message
和 reason
欄位會顯示無效 CSR 的疑難排解資訊。
Pod 缺少憑證
取得 Pod 的 Pod 規格:
kubectl get pod -n POD_NAMESPACE POD_NAME -o yaml
更改下列內容:
POD_NAMESPACE
:Pod 的命名空間。POD_NAME
:Pod 名稱。
請確認 Pod 規格包含「設定 Pod 以接收 mTLS 憑證」一文中所述的
security.cloud.google.com/use-workload-certificates
註解。確認 GKE 網格憑證的存取控制器是否已成功將
workloadcertificates.security.cloud.google.com
類型的 CSI 驅動程式磁碟區注入 Pod 規格:volumes: ... -csi: driver: workloadcertificates.security.cloud.google.com name: gke-workload-certificates ...
檢查每個容器中是否有磁碟區掛接:
containers: - name: ... ... volumeMounts: - mountPath: /var/run/secrets/workload-spiffe-credentials name: gke-workload-certificates readOnly: true ...
請確認下列憑證套件和私密金鑰是否可在 Pod 的以下位置使用:
- 憑證鏈結套件:
/var/run/secrets/workload-spiffe-credentials/certificates.pem
- 私密金鑰:
/var/run/secrets/workload-spiffe-credentials/private_key.pem
- CA 信任錨點套件:
/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem
- 憑證鏈結套件:
如果檔案無法使用,請執行下列步驟:
擷取叢集的 CA 服務 (預先發布版) 例項:
kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'
擷取 CA 服務 (預先發布版) 執行個體的狀態:
gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \ --location ISSUING_CA_LOCATION
更改下列內容:
ISSUING_CA_TYPE
:核發憑證授權單位類型,必須是subordinates
或roots
。ISSUING_CA_NAME
:核發 CA 的名稱。ISSUING_CA_LOCATION
:核發 CA 的區域。
取得根 CA 的 IAM 政策:
gcloud privateca roots get-iam-policy ROOT_CA_NAME
將
ROOT_CA_NAME
替換為根 CA 的名稱。在 IAM 政策中,確認
privateca.auditor
政策繫結是否存在:... - members: - serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.auditor ...
在本例中,
PROJECT_NUMBER
是叢集的專案編號。取得子 CA 的 IAM 政策:
gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAME
將
SUBORDINATE_CA_NAME
替換為子 CA 名稱。在 IAM 政策中,確認是否有
privateca.certificateManager
政策繫結:... - members: - serviceAccount: service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com role: roles/privateca.certificateManager ...
在本例中,
PROJECT_NUMBER
是叢集的專案編號。
應用程式無法使用核發的 mTLS 憑證
確認憑證未過期:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
確認應用程式支援您使用的金鑰類型。
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
確認核發 CA 是否使用與憑證金鑰相同的金鑰系列。
取得 CA 服務 (預先發布版) 執行個體的狀態:
gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \ --location ISSUING_CA_LOCATION
更改下列內容:
ISSUING_CA_TYPE
:核發憑證授權單位類型,必須是subordinates
或roots
。ISSUING_CA_NAME
:核發 CA 的名稱。ISSUING_CA_LOCATION
:核發 CA 的區域。
檢查輸出內容中的
keySpec.algorithm
是否與您在WorkloadCertificateConfig
YAML 資訊清單中定義的鍵演算法相同。輸出如下所示:config: ... subjectConfig: commonName: td-sub-ca subject: organization: TestOrgLLC subjectAltName: {} createTime: '2021-05-04T05:37:58.329293525Z' issuingOptions: includeCaCertUrl: true keySpec: algorithm: RSA_PKCS1_2048_SHA256 ...
憑證遭拒
- 確認對等應用程式使用相同信任套件來驗證憑證。
確認憑證未過期:
cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
請確認用戶端程式碼是否會定期從檔案系統重新整理憑證,如果未使用 gRPC Go 憑證重新載入 API。
請確認工作負載與 CA 位於相同的信任網域。GKE 網格憑證可支援單一信任網域中工作負載之間的通訊。
限制
只有 GKE 支援 Cloud Service Mesh 服務安全性。您無法使用 Compute Engine 部署服務安全性。
Cloud Service Mesh 不支援以下情況:有兩個以上的端點政策資源與端點相符,例如兩個具有相同標籤和連接埠的政策,或是兩個以上具有不同標籤的政策,且這些政策與端點的標籤相符。如要進一步瞭解如何將端點政策與端點的標籤進行比對,請參閱 EndpointPolicy.EndpointMatcher.MetadataLabelMatcher 的 API。在這種情況下,Cloud Service Mesh 不會根據任何衝突的政策產生安全性設定。