本頁面說明如何在 Google Kubernetes Engine (GKE) 叢集中,為 Ingress 資源設定多個 SSL 憑證。
總覽
如果要接受來自用戶端的 HTTPS 要求,應用程式負載平衡器必須要有憑證,以向用戶端證明其身分。負載平衡器還必須要有私密金鑰才能完成 HTTPS 握手。
當負載平衡器接受來自用戶端的 HTTPS 要求時,用戶端和負載平衡器之間的流量將會使用 TLS 加密。不過負載平衡器會終止 TLS 加密,並將要求在不加密的情況下轉給應用程式。透過 Ingress 設定應用程式負載平衡器時,可以設定負載平衡器向用戶端顯示最多 10 個 TLS 憑證。
負載平衡器會使用伺服器名稱指示 (SNI),依據 TLS 握手中的網域名稱判斷要向客戶呈現哪些憑證。若用戶端不使用 SNI,或者用戶端使用的網域名稱與其中一個憑證的常用名稱 (CN) 名稱不符,負載平衡器就會使用 Ingress 中列出的第一個憑證。
下圖顯示負載平衡器如何根據要求中使用的網域名稱,將流量傳送至不同後端:
您可以透過下列方法,為應用程式負載平衡器提供 SSL 憑證:
Google 代管的 SSL 憑證。 如需相關操作方式,請參閱代管憑證頁面。
Google Cloud 您自行管理的 SSL 憑證。SSL 憑證會使用您上傳到 Google Cloud 專案的預先共用憑證。
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,將流量轉送到最接近使用者所在地區的叢集。