在 GKE 叢集中使用 Cloud Service Mesh 輸出閘道:教學課程


本教學課程說明如何使用 Cloud Service Mesh 出口閘道和其他 Google Cloud 控制項,保護在 Google Kubernetes Engine 叢集中部署的工作負載的傳出流量 (出口)。本教學課程是在 GKE 叢集中使用 Cloud Service Mesh 輸出閘道的最佳做法的輔助教材。

本教學課程的目標對象包括網路、平台和安全性工程師,他們負責管理一或多個軟體提交團隊使用的 Google Kubernetes Engine 叢集。對於必須證明遵守法規的機構 (例如 GDPRPCI) 來說,這裡所述的控管措施特別實用。

目標

  • 設定執行 Cloud Service Mesh 的基礎架構:
  • 安裝 Cloud Service Mesh。
  • 在專屬節點集區中安裝輸出閘道 Proxy。
  • 透過輸出閘道,為外部流量設定多租戶轉送規則:
    • 命名空間 team-x 中的應用程式可連線至 example.com
    • 命名空間 team-y 中的應用程式可連線至 httpbin.org
  • 使用 Sidecar 資源,限制每個命名空間的附屬 Proxy Egress 設定範圍。
  • 設定授權政策,強制執行輸出規則。
  • 設定出口網關,將純文字 HTTP 要求升級為 TLS (TLS 來源)。
  • 設定輸出閘道,以便傳送 TLS 流量。
  • 將 Kubernetes 網路政策設為額外的輸出控制項。
  • 使用私人 Google 存取權和身分與存取權管理 (IAM) 權限,設定對 Google API 的直接存取權。

費用

在本文件中,您會使用 Google Cloud的下列計費元件:

您可以使用 Pricing Calculator 根據預測用量產生預估費用。 新 Google Cloud 使用者可能符合申請免費試用的資格。

完成本教學課程後,您可以刪除已建立的資源,以免持續產生費用。詳情請參閱「清除所用資源」一節。

事前準備

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  4. 請建立工作目錄,以便在遵循本教學課程時使用:

    mkdir -p ~/WORKING_DIRECTORY
    cd ~/WORKING_DIRECTORY
    
  5. 建立 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
    
  6. 啟用 compute.googleapis.com

    gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
    
  7. 將指令碼設為可執行狀態,並使用 source 指令執行指令碼,以便初始化環境。如果系統提示您啟用 compute.googleapis.com,請選取 Y

    chmod +x ./init-egress-tutorial.sh
    source ./init-egress-tutorial.sh
    

設定基礎架構

建立虛擬私有雲網路和子網路

  1. 建立新的虛擬私有雲網路:

    gcloud compute networks create vpc-network \
        --subnet-mode custom
    
  2. 為叢集建立子網路,並為 Pod 和服務預先指定次要 IP 位址範圍。啟用私人 Google 存取權,讓只有內部 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

Cloud NAT 可讓沒有外部 IP 位址的工作負載連線至網際網路上的目的地,並接收來自這些目的地的傳入回應。

  1. 建立 Cloud Router:

    gcloud compute routers create nat-router \
        --network vpc-network
    
  2. 在路由器中新增 NAT 設定:

    gcloud compute routers nats create nat-config \
        --router nat-router \
        --nat-all-subnet-ip-ranges \
        --auto-allocate-nat-external-ips
    

為每個 GKE 節點集區建立服務帳戶

建立兩個服務帳戶,供兩個 GKE 節點集區使用。每個節點集區都會指派個別的服務帳戶,讓您將 VPC 防火牆規則套用至特定節點。

  1. 建立服務帳戶,供預設節點集區中的節點使用:

    gcloud iam service-accounts create sa-application-nodes \
        --description="SA for application nodes" \
        --display-name="sa-application-nodes"
    
  2. 建立服務帳戶,供閘道節點集區中的節點使用:

    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

建立防火牆規則

在後續步驟中,您會將防火牆規則套用至虛擬私有雲網路,這樣一來,根據預設,所有輸出流量都會遭到拒絕。叢集必須具備特定連線功能才能運作,閘道節點也必須能夠連線至虛擬私有雲外的目的地。一組最少的特定防火牆規則會覆寫預設的拒絕所有規則,以便允許必要的連線。

  1. 建立預設 (低優先順序) 防火牆規則,拒絕所有來自虛擬私有雲網路的輸出流量:

    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."
    
  2. 建立規則,只允許擁有閘道服務帳戶的節點存取網際網路:

    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"
    
  3. 允許節點存取 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."
    
  4. 選用:如果您使用 Managed Cloud Service Mesh,則不需要這項防火牆規則。

    在將附屬 Proxy 注入工作負載時,Cloud Service Mesh 會使用 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"
    
  5. 允許叢集中執行的節點和 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"
    
  6. 允許存取 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)"
    
  7. 允許 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"
    

設定 Google Cloud API 的私人存取權

私人 Google 存取權可讓只有內部 IP 位址的 VM 和 Pod 存取 Google API 和服務。雖然 Google API 和服務是透過外部 IP 提供,但使用私人 Google 存取權時,節點的流量絕不會離開 Google 網路。

啟用 Cloud DNS API:

gcloud services enable dns.googleapis.com

建立私人 DNS 區域、CNAMEA 記錄,讓節點和工作負載可透過私人 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 區域、CNAMEA 記錄,讓節點可透過私人 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 叢集

  1. 找出 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
    
  2. 啟用 Google Kubernetes Engine API:

    gcloud services enable container.googleapis.com
    
  3. 建立私人 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 位址的私人節點。Pod 和服務會從您在建立 VPC 子網路時定義的命名次要範圍中,指派 IP。

    叢集內控制平面搭配 Cloud Service Mesh 時,叢集節點必須使用至少有 4 個 vCPU 的機器類型。

    Google 建議您讓叢集訂閱「一般」發布管道,確保節點執行 Cloud Service Mesh 支援的 Kubernetes 版本。

    如要進一步瞭解使用叢集內控制平面執行 Cloud Service Mesh 的先決條件,請參閱叢集內先決條件

    如要進一步瞭解執行受管理的 Cloud Service Mesh 的相關規定和限制,請參閱受管理的 Cloud Service Mesh 支援的功能

    叢集已啟用 Workload Identity Federation for GKE。Cloud Service Mesh 需要 GKE 適用的工作負載身分聯盟,這是從 GKE 工作負載存取 Google API 的建議方式。

  4. 建立名為「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。

  5. 下載憑證,以便使用 kubectl 連線至叢集:

    gcloud container clusters get-credentials cluster1
    
  6. 確認閘道節點是否有正確的污染:

    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 後,請停止並返回本教學課程,但不要安裝入口或出口閘道。

安裝輸出閘道

  1. 為外送閘道建立 Kubernetes 命名空間:

    kubectl create namespace istio-egress
    
  2. 啟用要用於插入的命名空間。步驟取決於控制層實作

    代管 (TD)

    將預設的注入標籤套用至命名空間:

    kubectl label namespace istio-egress \
        istio.io/rev- istio-injection=enabled --overwrite
    

    受管理 (Istiod)

    建議做法:執行下列指令,將預設注入標籤套用至命名空間:

      kubectl label namespace istio-egress \
          istio.io/rev- istio-injection=enabled --overwrite
    

    如果您是現有的 Managed Istiod 控制平面使用者:我們建議您使用預設插入作業,但也支援以修訂版本為基礎的插入作業。請按照下列操作說明進行:

    1. 執行下列指令,找出可用的發布版本:

      kubectl -n istio-system get controlplanerevision
      

      輸出結果會與下列內容相似:

      NAME                AGE
      asm-managed-rapid   6d7h
      

      在輸出內容中,NAME 欄下方的值是修訂版本標籤,對應至 Cloud Service Mesh 版本的發布管道

    2. 將修訂版本標籤套用至命名空間:

      kubectl label namespace istio-egress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      

    叢集內

    建議做法:執行下列指令,將預設注入標籤套用至命名空間:

      kubectl label namespace istio-egress \
          istio.io/rev- istio-injection=enabled --overwrite
    

    建議您使用預設插入方式,但系統也支援以修訂版本為基礎的插入方式: 請按照下列操作說明操作:

    1. 使用下列指令,找出 istiod 上的修訂版本標籤:

      kubectl get deploy -n istio-system -l app=istiod -o \
         jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
      
    2. 將修訂版本標籤套用至命名空間。在下列指令中,REVISION_LABEL 是您在上一個步驟中記下的 istiod 修訂版本標籤值。

      kubectl label namespace istio-egress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      
  3. 為輸出閘道建立運算子資訊清單

    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
    
  4. 下載 istioctl 工具。即使您使用的是 Cloud Service Mesh 1.15 以下版本,也必須使用 1.16.2-asm.2 以上版本。請參閱「下載正確的 istioctl 版本」。

  5. 解壓縮下載的封存檔案後,請設定環境變數,以便保留 istioctl 工具的路徑,並將其新增至初始化指令碼:

    ISTIOCTL=$(find "$(pwd -P)" -name istioctl)
    echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
    
  6. 使用作業系統管理員資訊清單和 istioctl 建立外送閘道安裝資訊清單:

    ${ISTIOCTL} manifest generate \
        --filename egressgateway-operator.yaml \
        --output egressgateway \
        --cluster-specific
    
  7. 安裝輸出閘道:

    kubectl apply --recursive --filename egressgateway/
    
  8. 確認出口閘道是否在 gateway 節點集區中的節點上執行:

    kubectl get pods -n istio-egress -o wide
    
  9. 輸出閘道 Pod 會為 gateway 節點集區中的節點提供 affinity,以及讓 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 類型 (受管理或叢集內):

準備網格和測試應用程式

  1. 請確認已啟用嚴格雙向傳輸層安全標準 (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 資源,藉此覆寫這項設定。

  2. 建立用於部署測試工作負載的命名空間。本教學課程後續步驟會說明如何為每個命名空間設定不同的傳出路由規則。

    kubectl create namespace team-x
    kubectl create namespace team-y
    
  3. 為命名空間加上標籤,讓 Kubernetes 網路政策可以選取這些命名空間:

    kubectl label namespace team-x team=x
    kubectl label namespace team-y team=y
    
  4. 如要讓 Cloud Service Mesh 自動注入 Proxy 補充資訊,請在工作負載命名空間中設定控制層修訂版本標籤:

    kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite
    kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwrite
    
  5. 建立用於進行測試部署作業的 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
    
  6. 將測試應用程式部署至 team-x 命名空間:

    kubectl -n team-x create -f ./test.yaml
    
  7. 確認測試應用程式已部署至預設資源池中的節點,且已插入 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 會在預設節點集區中的節點上執行。

  8. 確認無法從測試容器向外部網站提出 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 代理程式會產生錯誤訊息。

使用 Sidecar 資源限制補充 Proxy 設定的範圍

您可以使用側邊車資源,限制為側邊車 Proxy 設定的傳出事件監聽器範圍。為減少設定膨脹和記憶體用量,建議您為每個命名空間套用預設 Sidecar 資源。

Cloud Service Mesh 在 sidecar 中執行的 Proxy 是 Envoy。在 Envoy 術語中,cluster 是一組邏輯相似的上游端點,用於做為負載平衡的目的。

  1. 請執行 istioctl proxy-config 指令,檢查 Envoy 附加元件 Proxy 中為測試 Pod 所設定的輸出叢集:

    ${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \
        -o jsonpath={.items..metadata.name}).team-x --direction outbound
    

    清單中約有 11 個 Envoy 叢集,其中部分是用於出口閘道。

  2. 將 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 設定,只納入透過定義服務項目明確新增至 Mesh 服務註冊表的服務主機。

    設定 egress.hosts 可指定輔助 Proxy 只會從使用 exportTo 屬性提供的出口命名空間中選取路徑。'team-x/*' 部分包含在 team-x 命名空間中已在本機設定的任何路徑。

  3. 查看 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 將流量透過出口閘道轉送

  1. 為通訊埠 80 上的 HTTP 流量設定 GatewayGateway 會選取您部署至出口命名空間的出口閘道 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
    
  2. 為出口閘道建立 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
    
  3. 在出口命名空間中建立 ServiceEntry,即可在 team-x 命名空間的 Mesh 服務註冊中心中明確註冊 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
    
  4. 建立 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
    
  5. 執行 istioctl analyze 檢查設定錯誤:

    ${ISTIOCTL} analyze -n istio-egress --revision REVISION
    

    輸出結果會與下列內容相似:

    ✔ No validation issues found when analyzing namespace: istio-egress.
    
  6. 透過輸出閘道傳送多個要求至外部網站:

    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 狀態代碼。

  7. 檢查 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 - -
    
  8. 請一併檢查輸出閘道存取記錄:

    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 -
    

為第二個命名空間設定不同的路徑

為第二個外部主機設定轉送,瞭解如何為不同團隊設定不同的外部連線。

  1. 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
    
  2. 將測試應用程式部署至 team-y 命名空間:

    kubectl -n team-y create -f ./test.yaml
    
  3. 註冊第二個外部主機,並匯出至 team-xteam-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
    
  4. 建立虛擬服務,透過出口閘道將流量轉送至 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
    
  5. 執行 istioctl analyze 檢查設定錯誤:

    ${ISTIOCTL} analyze -n istio-egress --revision REVISION
    

    您會看到:

    ✔ No validation issues found when analyzing namespace: istio-egress.
    
  6. 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 回應。

  7. 另外,請從 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 回應。

  8. 嘗試從 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 命名空間。

  1. 建立 AuthorizationPolicy,讓 team-x 命名空間中的應用程式可透過通訊埠 80 傳送要求,連線至 example.com,但無法連線至其他外部主機。出口閘道 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
    
  2. 確認您可以從 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 回應。

  3. 請嘗試從 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 狀態碼。授權政策通常需要短暫的延遲時間才會生效,因此您可能需要等待幾秒鐘。

  4. 授權政策可提供多元控管機制,允許或拒絕特定流量。套用下列授權政策,允許 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
    
  5. 嘗試從 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: access denied」訊息和 403 Forbidden 狀態碼。

  6. 現在請透過同一個應用程式向 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 來源

您可以設定出口網關,將 upgrade (來源) 純 HTTP 要求轉送至 TLS 或雙向 TLS。允許應用程式提出純 HTTP 要求,與 Istio 雙向 TLS 和 TLS 來源搭配使用時,具有多項優點。詳情請參閱最佳做法指南

輸出閘道中的 TLS 啟動

  1. 建立 DestinationRule. The DestinationRule 可指定閘道會建立傳輸層安全標準 (TLS) 連線至 example.com。

    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
    
  2. 更新 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
    
  3. 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 回應。

  4. 請查看傳出閘道記錄,確認閘道是否透過原始 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 附加元件使用通訊埠 80 將要求傳送至閘道,並透過通訊埠 443 上的 TLS 將要求傳送至目的主機。

HTTPS/TLS 連線的直通

現有應用程式在與外部服務通訊時,可能已在使用 TLS 連線。您可以設定出口閘道,讓傳輸層安全標準 (TLS) 連線在未解密的情況下傳送。

tls 直通

  1. 修改設定,讓出口閘道使用 TLS 轉送功能連線至通訊埠 443:

    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
    
  2. 更新指向外送閘道的 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
    
  3. 更新 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
    
  4. 更新 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
    
  5. 新增授權政策,接受傳送至外送閘道服務的通訊埠 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
    
  6. 執行 istioctl analyze 檢查設定錯誤:

    ${ISTIOCTL} analyze -n istio-egress --revision REVISION
    

    您會看到:

    ✔ No validation issues found when analyzing namespace: istio-egress.
    
  7. 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 回應。

  8. 現在,請從 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 個回應。

  9. 再次查看外送閘道記錄:

    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 做為額外控管機制

在許多情況下,應用程式可以略過附屬 Proxy。您可以使用 Kubernetes NetworkPolicy,進一步指定工作負載可建立哪些連線。套用單一網路政策後,系統會拒絕所有未明確允許的連線。

本教學課程只會考量網路政策的輸出連線和輸出選取器。如果您在自己的叢集上使用網路政策控制入站流量,則必須建立入站政策,以便與出站政策相對應。舉例來說,如果您允許 team-x 命名空間中的作業負載輸出至 team-y 命名空間,則必須同時允許 team-x 命名空間輸入 team-y 命名空間。

  1. 允許在 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
    
  2. 允許工作負載和 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
    
  3. 允許工作負載和 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
    
  4. 允許工作負載和 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
    
  5. 選用:允許 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
    
  6. 選用:允許 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
    
  7. 補充 Proxy 之間的連線會保留。套用新的網路政策時,現有連線不會關閉。請重新啟動 team-x 命名空間中的各項工作負載,確保現有連線已關閉:

    kubectl -n team-x rollout restart deployment
    
  8. 請確認您仍可從 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 回應。

使用私人 Google 存取權和 IAM 權限直接存取 Google API

Google 的 API 和服務會使用外部 IP 位址公開。當具有虛擬私有雲原生別名 IP 位址的 Pod 使用私人 Google 存取權連線至 Google API 時,流量絕不會離開 Google 的網路。

設定本教學課程的基礎架構時,您已為 GKE Pod 使用的子網路啟用私人 Google 存取權。為允許存取私人 Google 存取權使用的 IP 位址,您已建立路徑、VPC 防火牆規則和私人 DNS 區域。這項設定可讓 Pod 直接存取 Google API,無須透過出口閘道傳送流量。您可以使用 Workload Identity Federation for GKE 和 IAM,控管特定 Kubernetes 服務帳戶 (以及命名空間) 可使用的 API。出口網關未處理 Google API 的連線,因此 Istio 授權不會生效。

您必須使用 IAM 授予權限,才能讓 Pod 呼叫 Google API。您在本教學課程中使用的叢集已設定為使用 GKE 適用的工作負載身分聯盟,可讓 Kubernetes 服務帳戶充當 Google 服務帳戶。

  1. 建立應用程式可使用的 Google 服務帳戶:

    gcloud iam service-accounts create sa-test-app-team-x
    
  2. 允許 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
    
  3. team-x 命名空間中,為測試應用程式提供 Kubernetes 服務帳戶的註解,並附上 Google 服務帳戶的電子郵件地址:

    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
    
  4. 測試應用程式 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
    
  5. 另外,請為 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
    
  6. 確認 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 服務帳戶列為唯一有效身分。

  7. 在 Cloud Storage 值區中建立測試檔案:

    echo "Hello, World!" > /tmp/hello
    gcloud storage buckets create gs://${PROJECT_ID}-bucket
    gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
    
  8. 授予服務帳戶權限,以便列出及查看值區中的檔案:

    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
    
  9. 確認測試應用程式可存取測試資料夾:

    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 帳戶收取這個教學課程所用資源的費用,請完成下列各節中的步驟:

刪除專案

如要避免系統向您收費,最簡單的方法就是刪除您在教學課程中建立的專案。

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

後續步驟