Cloud Service Mesh 範例:mTLS


在 Cloud Service Mesh 1.5 以上版本中,系統會預設啟用自動雙向 TLS (自動 mTLS)。有了自動 mTLS,用戶端 sidecar proxy 會自動偵測伺服器是否有 sidecar。用戶端 sidecar 會將 mTLS 傳送至含 sidecar 的工作負載,並將純文字傳送至不含 sidecar 的工作負載。不過請注意,服務會接受純文字和 mTLS 流量。在為 Pod 注入補充 Proxy時,建議您也將服務設為只接受 mTLS 流量。

您可以透過 Cloud Service Mesh 套用單一 YAML 檔案,在應用程式程式碼之外強制執行 mTLS。Cloud Service Mesh 可讓您靈活套用驗證政策,適用於整個服務網格、命名空間或個別工作負載。

雙向 mTLS

費用

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

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

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

事前準備

部署入口閘道

  1. kubectl 的目前背景資訊設為叢集:

    gcloud container clusters get-credentials CLUSTER_NAME  \
    --project=PROJECT_ID \
    --zone=CLUSTER_LOCATION 
    
  2. 為 Ingress Gateway 建立命名空間:

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

    代管 (TD)

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

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

    受管理 (Istiod)

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

      kubectl label namespace asm-ingress \
          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 asm-ingress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      
  4. anthos-service-mesh-samples 存放區中部署範例閘道:

    kubectl apply -n asm-ingress \
    -f docs/shared/asm-ingress-gateway
    

    預期輸出內容:

    serviceaccount/asm-ingressgateway configured
    service/asm-ingressgateway configured
    deployment.apps/asm-ingressgateway configured
    gateway.networking.istio.io/asm-ingressgateway configured
    

部署 Online Boutique 範例應用程式

  1. 如果您尚未設定,請將 kubectl 的目前背景資訊設為叢集:

      gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. 為範例應用程式建立命名空間:

      kubectl create namespace onlineboutique
    
  3. onlineboutique 命名空間加上標籤,以便自動插入 Envoy Proxy。按照這篇文章中的步驟啟用自動 Sidecar Inject 功能。

  4. 部署範例應用程式、前端的 VirtualService,以及工作負載的服務帳戶。在本教學課程中,您將部署 Online Boutique,這是一個微服務示範應用程式。

      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/virtual-service.yaml
      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/service-accounts
    

查看服務

  1. 查看 onlineboutique 命名空間中的 Pod:

    kubectl get pods -n onlineboutique
    

    預期輸出內容:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-m84m6               2/2     Running   0          2m7s
    cartservice-c77f6b866-m67vd              2/2     Running   0          2m8s
    checkoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10s
    currencyservice-59bc889674-jhk8z         2/2     Running   0          2m8s
    emailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10s
    frontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9s
    loadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8s
    paymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9s
    productcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114s
    recommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9s
    redis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7s
    shippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s
    

    應用程式的所有 Pod 都應已啟動並執行,且 READY 欄中應有 2/2。這表示 Pod 已成功插入 Envoy 邊車 Proxy。如果幾分鐘後仍未顯示 2/2,請參閱疑難排解指南

  2. 取得外部 IP,並將其設為變數:

    kubectl get services -n asm-ingress
    export FRONTEND_IP=$(kubectl --namespace asm-ingress \
    get service --output jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}' \
    )
    

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

    NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                      AGE
    asm-ingressgateway   LoadBalancer   10.19.247.233   35.239.7.64   80:31380/TCP,443:31390/TCP,31400:31400/TCP   27m
    
    
  3. 在網路瀏覽器中造訪 EXTERNAL-IP 位址。瀏覽器中應會顯示 Online Boutique 商店。

    線上精品店前端

建立 TestCurl Pod

建立 TestCurl Pod,以便傳送測試用的純文字流量。

  apiVersion: v1
  kind: Pod
  metadata:
    name: testcurl
    namespace: default
    annotations:
      sidecar.istio.io/inject: "false"
  spec:
    containers:
    - name: curl
      image: curlimages/curl
      command: ["sleep", "600"]

存取線上精品店

  1. kubectl 的目前背景資訊設為部署 Online Boutique 的叢集:

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. 列出 frontend 命名空間中的服務:

    kubectl get services -n frontend
    

    請注意,frontend-externalLoadBalancer,且具有外部 IP 位址。範例應用程式包含負載平衡器服務,因此可在沒有 Cloud Service Mesh 的情況下部署在 GKE 上。

  3. 使用 frontend-external 服務的外部 IP 位址,在瀏覽器中造訪應用程式:

    http://FRONTEND_EXTERNAL_IP/
    
  4. Cloud Service Mesh 可讓您部署入口網關。您也可以使用入口網關的外部 IP 位址存取線上精品店。取得閘道的外部 IP。將預留位置替換為下列資訊:

    • GATEWAY_SERVICE_NAME:Ingress Gateway 服務的名稱。如果您部署的是未經修改的範例閘道,或是部署了預設入口閘道,名稱會是 istio-ingressgateway
    • GATEWAY_NAMESPACE:部署入口網站閘道的命名空間。如果您部署了預設輸入閘道,命名空間就是 istio-system
    kubectl get service GATEWAY_NAME -n GATEWAY_NAMESPACE
    
  5. 在瀏覽器中開啟另一個分頁,然後使用入口網關的外部 IP 位址造訪應用程式:

    http://INGRESS_GATEWAY_EXTERNAL_IP/
    
  6. 執行下列指令,透過另一個 Pod 使用純 HTTP curl frontend 服務。由於這些服務位於不同的命名空間,因此您需要捲曲 frontend 服務的 DNS 名稱

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    根據預設,系統會同時接受 TLS 和純文字流量,因此要求會成功並顯示狀態 200

為每個命名空間啟用 mTLS

您可以透過 kubectl 套用 PeerAuthentication 政策來強制執行 mTLS。

  1. 將下列驗證政策儲存為 mtls-namespace.yaml

    cat <<EOF > mtls-namespace.yaml
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "namespace-policy"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    YAML 中的 mode: STRICT 行會將服務設為只接受 mTLS。根據預設,modePERMISSIVE,可將服務設為同時接受純文字和 mTLS。

  2. 套用驗證政策,將所有線上精品店服務設為只接受 mTLS:

    for ns in ad cart checkout currency email frontend loadgenerator \
         payment product-catalog recommendation shipping; do
    kubectl apply -n $ns -f mtls-namespace.yaml
    done
    

    預期的輸出內容:

    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created

  3. 在瀏覽器中前往使用 frontend-external 服務外部 IP 位址存取線上精品店的分頁:

    http://FRONTEND_EXTERNAL_IP/
    
  4. 重新整理頁面。瀏覽器會顯示以下錯誤:

    無法連上網站

    重新整理頁面會導致純文字傳送至 frontend 服務。由於 STRICT 驗證政策,側邊 Proxy 會封鎖對服務的要求。

  5. 在瀏覽器中前往使用 istio-ingressgateway 外部 IP 位址存取網路商店的分頁,然後重新整理頁面,即可成功顯示。使用入口網頁閘道存取線上精品店時,要求會沿著下列路徑傳送:

    雙向 mTLS

    mTLS 驗證流程:

    1. 瀏覽器會將純文字 HTTP 要求傳送至伺服器。
    2. 入口閘道 Proxy 容器會攔截要求。
    3. 網頁閘道 Proxy 會與伺服器端 Proxy (本例中的前端服務) 執行 TLS 握手。這項握手程序包括憑證交換。這些憑證會由 Cloud Service Mesh 預先載入至 Proxy 容器。
    4. 入口閘道 Proxy 會對伺服器的憑證執行安全命名檢查,驗證伺服器是否由授權身分執行。
    5. 入口網頁閘道和伺服器 Proxy 會建立 TLS 雙向連線,而伺服器 Proxy 會將要求轉送至伺服器應用程式容器 (前端服務)。
  6. 執行下列指令,使用另一個 Pod 中的純 HTTP frontend 服務curl

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    由於我們會從已套用嚴格 peerAuthentication 政策的無側載工作負載傳送純文字流量,因此您的要求會失敗。

尋找及刪除驗證政策

  1. 如需服務中介網中的所有 PeerAuthentication 政策清單,請參閱:

    kubectl get peerauthentication --all-namespaces
    

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

    NAMESPACE         NAME               MODE     AGE
    ad                namespace-policy   STRICT   17m
    cart              namespace-policy   STRICT   17m
    checkout          namespace-policy   STRICT   17m
    currency          namespace-policy   STRICT   17m
    email             namespace-policy   STRICT   17m
    frontend          namespace-policy   STRICT   17m
    loadgenerator     namespace-policy   STRICT   17m
    payment           namespace-policy   STRICT   17m
    product-catalog   namespace-policy   STRICT   17m
    recommendation    namespace-policy   STRICT   17m
    shipping          namespace-policy   STRICT   17m
    
  2. 從所有線上精品店命名空間中刪除驗證政策:

    for ns in ad cart checkout currency email frontend loadgenerator payment \
      product-catalog recommendation shipping; do
        kubectl delete peerauthentication -n $ns namespace-policy
    done;
    

    預期輸出內容:

    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    
  3. 使用 frontend-external 服務的外部 IP 位址存取線上精品店,然後重新整理頁面。頁面會如預期顯示。

  4. 執行下列指令,使用另一個 Pod 中的純 HTTP frontend 服務curl

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    根據預設,系統會同時接受 TLS 和純文字流量,因此要求會成功並顯示狀態 200

如果您在顯示工作負載清單的 Google Cloud 控制台中重新整理頁面,現在會顯示 mTLS 狀態為 Permissive

為每個工作負載啟用 mTLS

如要為特定工作負載設定 PeerAuthentication 政策,您必須設定 selector 部分,並指定符合所需工作負載的標籤。不過,Cloud Service Mesh 無法針對服務的傳出 mTLS 流量,匯總工作負載層級政策。您需要設定目標規則來管理這項行為。

  1. 將驗證政策套用至特定工作負載。請注意,下列政策如何使用標籤和選取器指定特定 frontend 部署作業。

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "frontend"
      namespace: "frontend"
    spec:
      selector:
        matchLabels:
          app: frontend
      mtls:
        mode: STRICT
    EOF
    

    預期輸出內容:

    peerauthentication.security.istio.io/frontend created
  2. 設定比對目的地規則。

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "networking.istio.io/v1alpha3"
    kind: "DestinationRule"
    metadata:
      name: "frontend"
    spec:
      host: "frontend.demo.svc.cluster.local"
      trafficPolicy:
        tls:
          mode: ISTIO_MUTUAL
    EOF
    

    預期輸出內容:

    destinationrule.networking.istio.io/frontend created
  3. 使用 frontend-external 服務的外部 IP 位址存取線上精品店,然後重新整理頁面。由於 frontend service 已設為 STRICT mTLS,而側載代理程式會封鎖要求,因此頁面不會顯示。

  4. 執行下列指令,使用另一個 Pod 中的純 HTTP frontend 服務curl

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    由於我們會從已套用嚴格 peerAuthentication 政策的無側載工作負載傳送純文字流量,因此您的要求會失敗。

  5. 刪除驗證政策:

    kubectl delete peerauthentication -n frontend frontend
    

    預期輸出內容:

    peerauthentication.security.istio.io "frontend" deleted
    
  6. 刪除目的地規則:

    kubectl delete destinationrule -n frontend frontend
    

    預期輸出內容:

    destinationrule.networking.istio.io "frontend" deleted
    

強制執行網格範圍的 mTLS

如要防止網格中的所有服務接受純文字流量,請設定網格層級的 PeerAuthentication 政策,並將 mTLS 模式設為 STRICT。網格層級 PeerAuthentication 政策不應包含選取器,且必須套用至根命名空間 istio-system。部署政策時,控制平面會自動佈建 TLS 憑證,讓工作負載彼此驗證。

  1. 強制執行網格全域 mTLS:

    kubectl apply -f - <<EOF
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "mesh-wide"
      namespace: "istio-system"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    預期的輸出內容:

    peerauthentication.security.istio.io/mesh-wide created

  2. 使用 frontend-external 服務的外部 IP 位址存取線上精品店,然後重新整理頁面。網頁未顯示。

  3. 執行下列指令,使用另一個 Pod 中的純 HTTP frontend 服務curl

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    由於我們會從已套用嚴格 peerAuthentication 政策的無側載工作負載傳送純文字流量,因此您的要求會失敗。

  4. 刪除 mesh-wide 政策:

    kubectl delete peerauthentication -n istio-system mesh-wide
    

    預期輸出內容:

    peerauthentication.security.istio.io "mesh-wide" deleted
    

清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本教學課程中所用資源的相關費用,請刪除含有該項資源的專案,或者保留專案但刪除個別資源。

  • 如要避免產生額外費用,請刪除叢集:

    gcloud container clusters delete  CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  • 如果您想保留叢集並移除 Online Boutique 範例,請按照下列步驟操作:

    1. 刪除應用程式命名空間:
      kubectl delete -f online-boutique/kubernetes-manifests/namespaces
    

    預期輸出內容:

    namespace "ad" deleted
    namespace "cart" deleted
    namespace "checkout" deleted
    namespace "currency" deleted
    namespace "email" deleted
    namespace "frontend" deleted
    namespace "loadgenerator" deleted
    namespace "payment" deleted
    namespace "product-catalog" deleted
    namespace "recommendation" deleted
    namespace "shipping" deleted
    
    1. 刪除服務項目:
      kubectl delete -f online-boutique/istio-manifests/allow-egress-googleapis.yaml
    

    預期輸出內容:

    serviceentry.networking.istio.io "allow-egress-googleapis" deleted
    serviceentry.networking.istio.io "allow-egress-google-metadata" deleted
    

後續步驟