整合 IAP 與 Cloud Service Mesh
本指南說明如何將 Identity-Aware Proxy (IAP) 與 Cloud Service Mesh 整合。透過 IAP 與 Cloud Service Mesh 整合,您就能根據 Google 的 BeyondCorp 原則安全存取服務。IAP 會驗證使用者身分和要求內容,判斷是否授予應用程式或資源的存取權。整合 IAP 與 Cloud Service Mesh 可為您帶來以下優點:
完整的情境感知存取權控管功能,可用於在 Cloud Service Mesh 上執行的工作負載。您可以根據原始要求的屬性 (例如使用者身分、IP 位址和裝置類型),設定精細的存取權政策。您可以根據要求網址的主機名稱和路徑,將存取權政策與限制條件結合。
在 Cloud Service Mesh 授權中啟用情境感知宣稱支援功能。
透過 Google Cloud 負載平衡器,提供可擴充、安全且可用性高的應用程式存取權。高效能負載平衡功能提供內建的分散式阻斷服務 (DDoS) 攻擊防護機制,並支援全球 anycast IP 位址。
事前準備
按照「安裝依附工具並驗證叢集」中的步驟操作:此外,本指南假設您已具備下列條件:
透過 Cloud Service Mesh 設定叢集
本節說明如何設定 IAP 整合功能,適用於安裝 Cloud Service Mesh 的新服務和升級服務。
新安裝
啟用
iap.googleapis.com
。在下列指令中,將PROJECT_ID
替換為您要安裝 Cloud Service Mesh 的專案:gcloud services enable \ --project=PROJECT_ID \ iap.googleapis.com
您要更新的叢集必須設定
--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
根據預設,
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
請按照「安裝預設功能和 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
,這會設定閘道,以便在服務網格上開啟特定埠。這樣一來,您就能設定負載平衡器,將傳送至網域名稱的流量轉送至這個通訊埠。如果您要安裝受管理的 Cloud Service Mesh,請完成下列步驟:
將修訂版本標籤新增至
istio-system
命名空間。下載 適用於 IAP 的 Istio 入口閘道服務規格,並將其命名為
iap_operator.yaml
。將輸入服務設為 NodePort 服務。詳情請參閱「從 IstioOperator 遷移」。
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,然後返回本指南完成整合。
啟用
iap.googleapis.com
。在下列指令中,將PROJECT_ID
替換為您要安裝 Cloud Service Mesh 的專案。gcloud services enable \ --project=PROJECT_ID \ iap.googleapis.com
您要更新的叢集必須設定
--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
如果您要更新現有的 HTTP Cloud Load Balancer,請執行以下指令碼,保留現有的 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}')
請按照「升級 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
在工作負載上觸發自動側邊代理程式注入作業,即可完成升級。詳情請參閱「部署及重新部署工作負載」。
升級完成後,請返回本指南,繼續閱讀下一節,設定與 IAP 的整合。
保留靜態 IP 位址及設定 DNS
如要將 Identity-Aware Proxy 與 Cloud Service Mesh 整合,您必須設定Google Cloud HTTP(S) 負載平衡器,而這需要一個指向靜態 IP 位址的網域名稱。您可以保留靜態外部 IP 位址,無限期將位址指派給專案,直到明確釋出為止。
預留靜態外部 IP 位址:
gcloud compute addresses create example-static-ip --global
取得靜態 IP 位址:
gcloud compute addresses describe example-static-ip --global
在網域名稱註冊商中,使用靜態 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 時,您為 istio-ingressgateway
指定了 NodePort
,這會在服務網狀結構中開啟特定連接埠。雖然叢集中的節點具有外部 IP 位址,但來自叢集外部的請求會遭到 Google Cloud 防火牆規則封鎖。使用 IAP 時,使用負載平衡器是將應用程式公開發布至網際網路的正確方法。請勿使用防火牆規則公開節點位址,否則會略過 IAP。
如要將要求轉送至 Bookinfo,請在Google Cloud 專案中設定 HTTP(S) 負載平衡器。負載平衡器位於專案中,因此位於防火牆內,可存取叢集中的節點。使用靜態 IP 位址和網域名稱設定負載平衡器後,您就可以將要求傳送至網域名稱,負載平衡器會將要求轉送至叢集中的節點。
啟用 IAP
下列步驟說明如何啟用 IAP。
設定同意畫面
使用list 指令,確認你是否已擁有品牌。每個專案只能有一個品牌。
gcloud iap oauth-brands list
如果品牌存在,以下是 gcloud 回應範例:
name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID] applicationTitle: [APPLICATION_TITLE] supportEmail: [SUPPORT_EMAIL] orgInternalOnly: true
如果沒有品牌,請使用建立指令:
gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_email=SUPPORT_EMAIL
supportEmail
:OAuth 同意畫面上顯示的支援電子郵件。這個電子郵件地址可以是使用者的地址,也可以是 Google 網路論壇別名。雖然服務帳戶也有電子郵件地址,但這些並非有效的電子郵件地址,因此無法用於建立品牌。不過,服務帳戶可以是 Google 群組的擁有者。建立新的 Google 群組,或設定現有群組,並將所需服務帳戶設為群組擁有者。applicationTitle
:在 OAuth 同意畫面上顯示的應用程式名稱。
回應包含下列欄位:
name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID] applicationTitle: [APPLICATION_TITLE] supportEmail: [SUPPORT_EMAIL] orgInternalOnly: true
建立 IAP OAuth 用戶端
使用 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]
使用用戶端 ID (上一個步驟中的
CLIENT_ID
) 和CLIENT_SECRET
啟用 IAP。使用 OAuth 用戶端的素材建立 Kubernetes 密鑰:kubectl create secret generic -n istio-system my-secret --from-literal=client_id=CLIENT_ID \ --from-literal=client_secret=CLIENT_SECRET
部署負載平衡器
您可以使用Ingress 資源建立具有自動設定 SSL 憑證的 HTTP(S) 負載平衡器。系統會針對您的網域佈建、更新及管理代管的 SSL 憑證。
建立 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
建立 BackendConfig 資源。這項資源會說明 GCLB 如何在 Ingress 閘道上執行健康檢查,以及如何設定 Identity-Aware Proxy。首先,從 Ingress Gateway 收集一些有關健康檢查的值:
健康狀態檢查入口通訊埠:這是 istio-ingress 的健康狀態檢查通訊埠。
export HC_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')
健康狀態檢查輸入路徑:這是 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
使用 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}'
定義 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
在 Google Cloud 控制台中,依序前往「Kubernetes Engine」 >「Services & Ingress」頁面。
前往「Service 與 Ingress」(Service 與 Ingress) 頁面
您應該會在「狀態」欄中看到「Creating ingress」訊息。請等待 GKE 完成 Ingress 佈建作業,再繼續操作。每隔幾分鐘重新整理頁面,即可取得最新的 Ingress 狀態。佈建 Ingress 後,您可能會看到「Ok」狀態,或是「所有後端服務皆處於不健康狀態」的錯誤訊息。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
。
測試負載平衡器。將瀏覽器指向:
http://DOMAIN_NAME/productpage
其中
DOMAIN_NAME
是您使用外部靜態 IP 位址設定的網域名稱。您應該會看到 Bookinfo 應用程式的
productpage
。請重新整理頁面幾次,你應該會看到不同版本的評論,以循環配置方式呈現 (紅色星號、黑色星號、無星號)。您也應測試
https
對 Bookinfo 的存取權。
在服務網格上啟用 RCToken 支援
根據預設,IAP 會產生範圍限定為 OAuth 用戶端的 JSON Web Token (JWT)。針對 Cloud Service Mesh,您可以設定 IAP 產生 RequestContextToken (RCToken),這是一個 JWT,但具有可設定的目標對象。您可以使用 RCToken 將 JWT 的對象設定為任意字串,並在 Cloud Service Mesh 政策中使用該字串,以便精細授權。
如何設定 RCToken:
為 RCToken 目標對象建立環境變數。這可以是任何字串。
export RCTOKEN_AUD="your-rctoken-aud"
選用:下列步驟需要使用
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
。擷取現有的 IAP 設定。
gcloud iap settings get --format json \ --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID > iapSettings.json
使用 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
在 Istio 入口閘道上啟用 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
選用:確保沒有有效 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
確認對 Bookinfo
productpage
的要求仍能成功:http://DOMAIN_NAME/productpage
如要測試政策,請按照下列步驟操作:
建立
IapSettings
要求物件,但將rctokenAud
設為其他字串:cat iapSettings.json | jq --arg RCTOKEN_AUD_STR wrong-rctoken-aud \ '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \ > wrongIapSettings.json
呼叫
IapSettings
API 以設定 RCtoken 目標對象。gcloud beta iap settings set wrongIapSettings.json --project=PROJECT_ID --resource-type=compute --service=BACKEND_SERVICE
向 Bookinfo
productpage
提出要求,應該會失敗:http://DOMAIN_NAME/productpage
正在清除所用資源
完成本教學課程後,請移除下列資源,以免您的帳戶產生不必要的費用:
刪除代管憑證:
kubectl delete managedcertificates example-certificate
刪除 Ingress,這會釋出負載平衡資源:
kubectl -n istio-system delete ingress example-ingress
刪除靜態 IP 位址:
gcloud compute addresses delete example-static-ip --global
如要這樣做,請務必從網域註冊商中刪除 IP 位址。
刪除叢集,這麼做會刪除組成叢集的資源,例如運算執行個體、磁碟和網路資源:
gcloud container clusters delete CLUSTER_NAME