將 IAP 與 Cloud Service Mesh 整合

本指南說明如何將 Identity-Aware Proxy (IAP) 與 Cloud Service Mesh 整合。透過 IAP 與 Cloud Service Mesh 整合,您就能根據 Google 的 BeyondCorp 原則安全存取服務。IAP 會驗證使用者身分和要求背景資訊,判斷是否應允許使用者存取應用程式或資源。Cloud Service Mesh 整合 IAP 後,可提供下列優點:

  • 針對在 Cloud Service Mesh 上執行的工作負載,提供完整的情境感知存取權控管功能。您可以根據原始要求的屬性 (例如使用者身分、IP 位址和裝置類型),設定精細的存取權政策。您可以將存取政策與要求網址的主機名稱和路徑限制合併。

  • 在 Cloud Service Mesh 授權中,啟用情境感知要求支援。

  • 透過 Google Cloud 負載平衡器,以可擴充、安全且高可用性的方式存取應用程式。高效能負載平衡功能提供內建的分散式阻斷服務 (DDoS) 攻擊防護機制,並支援全域任播 IP 位址。

必要條件

按照「安裝相依工具並驗證叢集」中的步驟操作, 完成下列事項:

此外,本指南假設您已具備下列條件:

設定採用 Cloud Service Mesh 的叢集

本節說明如何設定 IAP 整合,適用於 Cloud Service Mesh 的新安裝作業和升級作業。

新安裝次數

  1. 啟用「iap.googleapis.com」。在下列指令中,將 PROJECT_ID 替換為要安裝 Cloud Service Mesh 的專案:

    gcloud services enable \
      --project=PROJECT_ID \
      iap.googleapis.com
    
  2. 要更新的叢集必須設定 --addons=HttpLoadBalancing 選項。HttpLoadBalancing 外掛程式可為叢集啟用 HTTP (L7) 負載平衡控制器。執行下列指令,使用 Cloud Service Mesh 必要的選項更新叢集。除非您已設定預設區域或可用區,否則必須在指令中提供區域 (--region=REGION) 或可用區 (--zone=ZONE)。

    gcloud container clusters update CLUSTER_NAME \
      --project=PROJECT_ID \
      --update-addons=HttpLoadBalancing=ENABLED
    
  3. 根據預設,iap-operator.yaml 檔案會將通訊埠 31223 設為狀態通訊埠,並將通訊埠 31224 設為 http 通訊埠。如果叢集已使用通訊埠 31223,請執行下列指令,設定其他狀態通訊埠:

    kpt cfg set asm gcloud.container.cluster.ingress.statusPort STATUS_PORT
    

    如果叢集已使用通訊埠 31224,請執行下列指令來設定其他 HTTP 通訊埠:

    kpt cfg set asm gcloud.container.cluster.ingress.httpPort HTTP_PORT
    
  4. 請按照「安裝預設功能和 Mesh CA」中的步驟,使用 Google 提供的指令碼安裝 Cloud Service Mesh。執行指令碼時,請加入下列選項:

    --option iap-operator
    

    例如:

    ./asmcli install \
      --project_id "PROJECT_ID" \
      --cluster_name "CLUSTER_NAME" \
      --cluster_location "CLUSTER_LOCATION" \
      --fleet_id FLEET_PROJECT_ID \
      --output_dir DIR_PATH \
      --enable_all \
      --option iap-operator
    

    安裝 Cloud Service Mesh 時,iap-operator.yaml 檔案會將 istio-ingressgateway 服務上的 type 欄位設為 NodePort,將閘道設為在服務網格上開啟特定通訊埠。這樣一來,您就能設定負載平衡器,將傳送至網域名稱的流量導向這個通訊埠。

  5. 如要安裝代管 Cloud Service Mesh,請一併完成下列步驟:

    1. 將修訂版本標籤新增至 istio-system 命名空間。

    2. 下載 IAP 的 Istio 輸入閘道服務規格,並命名為 iap_operator.yaml。

    3. 將 Ingress 安裝為 NodePort 服務。

      asmcli experimental mcp-migrate-check -f iap_operator.yaml
      
      istioctl install -f /asm-generated-configs/gateways-istiooperator/"GATEWAY_NAME".yaml
      

安裝 Cloud Service Mesh 後,請返回本指南,並繼續進行下一節,設定與 IAP 的整合。

升級

本節涵蓋下列升級用途:

  • 您已設定 IAP 整合功能,且正在升級 Cloud Service Mesh。在本例中,您已在專案中啟用 iap.googleapis.com,並在叢集中啟用 HttpLoadBalancing 外掛程式。跳至步驟 3,下載 asm 套件並升級 Cloud Service Mesh。

  • 您正在升級 Cloud Service Mesh,並想首次設定與 IAP 的整合。在這種情況下,您需要完成下列所有步驟、升級 Cloud Service Mesh,並在升級後返回本指南完成整合。

  1. 啟用 iap.googleapis.com。在下列指令中,將 PROJECT_ID 替換為要安裝 Cloud Service Mesh 的專案。

    gcloud services enable \
      --project=PROJECT_ID \
      iap.googleapis.com
    
  2. 要更新的叢集必須設定 --addons=HttpLoadBalancing 選項。HttpLoadBalancing 外掛程式會為叢集啟用 HTTP (L7) 負載平衡控制器。執行下列指令,使用 Cloud Service Mesh 所需的選項更新叢集。除非已設定預設可用區或區域,否則您必須在指令中提供區域 (--region=REGION) 或可用區 (--zone=ZONE)。

    gcloud container clusters update CLUSTER_NAME \
      --project=PROJECT_ID
      --update-addons=HttpLoadBalancing=ENABLED
    
  3. 如要更新現有的 HTTP Cloud 負載平衡器,請執行下列指令,保留現有的 HTTP 和狀態通訊埠:

    kpt cfg set asm gcloud.container.cluster.ingress.httpPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
    
    kpt cfg set asm gcloud.container.cluster.ingress.statusPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')
    
  4. 按照「升級 Cloud Service Mesh」中的步驟操作,使用 Google 提供的指令碼升級 Cloud Service Mesh。

    升級 Cloud Service Mesh 時,iap-operator.yaml 檔案會將 istio-ingressgateway 服務的 type 欄位設為 NodePort,這會設定閘道,在服務網格上開啟特定連接埠。這樣一來,您就能設定負載平衡器,將傳送至網域名稱的流量轉送至這個通訊埠。

    根據預設,iap-operator.yaml 檔案會將通訊埠 31223 設為狀態通訊埠,並將通訊埠 31224 設為 HTTP 通訊埠。

    執行指令碼時,請加入下列選項:

    --option iap-operator
    

    例如:

    ./asmcli install \
      --project_id "PROJECT_ID" \
      --cluster_name "CLUSTER_NAME" \
      --cluster_location "CLUSTER_LOCATION" \
      --fleet_id FLEET_PROJECT_ID \
      --output_dir DIR_PATH \
      --enable_all \
      --option iap-operator
    
  5. 在工作負載上觸發自動 Sidecar Proxy 插入作業,即可完成升級。詳情請參閱「部署及重新部署工作負載」。

    升級完成後,請返回本指南並繼續下一個章節,設定與 IAP 的整合。

預留靜態 IP 位址及設定 DNS

如要整合 Identity-Aware Proxy 與 Cloud Service Mesh,請設定Google Cloud HTTP(S) 負載平衡器,這需要指向靜態 IP 位址的網域名稱。您可以預留靜態外部 IP 位址,進而將位址無期限地指派給專案,直到明確釋出該位址為止。

  1. 預留靜態外部 IP 位址:

    gcloud compute addresses create example-static-ip --global
    
  2. 取得靜態 IP 位址:

    gcloud compute addresses describe example-static-ip --global
    
  3. 在網域名稱註冊商中,使用靜態 IP 位址設定完整網域名稱 (FQDN)。一般來說,您會在 DNS 設定中新增 A 記錄。新增 FQDN 的 A 記錄時,設定步驟和術語會因網域名稱註冊商而異。

    DNS 設定最多需要 24 到 48 小時才會生效。您可以繼續按照本指南設定所有項目,但 DNS 設定傳播完成前,您無法測試設定。

部署範例應用程式

啟用 IAP 前,您需要先在 GKE 叢集上執行應用程式,以便驗證所有要求都有身分。本指南使用 Bookinfo 範例,說明如何設定 HTTP(S) 負載平衡器並啟用 IAP。

按照步驟部署 Bookinfo。在部署負載平衡器之前,您無法從 GKE 叢集外部 (例如瀏覽器) 存取 Bookinfo 應用程式。

外部要求

Bookinfo 的 Gateway 資源 (定義於 samples/bookinfo/networking/bookinfo-gateway.yaml) 使用預先設定的 istio-ingressgateway。回想一下,部署 Cloud Service Mesh 時,您指定了 NodePort,istio-ingressgateway會在服務網格上開啟特定通訊埠。雖然叢集中的節點有外部 IP 位址,但 Google Cloud 防火牆規則會封鎖來自叢集外部的要求。使用 IAP 時,將應用程式公開發布到網際網路的正確方式是使用負載平衡器。請勿使用防火牆規則公開節點位址,否則會略過 IAP。

如要將要求轉送至 Bookinfo,請在Google Cloud 專案中設定 HTTP(S) 負載平衡器。由於負載平衡器位於專案中,因此會受到防火牆保護,並可存取叢集中的節點。使用靜態 IP 位址和網域名稱設定負載平衡器後,您就可以將要求傳送至網域名稱,負載平衡器會將要求轉送至叢集中的節點。

啟用 IAP

下列步驟說明如何啟用 IAP。

  1. 使用 list 指令,確認你是否已有現有品牌。每個專案只能有一個品牌。

    gcloud iap oauth-brands list

    如果品牌存在,以下是 gcloud 回應範例:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    
  2. 如果沒有品牌,請使用 create 指令:

    gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_email=SUPPORT_EMAIL

    呼叫這個 API 時,必須提供上述欄位:

    • supportEmail:OAuth 同意畫面上顯示的支援電子郵件地址。 這個電子郵件地址可以是使用者的地址,也可以是 Google 群組別名。 服務帳戶也有電子郵件地址,但並非實際有效的電子郵件地址,因此無法用於建立品牌。不過,服務帳戶可以成為 Google 群組的擁有者。建立新的 Google 群組,或設定現有群組,並將所需服務帳戶設為群組擁有者。

    • applicationTitle:OAuth 同意畫面顯示的應用程式名稱。

    回應包含下列欄位:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    

建立 IAP OAuth 用戶端

  1. 使用 create 指令建立用戶端。使用上一個步驟的品牌 name。

    gcloud iap oauth-clients create projects/PROJECT_NUMBER/brands/BRAND-ID --display_name=NAME

    回應包含下列欄位:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_NAME]/identityAwareProxyClients/[CLIENT_ID]
    secret: [CLIENT_SECRET]
    displayName: [NAME]
    
  2. 使用用戶端 ID (上一步中的 CLIENT_ID) 和 CLIENT_SECRET 啟用 IAP。使用 OAuth 用戶端的資料建立 Kubernetes Secret:

    kubectl create secret generic -n istio-system my-secret --from-literal=client_id=CLIENT_ID \
    --from-literal=client_secret=CLIENT_SECRET

部署負載平衡器

您可以使用 Ingress 資源建立 HTTP(S) 負載平衡器,並自動設定 SSL 憑證。代管 SSL 憑證會為您的網域佈建、續約及管理。

  1. 建立 ManagedCertificate 資源。這項資源會指定 SSL 憑證的網域。spec.domains 清單只能包含一個網域。 系統不支援萬用字元網域。在下列 YAML 中,將 DOMAIN_NAME 替換成您為外部靜態 IP 位址設定的網域名稱。

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: example-certificate
      namespace: istio-system
    spec:
      domains:
        - DOMAIN_NAME
    EOF
  2. 建立 BackendConfig 資源。這項資源會指示 GCLB 如何對 Ingress Gateway 執行健康狀態檢查,以及如何設定 Identity-Aware Proxy。首先,從 Ingress Gateway 收集有關健康狀態檢查的幾個值:

    • 健康狀態檢查 ingress 通訊埠:這是 istio-ingress 的健康狀態檢查通訊埠。

      export HC_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')

    • 健康狀態檢查 ingress 路徑:這是 istio-ingress 的健康狀態檢查路徑。

      export HC_INGRESS_PATH=$(kubectl get pods -n istio-system -l app=istio-ingressgateway -o jsonpath='{.items[0].spec.containers[?(@.name=="istio-proxy")].readinessProbe.httpGet.path}')

    cat <<EOF | kubectl apply -n istio-system -f -
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: http-hc-config
    spec:
      healthCheck:
        checkIntervalSec: 2
        timeoutSec: 1
        healthyThreshold: 1
        unhealthyThreshold: 10
        port: ${HC_INGRESS_PORT}
        type: HTTP
        requestPath: ${HC_INGRESS_PATH}
      iap:
        enabled: true
        oauthclientCredentials:
          secretName: my-secret
    EOF
  3. 使用 BackendConfig 為 Ingress 服務加上註解。

        kubectl annotate -n istio-system service/istio-ingressgateway --overwrite \
          cloud.google.com/backend-config='{"default": "http-hc-config"}' \
          cloud.google.com/neg='{"ingress":false}'
    
  4. 定義 Ingress 資源,建立負載平衡器。

    • 將 networking.gke.io/managed-certificates 註解設為您在上一個步驟中建立的憑證名稱,example-certificate。

    • 將 kubernetes.io/ingress.global-static-ip-name 註解設為您預留的靜態 IP 位址名稱,example-static-ip。

    • 將 serviceName 設為 istio-ingressgateway,這會用於 Bookinfo 範例的 Gateway 資源。

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
      namespace: istio-system
      annotations:
        kubernetes.io/ingress.global-static-ip-name: example-static-ip
        networking.gke.io/managed-certificates: example-certificate
    spec:
      defaultBackend:
        service:
          name: istio-ingressgateway
          port:
            number: 80
    EOF
  5. 在 Google Cloud 控制台中,依序前往「Kubernetes Engine」 >「Services & Ingress」(服務與 Ingress) 頁面。

    前往「Services & Ingress」(Service 與 Ingress) 頁面

    「狀態」欄應會顯示「正在建立輸入」訊息。請等待 GKE 完全佈建 Ingress,再繼續操作。每隔幾分鐘重新整理頁面,即可查看 Ingress 的最新狀態。Ingress 佈建完成後,您可能會看到「Ok」狀態,或「All backend services are in UNHEALTHY state.」錯誤。GKE 佈建的資源之一是預設健康狀態檢查。如果看到錯誤訊息,表示 Ingress 已佈建,且預設健康狀態檢查已執行。看到「Ok」狀態或錯誤後,請繼續進行下一節,設定負載平衡器的健康狀態檢查。

設定 IAP 存取清單

將使用者新增至 IAP 的存取權政策:

gcloud beta iap web add-iam-policy-binding \
    --member=user:EMAIL_ADDRESS \
    --role=roles/iap.httpsResourceAccessor

其中 EMAIL_ADDRESS 是使用者的完整電子郵件地址,例如 alice@example.com。

  1. 測試負載平衡器。將瀏覽器指向:

    http://DOMAIN_NAME/productpage

    其中 DOMAIN_NAME 是您使用外部靜態 IP 位址設定的網域名稱。

    您應該會看到 Bookinfo 應用程式的 productpage。如果多次重新整理頁面,應該會看到不同版本的評論,以輪替方式呈現:紅色星星、黑色星星、沒有星星。

    您也應該測試 https 對 Bookinfo 的存取權。

在服務網格上啟用 RCToken 支援功能

根據預設,IAP 會產生 OAuth 用戶端範圍的 JSON 網頁符記 (JWT)。如果是 Cloud Service Mesh,您可以設定 IAP 來產生 RequestContextToken (RCToken),這是一種 JWT,但可設定目標對象。您可以將 JWT 的對象設定為任意字串,並在 Cloud Service Mesh 政策中使用,進行精細的授權作業。

如要設定 RCToken,請按照下列步驟操作:

  1. 為 RCToken 目標對象建立環境變數。可以是任何字串。

    export RCTOKEN_AUD="your-rctoken-aud"
    
  2. 選用:下列步驟需要使用 BACKEND_SERVICE_ID。如要找出 BACKEND_SERVICE_ID,請執行下列指令:

    kubectl -n istio-system get Ingress example-ingress -o json | jq \
     '.metadata.annotations."ingress.kubernetes.io/backends"'
    

    預期輸出內容類似於 "{\"BACKEND_SERVICE_ID\":\"HEALTHY\"}"。 例如:"ingress.kubernetes.io/backends": "{\"k8s-be-31224--51f3b55cd1457fb6\":\"HEALTHY\"}"。在本例中,BACKEND_SERVICE_ID 為 k8s-be-31224--51f3b55cd1457fb6。

  3. 擷取現有的 IAP 設定。

    gcloud iap settings get --format json \
    --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID > iapSettings.json
    
  4. 使用 RCToken 目標對象更新 IapSettings。

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR $RCTOKEN_AUD \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > updatedIapSettings.json
    
    gcloud iap settings set updatedIapSettings.json --format json \
    --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID
    
  5. 在 Istio Ingress 閘道上啟用 RCToken 驗證。

    cat <<EOF | kubectl apply -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "RequestAuthentication"
    metadata:
      name: "ingressgateway-jwt-policy"
      namespace: "istio-system"
    spec:
      selector:
        matchLabels:
          app: istio-ingressgateway
      jwtRules:
      - issuer: "https://cloud.google.com/iap"
        jwksUri: "https://www.gstatic.com/iap/verify/public_key-jwk"
        audiences:
        - $RCTOKEN_AUD
        fromHeaders:
        - name: ingress-authorization
          prefix: "Istio "
        outputPayloadToHeader: "verified-jwt"
        forwardOriginalToken: true
    EOF
    
  6. 選用:確保系統拒絕沒有有效 JWT 的要求:

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: iap-gateway-require-jwt
        namespace: istio-system
      spec:
        selector:
          matchLabels:
            app: istio-iap-ingressgateway
        action: DENY
        rules:
          - from:
              - source:
                  notRequestPrincipals: ["*"]
      EOF
      

  7. 確認對 Bookinfo productpage 的要求仍可成功:

    http://DOMAIN_NAME/productpage

如要測試政策,請按照下列步驟操作:

  1. 建立 IapSettings 要求物件,但將 rctokenAud 設為不同的字串:

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR wrong-rctoken-aud \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > wrongIapSettings.json
    
  2. 呼叫 IapSettings API 設定 RCtoken 目標對象。

    gcloud beta iap settings set wrongIapSettings.json --project=PROJECT_ID --resource-type=compute --service=BACKEND_SERVICE
  3. 向 Bookinfo productpage 提出要求,應該會失敗:

    http://DOMAIN_NAME/productpage

清除所用資源

完成本教學課程後,請移除下列資源,以免帳戶產生不必要的費用:

  1. 刪除受管理憑證:

    kubectl delete managedcertificates example-certificate
  2. 刪除 Ingress,這會取消分配負載平衡資源:

    kubectl -n istio-system delete ingress example-ingress

  3. 刪除靜態 IP 位址:

    gcloud compute addresses delete example-static-ip --global

    如果這麼做,請務必從網域註冊商刪除 IP 位址。

  4. 刪除叢集,這會刪除組成叢集的資源,例如運算執行個體、磁碟和網路資源:

    gcloud container clusters delete CLUSTER_NAME