如何在 GCP 建立萬用憑證 & 搭配 GKE 使用

Abstract/摘要

先前收到多個客戶的需求,想要在 GCP 上使用萬用憑證,但在 GCP Certificate Manager 問世之前,搭配 GCLB 的 Google-managed SSL certificates 只支援 SAN (多網域名稱憑證)而不支援萬用憑證,但現在使用 Global external Application Load Balancer, Classic Application Load Balancer, Global external proxy Network Load Balancer & Cross-region internal Application Load Balancer 這四種 GCLB 搭配 DNS 驗證就能透過 Certificate Manager 建立 WildCard certificates 並自動續訂,Certificate Manager 甚至支援每個負載平衡器部署最多一百萬個憑證,對於 GCP 使用者無疑是一大福音,本篇文章將會介紹如何使用 GCP Certificate Manager 建立萬用憑證,並且搭配 GKE Gateway 來保護您的應用程式流量。

環境/服務介紹

GCP Certificate Manager

Certificate Manager entities
icon/enlarge

Certificate Manager 包含以下元件[1]:

  • Certificates:預設情況下,憑證代表為特定網域名稱或網域通配符所頒發的單一 X.509 傳輸層安全性 (TLS) (SSL) 憑證,支援 Google Cloud 為您取得和管理的憑證或是您自行取得、設定和續約的憑證
  • Certificate maps:Certificate maps 參照一個或多個將特定憑證指派給特定主機名稱的 Certificate map entries。Certificate map entries 也定義負載平衡器在建立用戶端連線時所遵循的選擇邏輯。您可以將 Certificate maps 與多個 target proxies 相關聯,以便在多個負載平衡器之間重複使用。
  • Certificate map entries:Certificate map entries 是為特定網域提供服務的憑證清單,當用戶端連接到網域時,負載平衡器會協商在握手期間提供給用戶端的憑證類型。
  • Domain authorizations:以前的負載平衡器驗證方式需要您到DNS 將 Domain 指向到 GCLB 的 IP 才會簽署憑證,新的 Domain authorizations 支援使用 CNAME record 驗證, 讓您能在網路流量切換前就準備好憑證。

GKE Gateway

Gateway API overview
icon/enlarge

Gateway API 包含以下資源類型:

  • GatewayClass:定義叢集範圍的資源,它是在叢集中建立負載平衡器的範本。GKE 提供了一個可在 GKE 叢集中使用的 GatewayClass。
  • Gateway:定義負載平衡器偵聽流量的位置和方式。叢集營運商基於 GatewayClass 在其叢集中建立 Gateway。GKE 建立負載平衡器來實現 Gateway 資源中定義的配置。
  • HTTPRoute:定義特定於協定的規則,用於將請求從 Gateway 路由到 Kubernetes 服務。GKE 支援 HTTPRoutes 進行基於 HTTP(S) 的流量路由。
  • Policy:定義 Gateway 資源的一組特定實現的特徵。您可以將政策附加到網關、路由或 Kubernetes 服務

GKE Gateway with Certificate Manager 範例[2]

GKE Gateway with Certificate Manager 範例
icon/enlarge

The routing rules process HTTP traffic as follows:

  • Traffic to store.example.com/de routes to Service store-german.
  • Traffic to store.example.com with the HTTP header "env: canary" routes to Service store-v2.
  • The remaining traffic to store.example.com routes to Service store-v1.

Steps/步驟說明

使用 GCP Certificate Manager 建立 WildCard 憑證[3]

建立DNS授權

如果您要為萬用憑證建立 DNS 授權,例如 *.myorg.example.com,請設定父網域(例如myorg.example.com)的 DNS 授權,本篇文章預計建立 *.robbyhsieh.xyz 的萬用憑證,因此domain 指定父網域 robbyhsieh.xyz,並創建名稱為 test-wild-card的 dns-authorizations

1gcloud certificate-manager dns-authorizations create test-wild-card \ 2 --domain="robbyhsieh.xyz"
1gcloud certificate-manager dns-authorizations describe test-wild-card

該命令傳回類似於以下內容的輸出。使用輸出中的 CNAME 記錄新增到您的 DNS 配置中。

該命令傳回類似於以下內容的輸出。使用輸出中的 CNAME 記錄新增到您的 DNS 配置中。
icon/enlarge

將 CNAME 記錄新增至您的 DNS 配置中

如果您使用 Google Cloud 管理 DNS,請完成本部分的步驟。否則,請參閱第三方 DNS 解決方案的文件。

在完成本部分中的步驟之前,請確保您已建立公共 DNS 區域

  1. 啟動 DNS 記錄交易
1gcloud dns record-sets transaction start --zone="robby-wp"

將 robby-wp 替換為您的 Cloud DNS Zone 的名稱。

2. 將 CNAME 記錄新增至目標 DNS 區域:

1gcloud dns record-sets transaction add cf050101-8a8d-41af-ad1d-5b3fe5f5dbb4.7.authorize.certificatemanager.goog. \ 2 --name="_acme-challenge.robbyhsieh.xyz." \ 3 --ttl="30" \ 4 --type="CNAME" \ 5 --zone="robby-wp"

替換以上內容:

  • CNAME_RECORD:建立對應 DNS 授權的 Google Cloud CLI 指令傳回的 CNAME 記錄的完整資料值,此處使用上上一個步驟傳回的 data 值: cf050101-8a8d-41af-ad1d-5b3fe5f5dbb4.7.authorize.certificatemanager.goog.,最後的點也需要複製。
  • DOMAIN_NAME:目標域的名稱。域名必須是完全限定域名,例如myorg.example.com. 您還必須在目標網域後面包含尾隨句點,此處使用上上一個步驟傳回的 name 值: "_acme-challenge.robbyhsieh.xyz."
  • DNS_ZONE_NAME:將 "robby-wp" 替換為您的 Cloud DNS Zone 的名稱

3. 執行 DNS 記錄交易以儲存變更

1gcloud dns record-sets transaction execute --zone="robby-wp"

建立引用 DNS 授權的 Google 管理的證書

  1. 對於 Global external Application Load Balancer、Classic Application Load Balancer, 或 Global external proxy Network Load Balancer 運行以下指令:
1gcloud certificate-manager certificates create robby-wild-card \ 2 --domains=*.robbyhsieh.xyz --dns-authorizations=test-wild-card

替換以上內容:

  • CERTIFICATE_NAME:設定 certificate-manager 證書的唯一名稱,此處使用 robby-wild-card。
  • DOMAIN_NAME:證書的目標網域。前綴 *.表示通配符憑證。域名必須是完全限定域名,例如 myorg.example.com,此處使用 *.robbyhsieh.xyz
  • AUTHORIZATION_NAME:您在一開始的步驟中為此憑證所建立的 DNS 授權的名稱,此處使用 test-wild-card。

2. 檢查憑證

1gcloud certificate-manager certificates list

結果如下圖

結果如圖
icon/enlarge

將憑證部署到負載平衡器

使用證書映射部署證書

1. 建立 certificate map 以參照 certificate map entry 來關聯您的憑證:

1gcloud certificate-manager maps create wild-card-mapping

2. 建立 certificate map entry 並將其與您的憑證以及 certificate map 關聯起來

1gcloud certificate-manager maps entries create cert-mapping-entry \ 2 --map="wild-card-mapping" \ 3 --certificates="robby-wild-card" \ 4 --hostname="*.robbyhsieh.xyz"

替換以上內容:

  • CERTIFICATE_MAP_ENTRY_NAME: 設置 certificate map entry 的名稱,此處使用 cert-mapping-entry 
  • CERTIFICATE_MAP_NAME: 要與此 certificate map entry 關聯的 certificate map 名稱,此處使用上一步驟創建的 "wild-card-mapping"
  • CERTIFICATE_NAME: 要與此 certificate map entry 關聯的憑證名稱,此處使用先前建立的憑證 "robby-wild-card"
  • HOSTNAME: 要與此 certificate map entry 關聯的域名,此處使用"*.robbyhsieh.xyz"

3. 驗證 certificate map entry 狀態是否 Active

1gcloud certificate-manager maps entries describe cert-mapping-entry \ 2 --map="wild-card-mapping"

範例如下

驗證 certificate map entry 狀態是否 Active 範例
icon/enlarge

4. 若是要關聯 GKE Gateway 請跳過此步驟此步驟適用於非 GKE 且原先就有 GCLB ,並且想將萬用憑證套用於 GCLB 的讀者

將 certificate map 關聯至 target proxy,修改下方指令為您的 target proxy 名稱與certificate-map 名稱

1gcloud compute target-https-proxies update robby-wp-https-lb-target-proxy \ 2 --certificate-map="wild-card-mapping"

您可以從 GCLB 的頁面點選 load balancing components view 來查看您的 target proxy 名稱

您可以從 GCLB 的頁面點選 load balancing components view 來查看您的 target proxy 名稱
icon/enlarge

關聯成功後可以看到  target proxy 中顯示 Certificate map

關聯成功後可以看到 target proxy 中顯示 Certificate map
icon/enlarge

建立 GKE Gateway with Certificate Manager[4]

啟用 Gateway API

如需在現有 VPC 原生 GKE 叢集上啟用 Gateway API,請使用下列命令:

1 gcloud container clusters update CLUSTER_NAME \ 2 --gateway-api=standard \ 3 --location=CLUSTER_LOCATION

建立 GKE Gateway

將以下內容儲存到名為 gateway.yaml的檔案中:

1kind: Gateway 2apiVersion: gateway.networking.k8s.io/v1beta1 3metadata: 4 name: external-http 5 annotations: 6 networking.gke.io/certmap: wild-card-mapping 7spec: 8 gatewayClassName: gke-l7-global-external-managed 9 listeners: 10 - name: https 11 protocol: HTTPS 12 port: 443

此內容描述了具有以下欄位的 Gateway:

  • gatewayClassName: gke-l7-global-external-managed:指定此網關的GatewayClass。此網關類別使用全球外部應用負載平衡器。
  • protocol: HTTPS 和 port: 443:指定網關為 HTTPS 流量開放埠 443。這些欄位會啟用 TLS。
  • networking.gke.io/certmap: wild-card-mapping:在此處修改指定您 Certificate Manager 中 certificate map 的名稱。

將該檔案套用到您的叢集:

1kubectl apply -f gateway.yaml

GKE 可能需要幾分鐘時間來部署資源。

驗證網關已成功部署:

1kubectl describe gateway

輸出類似以下內容:

1Name: external-http 2Namespace: default 3Labels: <none> 4... 5Spec: 6 Gateway Class Name: gke-l7-global-external-managed 7 Listeners: 8 Allowed Routes: 9 Namespaces: 10 From: Same 11 Name: https 12 Port: 443 13 Protocol: HTTPS

在下一部分中,您將部署路由,以指示 Gateway 將流量傳送到後端。

使用 Console 部署演示應用

  1. 進入 GKE Console 點選 Workloads -> DEPLOY
進入 GKE Console 點選 Workloads -> DEPLOY
icon/enlarge

2. 使用預設 nginx container image 即可,點選 CONTINUE

使用預設 nginx container image 即可,點選 CONTINUE
icon/enlarge

3. 選擇您的 Cluster

選擇您的 Cluster
icon/enlarge

4. 選擇 Expose,設定 Port 為 80,Service Type 使用 Cluster IP

選擇 Expose,設定 Port 為 80,Service Type 使用 Cluster IP
icon/enlarge

建立HTTPRoute

將以下內容儲存到名為 route-external.yaml 的檔案中:

1kind: HTTPRoute 2apiVersion: gateway.networking.k8s.io/v1beta1 3metadata: 4 name: store-external 5spec: 6 parentRefs: 7 - kind: Gateway 8 name: external-http 9 hostnames: 10 - "gateway.robbyhsieh.xyz" 11 rules: 12 - backendRefs: 13 - name: nginx-1-service 14 port: 80

將此檔案套用到您的叢集:

1kubectl apply -f route-external.yaml

取得 Gateway 的 IP 位址:

1kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}"

輸出為一個IP 位址。

設置 DNS 指向

到 DNS 新增一筆 A Record,將您的 Domain 指向上一步驟之 GCLB IP

到 DNS 新增一筆 A Record,將您的 Domain 指向上一步驟之 GCLB IP
icon/enlarge

驗證

驗證部署是否成功

使用無痕測試連線

使用無痕測試連線
icon/enlarge

確認憑證是否為 Certificate manager 之萬用憑證

確認憑證是否為 Certificate manager 之萬用憑證
icon/enlarge
Certificate manager
icon/enlarge

Summary/總結

本篇文章以 GCP Certificate Manager 實作了萬用憑證的創建並整合進 GKE Gateway,讓您能保護您的應用程式流量,也許有人會好奇怎麼不用 Ingress,原因是目前 GKE Ingress 暫不支援 GCP Certificate manager[5],另外有個限制需要特別提醒大家,目前 GKE Gateway 有支援 Cloud Armor,但還不支援 Cloud CDN,因此使用上要依需求進行考量,我們可以期待 Google 盡快將 Cloud CDN 整合進 GKE Gateway 或將 GCP Certificate Manager 整合進 GKE Ingress 以解決上述限制;若是喜歡開源的解決方案,目前您也能使用 Cert-Manager 取得 Let's Encrypt 簽署的憑證搭配 GKE Ingress 使用,可參考 cert-manager[6]與第三方[7]的教學。

參考資料

[1] https://cloud.google.com/certificate-manager/docs/how-it-works

[2] https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-gateways#deploy_a_global_external_gateway 

[3] https://cloud.google.com/certificate-manager/docs/deploy-google-managed-dns-auth 

[4] https://cloud.google.com/kubernetes-engine/docs/how-to/secure-gateway 

[5] https://cloud.google.com/kubernetes-engine/docs/concepts/ingress#options_for_providing_ssl_certificates  

[6] https://cert-manager.io/docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl// 

[7] https://medium.com/contino-engineering/how-to-automatic-ssl-certificate-management-for-your-kubernetes-application-deployment-94b64dfc9114

撰文者:Robby Hsieh, Solution Architect

10 x Google Cloud 認證,7 x AWS 認證,專注於雲原生產業。擅長分析客戶需求並進行技術評估,以提供最適合的雲端解決方案

訂閱 CloudMile 電子報

所有 CloudMile 最新消息、產品動態、活動資訊和特別優惠,立即掌握。