本教學課程說明如何使用 Cloud Service Mesh 輸出閘道和其他 Google Cloud 控制項,保護從 Google Kubernetes Engine 叢集部署的工作負載傳出的流量 (輸出)。本教學課程是在 GKE 叢集中使用 Cloud Service Mesh 輸出閘道的最佳做法的輔助教材。
本教學課程的目標對象包括網路、平台和安全工程師,他們負責管理一或多個軟體交付團隊使用的 Google Kubernetes Engine 叢集。本文所述的控制項特別適合必須證明符合法規 (例如 GDPR 和 PCI) 的機構。
目標
- 設定執行 Cloud Service Mesh 的基礎架構:
- 自訂 VPC 網路和私有子網路
- 透過 Cloud NAT 存取網際網路
- 私人 GKE 叢集,並為輸出閘道 Pod 額外建立節點集區
- 限制性輸出 VPC 防火牆規則;只有閘道節點可以連線至外部主機
- 私人 Google 存取權,用於連線至 Container Registry 和 Google API
- 安裝 Cloud Service Mesh。
- 安裝在專屬節點集區上執行的輸出閘道 Proxy。
- 透過輸出閘道設定外部流量的多租戶轉送規則:
- 命名空間
team-x
中的應用程式可以連線至example.com
- 命名空間
team-y
中的應用程式可以連線至httpbin.org
- 命名空間
- 使用
Sidecar
資源,限制每個命名空間的 Sidecar Proxy 輸出設定範圍。 - 設定授權政策,強制執行輸出規則。
- 將輸出閘道設為將純文字 HTTP 要求升級為 TLS (TLS 來源)。
- 設定輸出閘道,以傳遞 TLS 流量。
- 設定 Kubernetes 網路政策,做為額外的輸出控制項。
- 使用 Private Google Access 和 Identity and Access Management (IAM) 權限,設定 Google API 的直接存取權。
費用
在本文件中,您會使用 Google Cloud的下列計費元件:
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
如要根據預測用量估算費用,請使用 Pricing Calculator。
完成本教學課程後,您可以刪除已建立的資源,避免持續產生費用。詳情請參閱「清除所用資源」一節。
事前準備
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
建立工作目錄,以便在逐步完成本教學課程時使用:
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
建立殼層指令碼,初始化本教學課程的環境。 根據專案和偏好設定替換及編輯變數。 如果 Shell 工作階段過期,請使用
source
指令執行這個指令碼,重新初始化環境:cat << 'EOF' > ./init-egress-tutorial.sh #! /usr/bin/env bash PROJECT_ID=YOUR_PROJECT_ID REGION=REGION ZONE=ZONE gcloud config set project ${PROJECT_ID} gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE} EOF
啟用
compute.googleapis.com
:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
將指令碼設為可執行狀態,然後使用
source
指令執行,初始化環境。如果系統提示啟用Y
,請選取該圖示compute.googleapis.com
:chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
設定基礎架構
建立虛擬私有雲網路和子網路
建立新的虛擬私有雲網路:
gcloud compute networks create vpc-network \ --subnet-mode custom
建立叢集要執行的子網路,並預先指派 Pod 和服務的次要 IP 位址範圍。啟用 Private Google Access,讓只有內部 IP 位址的應用程式可以連上 Google API 和服務:
gcloud compute networks subnets create subnet-gke \ --network vpc-network \ --range 10.0.0.0/24 \ --secondary-range pods=10.1.0.0/16,services=10.2.0.0/20 \ --enable-private-ip-google-access
設定 Cloud NAT
沒有外部 IP 位址的工作負載可以透過 Cloud NAT 連線至網際網路上的目的地,並接收來自這些目的地的傳入回應。
建立 Cloud Router:
gcloud compute routers create nat-router \ --network vpc-network
在路由器中新增 NAT 設定:
gcloud compute routers nats create nat-config \ --router nat-router \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
為每個 GKE 節點集區建立服務帳戶
建立兩個服務帳戶,供兩個 GKE 節點集區使用。每個節點集區都會指派個別的服務帳戶,方便您將虛擬私有雲防火牆規則套用至特定節點。
建立服務帳戶,供預設節點集區中的節點使用:
gcloud iam service-accounts create sa-application-nodes \ --description="SA for application nodes" \ --display-name="sa-application-nodes"
為閘道節點集區中的節點建立服務帳戶:
gcloud iam service-accounts create sa-gateway-nodes \ --description="SA for gateway nodes" \ --display-name="sa-gateway-nodes"
將權限授予服務帳戶
為應用程式和閘道服務帳戶新增最少量的 IAM 角色。如要記錄、監控及從 Container Registry 提取私人容器映像檔,必須具備這些角色。
project_roles=(
roles/logging.logWriter
roles/monitoring.metricWriter
roles/monitoring.viewer
roles/storage.objectViewer
)
for role in "${project_roles[@]}"
do
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
done
建立防火牆規則
在下列步驟中,您會將防火牆規則套用至虛擬私有雲網路,以便根據預設拒絕所有輸出流量。叢集必須具備特定連線能力才能運作,閘道節點也必須能夠連線至虛擬私有雲外部的目的地。一組最低限度的特定防火牆規則會覆寫預設的「全部拒絕」規則,以允許必要的連線。
建立預設 (低優先權) 防火牆規則,拒絕從虛擬私有雲網路輸出的所有流量:
gcloud compute firewall-rules create global-deny-egress-all \ --action DENY \ --direction EGRESS \ --rules all \ --destination-ranges 0.0.0.0/0 \ --network vpc-network \ --priority 65535 \ --description "Default rule to deny all egress from the network."
建立規則,只允許具有閘道服務帳戶的節點存取網際網路:
gcloud compute firewall-rules create gateway-allow-egress-web \ --action ALLOW \ --direction EGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --network vpc-network \ --priority 1000 \ --description "Allow the nodes running the egress gateways to connect to the web"
允許節點連線至 Kubernetes 控制層:
gcloud compute firewall-rules create allow-egress-to-api-server \ --action ALLOW \ --direction EGRESS \ --rules tcp:443,tcp:10250 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
選用:如果您使用 Managed Cloud Service Mesh,則不需要這項防火牆規則。
Cloud Service Mesh 會在將 Sidecar Proxy 注入工作負載時使用 Webhook。允許 GKE API 伺服器呼叫節點上執行的服務網格控制層公開的 Webhook:
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow the API server to call the webhooks exposed by istiod discovery"
允許在叢集上執行的節點和 Pod 之間建立輸出連線。GKE 會自動建立對應的 Ingress 規則。服務連線不需要任何規則,因為 iptables 路由鏈一律會將服務 IP 位址轉換為 Pod IP 位址。
gcloud compute firewall-rules create allow-egress-nodes-and-pods \ --action ALLOW \ --direction EGRESS \ --rules all \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.0.0.0/24,10.1.0.0/16 \ --network vpc-network \ --priority 1000 \ --description "Allow egress to other Nodes and Pods"
允許存取 Private Google Access 用於提供 Google API、Container Registry 和其他服務的保留 IP 位址集:
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 199.36.153.8/30 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the VIPs used by Google Cloud APIs (Private Google Access)"
允許 Google Cloud 健康狀態檢查服務存取叢集中執行的 Pod。詳情請參閱健康狀態檢查。
gcloud compute firewall-rules create allow-ingress-gcp-health-checker \ --action ALLOW \ --direction INGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 35.191.0.0/16,130.211.0.0/22,209.85.152.0/22,209.85.204.0/22 \ --network vpc-network \ --priority 1000 \ --description "Allow workloads to respond to Google Cloud health checks"
設定 API 的私人存取權 Google Cloud
啟用私人 Google 存取權後,只有內部 IP 位址的 VM 和 Pod 就能存取 Google API 和服務。雖然 Google API 和服務是透過外部 IP 提供服務,但使用私人 Google 存取權時,節點的流量絕不會離開 Google 網路。
啟用 Cloud DNS API:
gcloud services enable dns.googleapis.com
建立私人 DNS 區域、CNAME
和 A
記錄,讓節點和工作負載可以使用私人 Google 存取權和 private.googleapis.com
主機名稱連線至 Google API 和服務:
gcloud dns managed-zones create private-google-apis \
--description "Private DNS zone for Google APIs" \
--dns-name googleapis.com \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-google-apis
gcloud dns record-sets transaction add private.googleapis.com. \
--name "*.googleapis.com" \
--ttl 300 \
--type CNAME \
--zone private-google-apis
gcloud dns record-sets transaction add "199.36.153.8" \
"199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name private.googleapis.com \
--ttl 300 \
--type A \
--zone private-google-apis
gcloud dns record-sets transaction execute --zone private-google-apis
設定 Container Registry 的私人存取權
建立私人 DNS 區域、CNAME
和 A
記錄,讓節點可以使用私人 Google 存取權和 gcr.io
主機名稱連線至 Container Registry:
gcloud dns managed-zones create private-gcr-io \
--description "private zone for Container Registry" \
--dns-name gcr.io \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-gcr-io
gcloud dns record-sets transaction add gcr.io. \
--name "*.gcr.io" \
--ttl 300 \
--type CNAME \
--zone private-gcr-io
gcloud dns record-sets transaction add "199.36.153.8" "199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name gcr.io \
--ttl 300 \
--type A \
--zone private-gcr-io
gcloud dns record-sets transaction execute --zone private-gcr-io
建立私人 GKE 叢集
找出 Cloud Shell 的外部 IP 位址,以便新增至允許存取叢集 API 伺服器的網路清單:
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
如果 Cloud Shell VM 閒置一段時間,外部 IP 位址可能會變更。如果發生這種情況,您必須更新叢集的授權網路清單。在初始化指令碼中新增下列指令:
cat << 'EOF' >> ./init-egress-tutorial.sh SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com) gcloud container clusters update cluster1 \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 EOF
啟用 Google Kubernetes Engine API:
gcloud services enable container.googleapis.com
建立私人 GKE 叢集:
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-dataplane-v2 \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --network "vpc-network" \ --subnetwork "subnet-gke" \ --cluster-secondary-range-name "pods" \ --services-secondary-range-name "services" \ --workload-pool "${PROJECT_ID}.svc.id.goog" \ --zone ${ZONE}
叢集建立作業會在幾分鐘內完成。叢集具有內部 IP 位址的私有節點。系統會從您建立 VPC 子網路時定義的具名次要範圍,為 Pod 和服務指派 IP。
使用叢內控制層的 Cloud Service Mesh 必須使用至少有 4 個 vCPU 的機器類型。
Google 建議叢集訂閱「一般」發布管道,確保節點執行的 Kubernetes 版本支援 Cloud Service Mesh。
如要進一步瞭解使用叢內控制層執行 Cloud Service Mesh 的必要條件,請參閱叢內必要條件。
如要進一步瞭解執行代管 Cloud Service Mesh 的規定和限制,請參閱代管 Cloud Service Mesh 支援的功能。
叢集已啟用 Workload Identity Federation for GKE。Cloud Service Mesh 需要 Workload Identity Federation for GKE,建議您使用這項功能,從 GKE 工作負載存取 Google API。
建立名為「gateway」的節點集區。這個節點集區是部署輸出閘道的位置。
dedicated=gateway:NoSchedule
taint 會新增至閘道節點集區中的每個節點。gcloud container node-pools create "gateway" \ --cluster "cluster1" \ --machine-type "e2-standard-4" \ --node-taints dedicated=gateway:NoSchedule \ --service-account "sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --num-nodes "1"
Kubernetes taint 和容許條件可確保只有輸出閘道 Pod 會在閘道節點集區的節點上執行。
下載憑證,以便使用 kubectl 連線至叢集:
gcloud container clusters get-credentials cluster1
確認閘道節點是否具有正確的汙點:
kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \ -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
輸出結果會與下列內容相似:
name taints gke-cluster1-gateway-9d65b410-cffs map[effect:NoSchedule key:dedicated value:gateway]
安裝及設定 Cloud Service Mesh
請按照其中一個 Cloud Service Mesh 安裝指南操作:
安裝 Cloud Service Mesh 後,請停止並返回本教學課程,不要安裝輸入或輸出閘道。
安裝輸出閘道
為輸出閘道建立 Kubernetes 命名空間:
kubectl create namespace istio-egress
部署輸出閘道時,系統會根據您套用至部署或命名空間的標籤,自動注入設定。如果已設定預設標籤,請使用預設插入標籤標記命名空間,否則請使用已安裝控制平面的修訂版本標籤。您新增的修訂版本標籤也取決於您是否部署代管 Cloud Service Mesh,或安裝叢內控制層。
請根據安裝類型 (代管或叢集內),選取下方的分頁標籤。
受管理
使用下列指令找出可用的控制平面修訂版本:
kubectl -n istio-system get controlplanerevision
輸出結果會與下列內容相似:
NAME RECONCILED STALLED AGE asm-managed True False 112m
請記下要使用的控制平面修訂版本在
NAME
欄中的值。一般來說,Cloud Service Mesh 發布管道會對應至 Google Kubernetes Engine 叢集的發布管道。叢集內
如果是叢內控制層,
istiod
服務和部署作業通常會有類似istio.io/rev=
的修訂版本標籤,其中會識別 Cloud Service Mesh 版本。修訂版本會成為
istiod
服務名稱的一部分,例如:istiod-.istio-system
使用下列指令,在
istiod
上找出叢內控制層的修訂版本標籤:kubectl get deploy -n istio-system -l app=istiod \ -o=jsonpath='{.items[*].metadata.labels.istio\.io\/rev}''{"\n"}'
選用:為命名空間加上標籤,系統就會自動插入閘道設定。只要標記命名空間或部署作業即可。為配合本教學課程,請為兩者加上標籤,避免
istioctl analyze
工具發出警告。kubectl label namespace istio-egress istio.io/rev=REVISION
為輸出閘道建立運算子資訊清單:
cat << EOF > egressgateway-operator.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: egressgateway-operator annotations: config.kubernetes.io/local-config: "true" spec: profile: empty revision: REVISION components: egressGateways: - name: istio-egressgateway namespace: istio-egress enabled: true values: gateways: istio-egressgateway: injectionTemplate: gateway tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
下載
istioctl
工具。即使您使用 Cloud Service Mesh 1.15 以下版本,也必須使用 1.16.2-asm.2 以上版本。請參閱「下載正確的 istioctl 版本」。解壓縮下載的封存檔案後,請設定環境變數來保留
istioctl
工具的路徑,並將其新增至初始化指令碼:ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
使用運算子資訊清單和
istioctl
,建立輸出閘道安裝資訊清單:${ISTIOCTL} manifest generate \ --filename egressgateway-operator.yaml \ --output egressgateway \ --cluster-specific
安裝輸出閘道:
kubectl apply --recursive --filename egressgateway/
確認輸出閘道是否在
gateway
節點集區的節點上執行:kubectl get pods -n istio-egress -o wide
輸出閘道 Pod 具有節點的
affinity
(位於gateway
節點集區中),以及容許條件,可讓 Pod 在受汙染的閘道節點上執行。檢查輸出閘道 Pod 的節點親和性和容許條件:kubectl -n istio-egress get pod -l istio=egressgateway \ -o=custom-columns='name:metadata.name,node-affinity:spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,tolerations:spec.tolerations[?(@.key=="dedicated")]'
輸出結果會與下列內容相似:
name node-affinity tolerations istio-egressgateway-754d9684d5-jjkdz [map[matchExpressions:[map[key:cloud.google.com/gke-nodepool operator:In values:[gateway]]]]] map[key:dedicated operator:Equal value:gateway]
啟用 Envoy 存取記錄功能
啟用 Envoy 存取記錄所需的步驟,取決於 Cloud Service Mesh 類型 (代管或叢集內):
受管理
叢集內
準備網格和測試應用程式
請確認已啟用「STRICT」雙向傳輸層安全標準 (TLS)。在
istio-system
命名空間中,為網格套用預設PeerAuthentication
政策:cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOF
您可以在特定命名空間中建立
PeerAuthentication
資源,藉此覆寫這項設定。建立用於部署測試工作負載的命名空間。本教學課程稍後的步驟會說明如何為每個命名空間設定不同的輸出路徑規則。
kubectl create namespace team-x kubectl create namespace team-y
為命名空間加上標籤,以便 Kubernetes 網路政策選取:
kubectl label namespace team-x team=x kubectl label namespace team-y team=y
如要讓 Cloud Service Mesh 自動注入 Proxy 輔助資訊,請在工作負載命名空間中設定控制層修訂版本標籤:
kubectl label ns team-x istio.io/rev=REVISION kubectl label ns team-y istio.io/rev=REVISION
建立用於進行測試部署作業的 YAML 檔案:
cat << 'EOF' > ./test.yaml apiVersion: v1 kind: ServiceAccount metadata: name: test --- apiVersion: v1 kind: Service metadata: name: test labels: app: test spec: ports: - port: 80 name: http selector: app: test --- apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 selector: matchLabels: app: test template: metadata: labels: app: test spec: serviceAccountName: test containers: - name: test image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim command: ["/bin/sleep", "infinity"] imagePullPolicy: IfNotPresent EOF
將測試應用程式部署至
team-x
命名空間:kubectl -n team-x create -f ./test.yaml
確認測試應用程式已部署至預設集區中的節點,且已注入 Proxy Sidecar 容器。重複執行下列指令,直到 Pod 狀態為
Running
:kubectl -n team-x get po -l app=test -o wide
輸出結果會與下列內容相似:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-d5bdf6f4f-9nxfv 2/2 Running 0 19h 10.1.1.25 gke-cluster1-default-pool-f6c7a51f-wbzj
2 個容器中有 2 個是
Running
。一個是測試應用程式,另一個是 Proxy Sidecar。Pod 在預設節點集區的節點上執行。
確認無法從測試容器對外部網站發出 HTTP 要求:
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test -- curl -v http://example.com
由於
global-deny-egress-all
防火牆規則拒絕上游連線,因此產生來自 Sidecar Proxy 的錯誤訊息。
使用 Sidecar 資源限制補充 Proxy 設定的範圍
您可以透過 Sidecar 資源,限制為 Sidecar Proxy 設定的輸出監聽器範圍。為減少設定膨脹和記憶體用量,建議為每個命名空間套用預設 Sidecar
資源。
Cloud Service Mesh 在 Sidecar 中執行的 Proxy 是 Envoy。在 Envoy 術語中,cluster
是上游端點的邏輯相似群組,用做負載平衡的目的地。
執行
istioctl proxy-config
指令,檢查為測試 Pod 設定的 Envoy Sidecar Proxy 中的外送叢集:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
清單中約有 11 個 Envoy 叢集,包括一些用於輸出閘道的叢集。
將 Proxy 設定限制為已在輸出和
team-x
命名空間中,透過服務項目明確定義的輸出路徑。將Sidecar
資源套用至team-x
命名空間:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-x spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-x/*' EOF
將輸出流量政策模式設為
REGISTRY_ONLY
,可限制 Proxy 設定,只納入已定義服務項目並明確新增至網格服務登錄的外部主機。設定
egress.hosts
會指定 Sidecar Proxy 僅從使用exportTo
屬性提供的輸出命名空間中選取路徑。「team-x/*
」部分包含team-x
命名空間中本機設定的所有路徑。查看 Envoy 補充 Proxy 中設定的出站叢集,並與套用
Sidecar
資源前設定的叢集清單進行比較:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
您會看到輸出閘道的叢集,以及測試 Pod 本身的叢集。
設定 Cloud Service Mesh,透過輸出閘道轉送流量
在通訊埠 80 上為 HTTP 流量設定
Gateway
。Gateway
會選取您部署至輸出命名空間的輸出閘道 Proxy。Gateway
設定會套用至輸出命名空間,並處理任何主機的流量。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL EOF
建立
DestinationRule
,並使用雙向 TLS 進行驗證和加密,為所有外部主機使用單一共用目的地規則。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: tls: mode: ISTIO_MUTUAL EOF
在輸出命名空間中建立
ServiceEntry
,在網格的服務登錄中,為team-x
命名空間明確登錄 example.com:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: example-com-ext namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: example.com spec: hosts: - example.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'team-x' - 'istio-egress' EOF
建立
VirtualService
,透過輸出閘道將流量轉送至 example.com。有兩個比對條件:第一個條件會將流量導向輸出閘道,第二個條件則會將流量從輸出閘道導向目的地主機。exportTo
屬性可控管哪些命名空間可以使用虛擬服務。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
執行
istioctl analyze
檢查設定錯誤:${ISTIOCTL} analyze -n istio-egress --revision REVISION
輸出結果會與下列內容相似:
✔ No validation issues found when analyzing namespace: istio-egress.
透過輸出閘道傳送多個要求至外部網站:
for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- \ curl -s -o /dev/null -w "%{http_code}\n" http://example.com done
您會看到所有四個回應的
200
狀態碼。檢查 Proxy 存取記錄,確認要求是否透過輸出閘道導向。首先,請檢查隨測試應用程式部署的 Proxy Sidecar 存取記錄:
kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) istio-proxy
您傳送的每項要求都會顯示類似下列內容的記錄項目:
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/1.1" 200 - "-" "-" 0 0 5 4 "-" "curl/7.67.0" "d57ea5ad-90e9-46d9-8b55-8e6e404a8f9b" "example.com" "10.1.4.12:8080" outbound|80||istio-egressgateway.istio-egress.svc.cluster.local 10.1.0.17:42140 93.184.216.34:80 10.1.0.17:60326 - -
此外,也請檢查輸出閘道存取記錄:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
您傳送的每個要求都會顯示類似下列內容的輸出閘道存取記錄項目:
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 4 3 "10.1.0.17" "curl/7.67.0" "095711e6-64ef-4de0-983e-59158e3c55e7" "example.com" "93.184.216.34:80" outbound|80||example.com 10.1.4.12:37636 10.1.4.12:8080 10.1.0.17:44404 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
為第二個命名空間設定不同的路徑
設定第二個外部主機的轉送,瞭解如何為不同團隊設定不同的外部連線。
為
team-y
命名空間建立Sidecar
資源:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-y spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-y/*' EOF
將測試應用程式部署至
team-y
命名空間:kubectl -n team-y create -f ./test.yaml
註冊第二個外部主機,並將其匯出至
team-x
和team-y
命名空間:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: httpbin-org-ext namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: httpbin.org spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
建立虛擬服務,透過輸出閘道將流量轉送至 httpbin.org:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
執行
istioctl analyze
檢查設定錯誤:${ISTIOCTL} analyze -n istio-egress --revision REVISION
您會看到:
✔ No validation issues found when analyzing namespace: istio-egress.
從
team-y
測試應用程式向 httpbin.org 發出要求:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test -o \ jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
您會看到
200 OK
回應。此外,請從
team-x
測試應用程式向 httpbin.org 發出要求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
您會看到
200 OK
回應。嘗試從
team-y
命名空間向 example.com 發出要求:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
由於未為
example.com
主機設定輸出路徑,因此要求失敗。
使用授權政策進一步控管流量
在本教學課程中,您會在 istio-egress
命名空間中建立輸出閘道的授權政策。您可以設定 Kubernetes RBAC,只允許網路管理員存取 istio-egress
命名空間。
建立
AuthorizationPolicy
,讓team-x
命名空間中的應用程式可以連線至 example.com,但透過通訊埠 80 送出要求時,無法連線至其他外部主機。出口閘道 Pod 上的對應targetPort
為 8080。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-x-to-example-com namespace: istio-egress spec: action: ALLOW rules: - from: - source: namespaces: - 'team-x' to: - operation: hosts: - 'example.com' when: - key: destination.port values: ["8080"] EOF
確認您可以從
team-x
命名空間中的測試應用程式,向 example.com 提出要求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
您會看到
200 OK
回應。請嘗試從
team-x
命名空間的測試應用程式提出對 httpbin.org 的要求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
要求會失敗,並顯示
RBAC: access denied
訊息和 403 Forbidden 狀態碼。授權政策通常會過一小段時間才會生效,因此您可能需要稍候片刻。授權政策可精細控管允許或拒絕的流量。套用下列授權政策,允許
team-y
命名空間中的測試應用程式,在透過通訊埠 80 發送要求時,使用特定網址路徑向 httpbin.org 發出要求。輸出閘道 Pod 上的對應targetPort
為 8080。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-y-to-httpbin-teapot namespace: istio-egress spec: action: ALLOW rules: - from: - source: namespaces: - 'team-y' to: - operation: hosts: - httpbin.org paths: ['/status/418'] when: - key: destination.port values: ["8080"] EOF
嘗試從
team-y
命名空間的測試應用程式連線至 httpbin.org:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
要求會失敗,並顯示 RBAC:存取遭拒訊息和 403 Forbidden 狀態碼。
現在,請從同一個應用程式向 httpbin.org/status/418 發出要求:
kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl http://httpbin.org/status/418
要求成功,因為路徑符合授權政策中的模式。輸出結果會與下列內容相似:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
輸出閘道的傳輸層安全標準 (TLS) 啟動
您可以將輸出閘道設為向 TLS 或雙向 TLS upgrade
(發出) 純 HTTP 要求。搭配 Istio 雙向 TLS 和 TLS 來源時,允許應用程式發出純 HTTP 要求有幾項優點。詳情請參閱最佳做法指南。
建立
DestinationRule. The DestinationRule
指定閘道發起與 example.com 的 TLS 連線。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: example-com-originate-tls namespace: istio-egress spec: host: example.com subsets: - name: example-com-originate-TLS trafficPolicy: portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
更新 example.com 的虛擬服務,讓傳送至目的地主機時,閘道上通訊埠 80 的要求會
upgraded
至通訊埠 443 上的 TLS:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 EOF
從
team-x
命名空間的測試應用程式向 example.com 發出多項要求:for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com done
和先前一樣,要求會成功,並傳回
200 OK
回應。檢查輸出閘道記錄,確認閘道是否透過發起 TLS 連線,將要求轉送至目的地主機:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath=" {.items[0].metadata.name}") istio-proxy
輸出結果會與下列內容相似:
[2020-09-24T17:58:02.548Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 6 5 "10.1.1.15" "curl/7.67.0" "83a77acb-d994-424d-83da-dd8eac902dc8" "example.com" "93.184.216.34:443" outbound|443|example-com-originate-TLS|example.com 10.1.4.31:49866 10.1.4.31:8080 10.1.1.15:37334 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
Proxy Sidecar 使用通訊埠 80 將要求傳送至閘道,並在通訊埠 443 上發起 TLS,將要求傳送至目的地主機。
HTTPS/TLS 連線的直通
現有應用程式在與外部服務通訊時,可能已使用 TLS 連線。您可以設定輸出閘道,讓傳輸層安全標準 (TLS) 連線通過,不必解密。
修改設定,讓輸出閘道對通訊埠 443 的連線使用 TLS 直通:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL - port: number: 443 name: tls protocol: TLS hosts: - '*' tls: mode: PASSTHROUGH EOF
更新指向輸出閘道的
DestinationRule
,在閘道上為通訊埠 443 新增第二個子集。這個新子集不會使用相互 TLS。Istio mTLS 不支援傳遞 TLS 連線。通訊埠 80 的連線仍使用 mTLS:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: portLevelSettings: - port: number: 80 tls: mode: ISTIO_MUTUAL - name: target-egress-gateway-TLS-passthrough EOF
更新 example.com 的虛擬服務,讓通訊埠 443 上的 TLS 流量通過閘道:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - example.com route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - example.com route: - destination: host: example.com port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
更新 httpbin.org 的虛擬服務,讓通訊埠 443 上的 TLS 流量通過閘道:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - httpbin.org route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - httpbin.org route: - destination: host: httpbin.org port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
新增授權政策,接受傳送至 Egress 閘道服務通訊埠 443 的任何流量。閘道 Pod 上的對應
targetPort
為 8443。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-all-443 namespace: istio-egress spec: action: ALLOW rules: - when: - key: destination.port values: ["8443"] EOF
執行
istioctl analyze
檢查設定錯誤:${ISTIOCTL} analyze -n istio-egress --revision REVISION
您會看到:
✔ No validation issues found when analyzing namespace: istio-egress.
從
team-x
命名空間的測試應用程式,向 example.com 發出純 HTTP 要求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
要求成功,並傳回
200 OK
回應。現在,請從
team-x
命名空間的測試應用程式發出多個 TLS (HTTPS) 要求:for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -o /dev/null \ -w "%{http_code}\n" \ https://example.com done
您會看到 200 個回應。
再次查看輸出閘道記錄:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
您會看到類似下列內容的記錄項目:
[2020-09-24T18:04:38.608Z] "- - -" 0 - "-" "-" 1363 5539 10 - "-" "-" "-" "-" "93.184.216.34:443" outbound|443||example.com 10.1.4.31:51098 10.1.4.31:8443 10.1.1.15:57030 example.com -
系統已將 HTTPS 要求視為 TCP 流量,並透過閘道傳送至目的地主機,因此記錄中不會包含 HTTP 資訊。
使用 Kubernetes NetworkPolicy 做為額外控制項
在許多情況下,應用程式可以略過 Sidecar Proxy。
您可以使用 Kubernetes NetworkPolicy
,額外指定工作負載可建立的連線。套用單一網路政策後,系統會拒絕所有未明確允許的連線。
本教學課程僅考量網路政策的輸出連線和輸出選取器。如果您在自己的叢集上使用網路政策控管連入流量,則必須建立與連出政策對應的連入政策。舉例來說,如果您允許 team-x
命名空間中的工作負載輸出至 team-y
命名空間,也必須允許 team-x
命名空間輸入至 team-y
命名空間。
允許在
team-x
命名空間中部署的工作負載和 Proxy 連線至istiod
和輸出閘道:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-control-plane namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-egress podSelector: matchLabels: istio: egressgateway EOF
允許工作負載和 Proxy 查詢 DNS:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-dns namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": kube-system ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
允許工作負載和 Proxy 連線至提供 Google API 和服務的 IP,包括 Cloud Service Mesh 憑證授權單位:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-google-apis namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - ipBlock: cidr: 199.36.153.4/30 - ipBlock: cidr: 199.36.153.8/30 EOF
允許工作負載和 Proxy 連線至 GKE 中繼資料伺服器:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-metadata-server namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: # For GKE data plane v2 - ipBlock: cidr: 169.254.169.254/32 - to: # For GKE data plane v1 - ipBlock: cidr: 127.0.0.1/32 # Prior to 1.21.0-gke.1000 - ipBlock: cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later ports: - protocol: TCP port: 987 - protocol: TCP port: 988 EOF
選用:允許
team-x
命名空間中的工作負載和 Proxy 彼此建立連線:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-same-namespace namespace: team-x spec: podSelector: {} ingress: - from: - podSelector: {} egress: - to: - podSelector: {} EOF
選用:允許
team-x
命名空間中的工作負載和 Proxy 連線至其他團隊部署的工作負載:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-team-y namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": team-y EOF
補充 Proxy 之間的連線會持續存在。套用新網路政策時,現有連線不會關閉。在 team-x 命名空間中重新啟動工作負載,確保現有連線已關閉:
kubectl -n team-x rollout restart deployment
確認您仍可從
team-x
命名空間的測試應用程式,對 example.com 發出 HTTP 要求:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
要求成功,並傳回
200 OK
回應。
使用 Private Google Access 和 IAM 權限直接存取 Google API
Google 的 API 和服務會使用外部 IP 位址公開。當具有虛擬私有雲原生別名 IP 位址的 Pod 使用私人 Google 存取權連線至 Google API 時,流量絕不會離開 Google 的網路。
設定本教學課程的基礎架構時,您已為 GKE Pod 使用的子網路啟用私人 Google 存取權。如要允許存取私人 Google 存取權使用的 IP 位址,您已建立路徑、虛擬私有雲防火牆規則和私有 DNS 區域。這項設定可讓 Pod 直接連上 Google API,不必透過輸出閘道傳送流量。您可以透過 GKE 適用的工作負載身分聯盟和 IAM,控管特定 Kubernetes 服務帳戶 (以及命名空間) 可用的 API。由於連線至 Google API 的作業並非由輸出閘道處理,因此 Istio 授權不會生效。
Pod 必須先透過 IAM 取得權限,才能呼叫 Google API。您在本教學課程中使用的叢集已設定為使用 GKE 適用的工作負載身分聯盟,因此 Kubernetes 服務帳戶可以做為 Google 服務帳戶。
為應用程式建立 Google 服務帳戶:
gcloud iam service-accounts create sa-test-app-team-x
允許 Kubernetes 服務帳戶模擬 Google 服務帳戶:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[team-x/test]" \ sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
在
team-x
命名空間中,使用 Google 服務帳戶的電子郵件地址,為測試應用程式的 Kubernetes 服務帳戶加上註解:cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: annotations: iam.gke.io/gcp-service-account: sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com name: test namespace: team-x EOF
測試應用程式 Pod 必須能夠存取 Google 中繼資料伺服器 (以 DaemonSet 形式執行),才能取得呼叫 Google API 的臨時憑證。為 GKE 中繼資料伺服器建立服務項目:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: metadata-google-internal namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: metadata.google.internal spec: hosts: - metadata.google.internal ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
同時為 private.googleapis.com 和 storage.googleapis.com 建立服務項目:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: private-googleapis-com namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: googleapis.com spec: hosts: - private.googleapis.com - storage.googleapis.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
確認 Kubernetes 服務帳戶已正確設定為 Google 服務帳戶:
kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- gcloud auth list
您會看到 Google 服務帳戶列為有效且唯一的 ID。
在 Cloud Storage bucket 中建立測試檔案:
echo "Hello, World!" > /tmp/hello gcloud storage buckets create gs://${PROJECT_ID}-bucket gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
授予服務帳戶權限,列出及查看 bucket 中的檔案:
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-bucket/ \ --member=serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com \ --role=roles/storage.objectViewer
確認測試應用程式可以存取測試值區:
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gcloud storage cat gs://${PROJECT_ID}-bucket/hello
您會看到:
Hello, World!
清除所用資源
如要避免系統向您的 Google Cloud 帳戶收取本教學課程中所用資源的相關費用,請刪除含有該項資源的專案,或者保留專案但刪除個別資源。
如要避免系統向您的 Google Cloud 帳戶收取這個教學課程所用資源的費用,請完成下列各節中的步驟:
刪除專案
如要避免付費,最簡單的方法就是刪除您為本教學課程建立的專案。
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
後續步驟
- 請參閱隨附的最佳做法指南。
- 請參閱 GKE 強化指南。
- 瞭解如何使用 CA 服務,自動管理 Cloud Service Mesh 進入閘道的 TLS 憑證。
- 瞭解如何使用 GKE Enterprise Configuration Management,管理所有基礎架構的設定和政策。
- 如需更多參考架構、圖表和最佳做法,請瀏覽 Cloud 架構中心。