使用 Ingress 在 HTTP(S) 負載平衡中使用多個 SSL 憑證

總覽

HTTP(S) 負載平衡器會終止用戶端 SSL/TLS 連線,然後在 Pod 之間平衡要求。透過 Ingress 設定 HTTP(S) 負載平衡器時,可以設定負載平衡器向用戶端顯示最多 10 個 TLS 憑證。

負載平衡器會使用伺服器名稱指示 (SNI),依據 TLS 握手中的網域名稱判斷要向客戶呈現哪些憑證。若用戶端不使用 SNI,或者用戶端使用的網域名稱與其中一個憑證的常用名稱 (CN) 名稱不符,負載平衡器就會使用 Ingress 中列出的第一個憑證。下列圖表說明將流量依據要求中所使用的網域名稱,傳送到不同後端的負載平衡器:

「使用 Ingress 設定多個 SSL 憑證」系統圖表

您可以選用以下三種方法來指定 Ingress 的憑證:

  • Kubernetes 密鑰

  • 之前上傳到 Google Cloud Platform 專案的預先共用憑證。

  • Google 代管的 SSL 憑證。代管憑證支援單一、非萬用字元網域。如需相關操作方式,請參閱代管憑證頁面。

您可以在同一個 Ingress 中使用多個方法,如此一來,在方法間進行遷移時就不會出現停機時間。

最低 GKE 版本

您必須使用 GKE 1.10.2 以上版本才能使用預先共用的憑證,或在 Ingress 中指定多個憑證。

縱觀全局

以下概要說明此主題中的步驟:

  1. 建立 Deployment

  2. 建立 Service

  3. 建立兩個憑證檔案和兩個金鑰檔案。

  4. 建立使用密鑰或預先共用憑證的 Ingress。建立 Ingress 會讓 GKE 建立並設定 HTTP(S) 負載平衡器。

  5. 測試 HTTP(S) 負載平衡器。

事前準備

如要準備這項工作,請執行下列步驟:

  • 確認您已啟用 Google Kubernetes Engine API。
  • 啟用 Google Kubernetes Engine API
  • 確認您已安裝 Cloud SDK
  • 設定預設的專案 ID
    gcloud config set project [PROJECT_ID]
  • 如果您使用區域叢集,請設定預設的運算區域
    gcloud config set compute/zone [COMPUTE_ZONE]
  • 如果您使用地區叢集,請設定預設的運算地區
    gcloud config set compute/region [COMPUTE_REGION]
  • gcloud 更新到最新版本:
    gcloud components update

建立 Deployment

以下是 Deployment 的資訊清單:

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: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50001"
      - name: hello-again
        image: "gcr.io/google-samples/node-hello:1.0"
        env:
        - name: "PORT"
          value: "50002"

Deployment 包含三個 Pod,每個 Pod 都有兩個容器。其中一個容器會執行 hello-app 並監聽 TCP 通訊埠 50001,另一個容器會執行 node-hello 並監聽 TCP 通訊埠 50002。

將資訊清單複製到 my-mc-deployment.yaml 檔案,然後建立 Deployment:

kubectl apply -f my-mc-deployment.yaml

建立 Service

以下是 Service 的資訊清單:

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 的成員。所以您在前一個步驟建立的 Deployment Pod 是 Service 的成員。

Service 資訊清單的 ports 欄位是 ServicePort 物件的陣列。當用戶端傳送要求到 my-first-port 上的 Service 時,要求會轉送到通訊埠 50001 上的其中一個成員 Pod。當用戶端將要求傳送至 my-second-port 上的 Service 時,要求會轉送到通訊埠 50002 上的其中一個成員 Pod。

將資訊清單複製到 my-mc-service.yaml 檔案,然後建立 Service:

kubectl apply -f my-mc-service.yaml

建立憑證和金鑰

若要進行此頁面的練習,您要有兩個憑證,每個憑證都有對應的金鑰。每一個憑證都必須有一個與您所擁有的網域相等的共用名稱 (CN)。若您已有具備適當的「共用名稱」值的兩個憑證檔案,可直接前往下一節。

建立第一個金鑰:

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_NAME]"

其中 [FIRST_DOMAIN_NAME] 為您所擁有的網域名稱或是假網域名稱。

例如,假設您希望負載平衡器為來自 your-store.example 的要求提供服務。那麼您的憑證簽署要求會如下所示:

openssl req -new -key test-ingress-1.key -out test-ingress-1.csr \
    -subj "/CN=your-store.example"

建立第一個憑證:

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_NAME]"

其中 [SECOND_DOMAIN] 為您所擁有的另一個網域名稱或者假網域名稱。

例如,假設您希望負載平衡器提供來自 your-experimental-store.example 的要求。那麼您的憑證簽署要求會如下所示:

openssl req -new -key test-ingress-2.key -out test-ingress-2.csr \
    -subj "/CN=your-experimental-store.example"

建立第二個憑證:

openssl x509 -req -days 365 -in test-ingress-2.csr -signkey test-ingress-2.key \
    -out test-ingress-2.crt

如要進一步瞭解如何建立您自己的憑證和金鑰,請參閱取得私密金鑰和簽署憑證

您現在有兩個憑證檔案和兩個金鑰檔案。此工作中剩下的步驟會使用這些預留位置來參照您的網域、憑證檔案和金鑰檔案:

  • [FIRST_CERT_FILE] 是第一個憑證檔案的路徑。

  • [FIRST_KEY_FILE] 是與第一個憑證搭配使用的金鑰檔案路徑。

  • [SECOND_CERT_FILE] 是第二個憑證檔案的路徑。

  • [SECOND_KEY_FILE] 是與第二個憑證搭配使用的金鑰檔案路徑。

  • [FIRST_DOMAIN] 是您所擁有的網域名稱或假網域名稱。

  • [SECOND_DOMAIN] 是您所擁有的第二個網域名稱或第二個假網域名稱。

指定 Ingress 的憑證

下一個步驟是建立 Ingress 物件。在您的 Ingress 資訊清單中,可以使用一個或兩個方法來提供負載平衡器的憑證:

  • Secrets (密鑰)
  • 預先共用的憑證

請選取 [SECRETS] (密鑰) 分頁或 [PRE-SHARED CERTS] (預先共用憑證) 分頁,從兩個方法中擇一:

Secrets (密鑰)

建立密鑰

建立包含第一個憑證和金鑰的「密鑰」:

kubectl create secret tls my-first-secret \
  --cert [FIRST_CERT_FILE] --key [FIRST_KEY_FILE]

建立包含第二個憑證和金鑰的「密鑰」:

kubectl create secret tls my-second-secret \
  --cert [SECOND_CERT_FILE] --key [SECOND_KEY_FILE]

建立 Ingress

以下是 Ingress 的資訊清單。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-mc-ingress
spec:
  tls:
  - secretName: my-first-secret
  - secretName: my-second-secret
  rules:
  - host: [FIRST_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-first-port
  - host: [SECOND_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-second-port

將資訊清單複製到 my-mc-ingress.yaml 檔案。使用您所擁有的網域名稱或假網域名稱來取代 [FIRST_DOMAIN][SECOND_DOMAIN]

建立 Ingress:

kubectl apply -f my-mc-ingress.yaml

建立 Ingress 時,GKE 輸入控制器會建立 HTTP(S) 負載平衡器。請稍候一分鐘,等待 GKE 將外部 IP 位址指派給負載平衡器。

說明您的 Ingress:

kubectl describe ingress my-mc-ingress

此結果顯示有兩個密鑰與 Ingress 關聯。輸出也顯示負載平衡器的外部 IP 位址。

Name: my-mc-ingress
Address: 203.0.113.1
...
TLS:
  my-first-secret terminates
  my-second-secret terminates
Rules:
  Host              Path  Backends
  ----              ----  --------
  your-store.example
                     my-mc-service:my-first-port (<none>)
  your-experimental-store.example
                     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

Pre-shared certs (預先共用的憑證)

使用預先共用的憑證

在您的 Google Cloud Platform 專案中建立憑證資源:

gcloud compute ssl-certificates create test-ingress-1 \
--certificate [FIRST_CERT_FILE] --private-key [FIRST_KEY_FILE]

其中:

在您的 Google Cloud Platform 專案中建立第二個憑證資源:

gcloud compute ssl-certificates create test-ingress-2 \
--certificate [SECOND_CERT_FILE] --private-key [SECOND_KEY_FILE]

其中:

  • [SECOND_CERT_FILE] 是您的第二個憑證檔案。

  • [SECOND_KEY_FILE] 是您的第二個金鑰檔案。

查看您的憑證資源:

gcloud compute ssl-certificates list

此結果顯示您擁有名為 test-ingres-1test-ingress-2 的憑證資源:

NAME                CREATION_TIMESTAMP
test-ingress-1      2018-11-03T12:08:47.751-07:00
test-ingress-2      2018-11-03T12:09:25.359-07:00

以下是 Ingress 的資訊清單,在註解中列出預先共用的憑證資源:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-psc-ingress
  annotations:
    ingress.gcp.kubernetes.io/pre-shared-cert: "test-ingress-1,test-ingress-2"
spec:
  rules:
  - host: [FIRST_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-first-port
  - host: [SECOND_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-second-port

將資訊清單複製到名為 my-psc-ingress.yaml 的檔案。使用您的網域名稱或假網域名稱來取代 [FIRST_DOMAIN][SECOND_DOMAIN]

建立 Ingress:

kubectl apply -f my-psc-ingress.yaml

請稍候一分鐘,等待 GKE 將外部 IP 位址指派給負載平衡器。

說明您的 Ingress:

kubectl describe ingress my-psc-ingress

從此結果顯示 Ingress 與名為 test-ingress-1test-ingress-2 的預先共用憑證有關聯。輸出也會顯示負載平衡器的外部 IP 位址。

Name:             my-psc-ingress
Address:          203.0.113.2
...
Rules:
  Host              Path  Backends
  ----              ----  --------
  your-store.example
                     my-mc-service:my-first-port (<none>)
  your-experimental-store.example
                     my-mc-service:my-second-port (<none>)
Annotations:
  ...
  ingress.gcp.kubernetes.io/pre-shared-cert:    test-ingress-1,test-ingress-2
  ...
  ingress.kubernetes.io/ssl-cert:               test-ingress-1,test-ingress-2
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

測試負載平衡器

請稍候五分鐘,等待 GKE 設定負載平衡器完成。

若要執行這個步驟,您必須擁有兩個網域名稱,而這兩個網域名稱必須解析 HTTP(S) 負載平衡器的外部 IP 位址。

使用您的第一個網域名稱傳送要求至負載平衡器:

curl -kv https://[FIRST_DOMAIN]

結果顯示在 TLS 握手使用您的第一個憑證。 若您的第一個網域為 your-store.example,結果看起來會像這樣:

...
*   Trying 203.0.113.1...
...
* Connected to your-store.example (203.0.113.1) port 443 (#0)
...
* TLSv1.2 (IN), TLS handshake, Certificate (11):
...
* Server certificate:
*  subject: CN=your-store.example
...
> Host: your-store.example
...
<
Hello, world!
Version: 2.0.0
...

使用第二個網域名稱,將要求傳送至負載平衡器。

curl -kv https://[SECOND_DOMAIN]

結果顯示在 TLS 握手使用您的第二個憑證。 若您的第二個網域為 your-experimental-store.example,結果看起來會像這樣:

...
*   Trying 203.0.113.1...
...
* Connected to your-experimental-store.example (203.0.113.1) port 443 (#0)
...
* Server certificate:
*  subject: CN=your-experimental-store.example
...
> Host: your-experimental-store.example
...
Hello Kubernetes!

Ingress 物件的主機欄位。

IngressSpectls 欄位是 IngressTLS 物件的陣列。每個 IngressTLS 物件都包含 hosts 欄位和 SecretName 欄位。 GKE 中不使用 hosts 欄位。GKE 會從密鑰中的憑證讀取共用名稱 (CN)。若共用名稱符合用戶端要求中的網域名稱,負載平衡器便會對用戶端提供相符的憑證。

提供的憑證有哪些?

負載平衡器會根據下列這些規則選擇憑證

  • 若密鑰和預先共用的憑證都列於 Ingress 中,負載平衡器會忽略密鑰,並使用預先共用的憑證清單。

  • 若憑證的共用名稱 (CN) 都不符合服務用戶端要求中的網域名稱,負載平衡器便會向用戶端提供主要憑證。

  • 針對 tls 區塊中列出的密鑰,主要憑證是清單中的第一個密鑰。

  • 針對註解中列出的預先共用憑證,主要憑證為清單中的第一個憑證。

疑難排解

指定無效或不存在的密鑰會導致 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'

後續步驟

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Kubernetes Engine 說明文件