本頁面說明如何在 Google Kubernetes Engine (GKE) 叢集中,為 Ingress 資源設定多個 SSL 憑證。
總覽
如果要接受來自用戶端的 HTTPS 要求,應用程式負載平衡器必須要有憑證,以向用戶端證明其身分。負載平衡器還必須要有私密金鑰才能完成 HTTPS 握手。
當負載平衡器接受來自用戶端的 HTTPS 要求時,用戶端和負載平衡器之間的流量將會使用 TLS 加密。不過負載平衡器會終止 TLS 加密,並將要求在不加密的情況下轉給應用程式。透過 Ingress 設定應用程式負載平衡器時,可以設定負載平衡器向用戶端顯示最多 10 個 TLS 憑證。
負載平衡器會使用伺服器名稱指示 (SNI),依據 TLS 握手中的網域名稱判斷要向客戶呈現哪些憑證。若用戶端不使用 SNI,或者用戶端使用的網域名稱與其中一個憑證的常用名稱 (CN) 名稱不符,負載平衡器就會使用 Ingress 中列出的第一個憑證。
下圖顯示負載平衡器如何根據要求中使用的網域名稱,將流量傳送至不同後端:
您可以透過下列方法,為應用程式負載平衡器提供 SSL 憑證:
Google 代管的 SSL 憑證。 如需相關操作方式,請參閱代管憑證頁面。
Trusted Cloud by S3NS 您自行管理的 SSL 憑證。SSL 憑證會使用您上傳到 Trusted Cloud by S3NS 專案的預先共用憑證。
Kubernetes 密鑰。 密鑰包含您自行建立的憑證和金鑰。將 Secret 名稱新增至 Ingress 資訊清單的
tls
欄位。
您可以在同一個 Ingress 中使用多個方法,如此一來,在方法間進行遷移時就不會出現停機時間。
縱觀全局
以下概要說明本文中的步驟:
建立 Deployment。
建立 Service。
建立兩個憑證檔案和兩個金鑰檔案,或兩個
ManagedCertificate
物件。您必須在與負載平衡器部署位置相同的專案和命名空間中,設定這些憑證。建立使用密鑰或預先共用憑證的 Ingress。 建立 Ingress 時,GKE 會建立並設定應用程式負載平衡器。
測試應用程式負載平衡器。
事前準備
開始之前,請確認你已完成下列工作:
- 啟用 Google Kubernetes Engine API。 啟用 Google Kubernetes Engine API
- 如要使用 Google Cloud CLI 執行這項工作,請安裝並初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行
gcloud components update
,取得最新版本。
- 您必須擁有兩個網域名稱。網域名稱的長度不得超過 63 個字元。
限制
Google 代管憑證僅適用於使用外部應用程式負載平衡器的 GKE Ingress。Google 代管憑證不支援第三方 Ingress 控制器。
如果是內部應用程式負載平衡器,您必須在 Ingress 資訊清單中停用 HTTP。外部負載平衡器則不必執行這項操作。
您不得手動變更或更新應用程式負載平衡器的設定。也就是說,您不得編輯任何負載平衡器的元件,包括目標 proxy、網址對應和後端服務。您所做的任何變更都將被 GKE 覆寫。
可建立部署作業
將下列資訊清單儲存為
my-mc-deployment.yaml
:apiVersion: apps/v1 kind: Deployment metadata: name: my-mc-deployment spec: selector: matchLabels: app: products department: sales replicas: 3 template: metadata: labels: app: products department: sales spec: containers: - name: hello image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0" env: - name: "PORT" value: "50001" - name: hello-again image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0" env: - name: "PORT" value: "50002"
這個資訊清單說明含有三個 Pod 的部署。每個 Pod 都有兩個容器。其中一個容器會執行
hello-app:1.0
並監聽 TCP 通訊埠 50001。另一個容器會執行hello-app:2.0
並監聽 TCP 通訊埠 50002。將資訊清單套用至叢集:
kubectl apply -f my-mc-deployment.yaml
建立 Service
將下列資訊清單儲存為
my-mc-service.yaml
:apiVersion: v1 kind: Service metadata: name: my-mc-service spec: type: NodePort selector: app: products department: sales ports: - name: my-first-port protocol: TCP port: 60001 targetPort: 50001 - name: my-second-port protocol: TCP port: 60002 targetPort: 50002
這份資訊清單說明瞭具有下列欄位的 Service:
selector
:指定同時具有app: products
標籤和department: sales
標籤的任何 Pod,都是這個 Service 的成員。ports
:指定當用戶端將要求傳送至my-first-port
上的 Service 時,GKE 會將要求轉送至通訊埠 50001 上的其中一個成員 Pod。當用戶端傳送要求到my-second-port
上的 Service 時,GKE 會將要求轉送到通訊埠 50002 上的其中一個成員 Pod。
將資訊清單套用至叢集:
kubectl apply -f my-mc-service.yaml
建立憑證和金鑰
若要進行此頁面的練習,您要有兩個憑證,每個憑證都有對應的金鑰。每一個憑證都必須有一個與您所擁有的網域相等的共用名稱 (CN)。
您可以手動建立這些憑證,也可以使用 Google 代管的憑證。
若您已有具備適當的「共用名稱」值的兩個憑證檔案,可直接前往下一節。
使用者管理的憑證
建立第一個金鑰:
openssl genrsa -out test-ingress-1.key 2048
建立第一個憑證簽署要求:
openssl req -new -key test-ingress-1.key -out test-ingress-1.csr \ -subj "/CN=FIRST_DOMAIN"
將
FIRST_DOMAIN
替換為您擁有的網域名稱,例如example.com
。建立第一個憑證:
openssl x509 -req -days 365 -in test-ingress-1.csr -signkey test-ingress-1.key \ -out test-ingress-1.crt
建立第二個金鑰:
openssl genrsa -out test-ingress-2.key 2048
建立第二個憑證簽署要求:
openssl req -new -key test-ingress-2.key -out test-ingress-2.csr \ -subj "/CN=SECOND_DOMAIN"
將
SECOND_DOMAIN
替換為您擁有的其他網域名稱,例如examplepetstore.com
。建立第二個憑證:
openssl x509 -req -days 365 -in test-ingress-2.csr -signkey test-ingress-2.key \ -out test-ingress-2.crt
如要進一步瞭解憑證和金鑰,請參閱「安全資料傳輸層 (SSL) 憑證總覽」。
您現在有兩個憑證檔案和兩個金鑰檔案。
其餘工作會使用下列預留位置來參照您的網域、憑證和金鑰:
FIRST_CERT_FILE
:第一個憑證檔案的路徑。FIRST_KEY_FILE
:與第一個憑證搭配使用的金鑰檔案路徑。FIRST_DOMAIN
:您擁有的網域名稱。FIRST_SECRET_NAME
:包含第一個憑證和金鑰的 Secret 名稱。SECOND_CERT_FILE
:第二個憑證檔案的路徑。SECOND_KEY_FILE
:與第二個憑證搭配使用的金鑰檔案路徑。SECOND_DOMAIN
:您擁有的第二個網域名稱。SECOND_SECRET_NAME
:包含第二個憑證和金鑰的 Secret 名稱。
Google 代管的憑證
如要建立 Google 代管的憑證,您必須將 ManagedCertificate
物件新增至 Ingress 的命名空間。您可以使用下列範本,為網域定義憑證:
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: FIRST_CERT_NAME
spec:
domains:
- FIRST_DOMAIN
---
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: SECOND_CERT_NAME
spec:
domains:
- SECOND_DOMAIN
更改下列內容:
FIRST_CERT_NAME
:第一個ManagedCertificate
物件的名稱。FIRST_DOMAIN
:您擁有的第一個網域。SECOND_CERT_NAME
:第二個ManagedCertificate
物件的名稱。SECOND_DOMAIN
:您擁有的第二個網域。
ManagedCertificate
物件的名稱與實際建立的憑證名稱不同。您只需要知道 ManagedCertificate
物件的名稱,即可在 Ingress 中使用這些物件。
指定 Ingress 的憑證
下一個步驟是建立 Ingress 物件。在您的 Ingress 資訊清單中,可以使用下列其中一種方法來提供負載平衡器的憑證:
- 密鑰
- 預先共用的憑證
- Google 代管憑證
密鑰
建立包含第一個憑證和金鑰的「密鑰」:
kubectl create secret tls FIRST_SECRET_NAME \ --cert=FIRST_CERT_FILE \ --key=FIRST_KEY_FILE
建立包含第二個憑證和金鑰的「密鑰」:
kubectl create secret tls SECOND_SECRET_NAME \ --cert=SECOND_CERT_FILE \ --key=SECOND_KEY_FILE
建立 Ingress
將下列資訊清單儲存為
my-mc-ingress.yaml
:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-mc-ingress spec: tls: - secretName: FIRST_SECRET_NAME - secretName: SECOND_SECRET_NAME rules: - host: FIRST_DOMAIN http: paths: - pathType: ImplementationSpecific backend: service: name: my-mc-service port: number: 60001 - host: SECOND_DOMAIN http: paths: - pathType: ImplementationSpecific backend: service: name: my-mc-service port: number: 60002
將
FIRST_DOMAIN
和SECOND_DOMAIN
替換為您擁有的網域名稱,例如example.com
和examplepetstore.com
。將資訊清單套用至叢集:
kubectl apply -f my-mc-ingress.yaml
說明您的 Ingress:
kubectl describe ingress my-mc-ingress
輸出結果會與下列內容相似:
Name: my-mc-ingress Address: 203.0.113.1 ... TLS: FIRST_SECRET_NAME terminates SECOND_SECRET_NAME terminates Rules: Host Path Backends ---- ---- -------- FIRST_DOMAIN my-mc-service:my-first-port (<none>) SECOND_DOMAIN my-mc-service:my-second-port (<none>) Annotations: ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 3m loadbalancer-controller default/my-mc-ingress Normal CREATE 2m loadbalancer-controller ip: 203.0.113.1
此結果顯示有兩個密鑰與 Ingress 關聯。輸出也會顯示負載平衡器的外部 IP 位址。如果未設定外部 IP 位址,請稍候幾分鐘,然後再次嘗試執行指令。
Pre-shared certs (預先共用的憑證)
建立憑證:
gcloud compute ssl-certificates create FIRST_CERT_NAME \ --certificate=FIRST_CERT_FILE \ --private-key=FIRST_KEY_FILE
更改下列內容:
FIRST_CERT_NAME
:第一個憑證的名稱。FIRST_CERT_FILE
:您的第一個憑證檔案。FIRST_KEY_FILE
:您的第一個金鑰檔案。
建立第二個憑證:
gcloud compute ssl-certificates create SECOND_CERT_NAME \ --certificate=SECOND_CERT_FILE \ --private-key=SECOND_KEY_FILE
更改下列內容:
SECOND_CERT_NAME
:第二個憑證的名稱。SECOND_CERT_FILE
:第二個憑證檔案。SECOND_KEY_FILE
:第二個金鑰檔案。
查看您的憑證資源:
gcloud compute ssl-certificates list
輸出結果會與下列內容相似:
NAME CREATION_TIMESTAMP FIRST_CERT_NAME 2018-11-03T12:08:47.751-07:00 SECOND_CERT_NAME 2018-11-03T12:09:25.359-07:00
建立 Ingress
將下列資訊清單儲存為
my-psc-ingress.yaml
:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-psc-ingress annotations: ingress.gcp.kubernetes.io/pre-shared-cert: "FIRST_CERT_NAME,SECOND_CERT_NAME" spec: rules: - host: FIRST_DOMAIN http: paths: - pathType: ImplementationSpecific backend: service: name: my-mc-service port: number: 60001 - host: SECOND_DOMAIN http: paths: - pathType: ImplementationSpecific backend: service: name: my-mc-service port: number: 60002
將
FIRST_DOMAIN
和SECOND_DOMAIN
替換成您的網域名稱。這份資訊清單說明 Ingress,在註解中列出預先共用的憑證資源。
將資訊清單套用至叢集:
kubectl apply -f my-psc-ingress.yaml
說明您的 Ingress:
kubectl describe ingress my-psc-ingress
輸出結果會與下列內容相似:
Name: my-psc-ingress Address: 203.0.113.2 ... Rules: Host Path Backends ---- ---- -------- FIRST_DOMAIN my-mc-service:my-first-port (<none>) SECOND_DOMAIN my-mc-service:my-second-port (<none>) Annotations: ... ingress.gcp.kubernetes.io/pre-shared-cert: FIRST_CERT_NAME,SECOND_CERT_NAME ... ingress.kubernetes.io/ssl-cert: FIRST_CERT_NAME,SECOND_CERT_NAME Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 2m loadbalancer-controller default/my-psc-ingress Normal CREATE 1m loadbalancer-controller ip: 203.0.113.2
從此結果顯示 Ingress 與名為
FIRST_CERT_NAME
和SECOND_CERT_NAME
的預先共用憑證有關聯。輸出也會顯示負載平衡器的外部 IP 位址。如果未設定外部 IP 位址,請稍候幾分鐘,然後再次嘗試執行指令。
Google 代管的憑證
建立 Ingress
將下列資訊清單儲存為
my-gmc-ingress.yaml
:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-gmc-ingress annotations: networking.gke.io/managed-certificates: "FIRST_CERT_NAME,SECOND_CERT_NAME" spec: rules: - host: FIRST_DOMAIN http: paths: - pathType: ImplementationSpecific backend: service: name: my-mc-service port: number: 60001 - host: SECOND_DOMAIN http: paths: - pathType: ImplementationSpecific backend: service: name: my-mc-service port: number: 60002
將
FIRST_DOMAIN
和SECOND_DOMAIN
替換成您的網域名稱。這份資訊清單說明 Ingress,在註解中列出預先共用的憑證資源。
將資訊清單套用至叢集:
kubectl apply -f my-gmc-ingress.yaml
說明您的 Ingress:
kubectl describe ingress my-gmc-ingress
輸出結果會與下列內容相似:
Name: my-gmc-ingress Address: 203.0.113.2 ... Rules: Host Path Backends ---- ---- -------- FIRST_DOMAIN my-mc-service:my-first-port (<none>) SECOND_DOMAIN my-mc-service:my-second-port (<none>) Annotations: ... ingress.gcp.kubernetes.io/pre-shared-cert: mcrt-a6e41ce4-2b39-4334-84ce-867ff543c424,mcrt-bbff4116-f014-4800-a43a-4095bffeb4f4 ... ingress.kubernetes.io/ssl-cert: mcrt-a6e41ce4-2b39-4334-84ce-867ff543c424,mcrt-bbff4116-f014-4800-a43a-4095bffeb4f4 networking.gke.io/managed-certificates: FIRST_CERT_NAME,SECOND_CERT_NAME Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 2m loadbalancer-controller default/my-gmc-ingress Normal CREATE 1m loadbalancer-controller ip: 203.0.113.2
從此結果顯示 Ingress 與名為
FIRST_CERT_NAME
和SECOND_CERT_NAME
的代管憑證有關聯。GKE 會自動使用您透過ManagedCertificate
物件建立的 Google 代管憑證,填入ingress.gcp.kubernetes.io/pre-shared-cert
和ingress.kubernetes.io/ssl-cert
註解。輸出也會顯示負載平衡器的外部 IP 位址。如果未設定外部 IP 位址,請稍候片刻,然後再次嘗試執行指令。
測試負載平衡器
請稍候五分鐘,等待 GKE 設定負載平衡器完成。
如果您使用 Google 代管的憑證,系統需要佈建憑證並驗證指定網域的 DNS 設定,因此完成設定的時間可能會大幅延長。
如要測試負載平衡器,您必須擁有兩個網域名稱,且這兩個網域名稱必須解析外部應用程式負載平衡器的外部 IP 位址。
使用您的第一個網域名稱傳送要求至負載平衡器:
curl -v https://FIRST_DOMAIN
您可能需要使用
curl -k
選項執行不安全的 SSL 傳輸,這樣curl
才會接受自行簽署的憑證。輸出結果會與下列內容相似:
... * Trying 203.0.113.1... ... * Connected to FIRST_DOMAIN (203.0.113.1) port 443 (#0) ... * TLSv1.2 (IN), TLS handshake, Certificate (11): ... * Server certificate: * subject: CN=FIRST_DOMAIN ... > Host: FIRST_DOMAIN.com ... Hello, world! Version: 1.0.0 ...
結果顯示在 TLS 握手使用您的第一個憑證。
使用第二個網域名稱,將要求傳送至負載平衡器。
curl -v https://SECOND_DOMAIN
輸出結果會與下列內容相似:
... * Trying 203.0.113.1... ... * Connected to SECOND_DOMAIN (203.0.113.1) port 443 (#0) ... * Server certificate: * subject: CN=SECOND_DOMAIN ... > Host: SECOND_DOMAIN ... Hello, world! Version: 2.0.0
結果顯示在 TLS 握手使用您的第二個憑證。
Ingress 物件的主機欄位。
IngressSpec 的 tls
欄位是 IngressTLS 物件的陣列。每個 IngressTLS
物件都有 hosts
欄位和 SecretName
欄位。
GKE 中不使用 hosts
欄位。GKE 會從密鑰中的憑證讀取共用名稱 (CN)。若共用名稱符合用戶端要求中的網域名稱,負載平衡器便會對用戶端提供相符的憑證。
提供的憑證有哪些?
負載平衡器會根據下列這些規則選擇憑證:
若密鑰和預先共用的憑證都列於 Ingress 中,預先共用的憑證會優先於密鑰。換句話說,系統仍會納入密鑰,但會優先顯示預先共用的憑證。
若憑證的共用名稱 (CN) 都不符合服務用戶端要求中的網域名稱,負載平衡器便會向用戶端提供主要憑證。
針對
tls
區塊中列出的密鑰,主要憑證是清單中的第一個密鑰。針對註解中列出的預先共用憑證,主要憑證為清單中的第一個憑證。
憑證輪替最佳做法
如要輪替 Secret 或預先共用憑證的內容,請參考下列最佳做法:
- 建立含有新憑證資料的新密鑰或預先共用憑證,並使用不同名稱。按照先前提供的操作說明,將這個資源 (連同現有資源) 附加至 Ingress。確認變更沒有問題後,即可從 Ingress 移除舊憑證。
- 如果不在意流量中斷,可以從 Ingress 移除舊資源,以相同名稱但不同內容佈建新資源,然後重新附加至 Ingress。
如要避免自行管理憑證輪替,請參閱「使用 Google 代管的 SSL 憑證」。
疑難排解
指定無效或不存在的密鑰會導致 Kubernetes 事件錯誤。 您可以查看 Ingress 的 Kubernetes 事件,如下:
kubectl describe ingress
輸出結果會與下列內容相似:
Name: my-ingress
Namespace: default
Address: 203.0.113.3
Default backend: hello-server:8080 (10.8.0.3:8080)
TLS:
my-faulty-Secret terminates
Rules:
Host Path Backends
---- ---- --------
* * my-service:443 (10.8.0.3:443)
Events:
Error during sync: cannot get certs for Ingress default/my-ingress:
Secret "my-faulty-ingress" has no 'tls.crt'
後續步驟
閱讀 GKE 網路總覽。
瞭解如何使用靜態 IP 位址設定網域名稱。
如果您的應用程式在不同地區的多個 GKE 叢集上執行,請設定多叢集 Ingress,將流量轉送到最接近使用者所在地區的叢集。