升級至 1.23 版前,確認 Webhook 憑證的相容性


1.23 版起,Kubernetes 不再支援使用憑證中的 X.509 通用名稱 (CN) 欄位驗證伺服器身分。Kubernetes 只會依據 X.509 主體別名 (SAN) 欄位中的資訊。

為避免叢集受到影響,請務必先為 Webhook 和匯總 API 伺服器的後端,替換不含 SAN 的不相容憑證,再將叢集升級至 Kubernetes 1.23 版

為什麼 Kubernetes 不再支援沒有 SAN 的後端憑證

GKE 採用開放原始碼 Kubernetes,並使用 kube-apiserver 元件,透過傳輸層安全標準 (TLS) 與 Webhook 和匯總 API 伺服器後端通訊。kube-apiserver 元件是以 Go 程式設計語言編寫而成。

在 Go 1.15 之前,傳輸層安全標準 (TLS) 用戶端會透過兩步驟程序,驗證連線伺服器的身分:

  1. 檢查伺服器憑證的 SAN 中是否包含伺服器的 DNS 名稱 (或 IP 位址)。
  2. 如果無法使用上述方法,請檢查伺服器的 DNS 名稱 (或 IP 位址) 是否與伺服器憑證上的 CN 相同。

RFC 6125 已於 2011 年全面淘汰以 CN 欄位為基礎的伺服器身分驗證。瀏覽器和其他安全性關鍵應用程式不再使用這個欄位。

為配合更廣泛的 TLS 生態系統, Go 1.15 已從驗證程序中移除步驟 2,但保留了偵錯切換 (x509ignoreCN=0),可啟用舊行為,簡化遷移程序。Kubernetes 1.19 版是第一個使用 Go 1.15 建構的版本。1.19 至 1.22 版的 GKE 叢集預設會啟用偵錯切換開關,讓客戶有更多時間替受影響的 Webhook 和匯總 API 伺服器後端更換憑證。

Kubernetes 1.23 版是使用 Go 1.17 建構而成,這個版本移除了偵錯切換開關。GKE 將叢集升級至 1.23 版後,如果 Webhook 或匯總 API 服務未提供具有適當 SAN 的有效 X.509 憑證,叢集控制層就無法連線至這些服務。

找出受影響的叢集

適用於執行至少 1.21.9 或 1.22.3 修補程式版本的叢集

如果叢集使用 1.21.9 和 1.22.3 以上的修補程式版本,且已啟用 Cloud Logging,GKE 會提供 Cloud 稽核記錄記錄,協助您找出叢集對受影響後端的呼叫。您可以使用下列篩選器搜尋記錄:

logName =~ "projects/.*/logs/cloudaudit.googleapis.com%2Factivity"
resource.type = "k8s_cluster"
operation.producer = "k8s.io"
"invalid-cert.webhook.gke.io"

如果叢集尚未呼叫使用受影響憑證的後端,您就不會看到任何記錄。如果看到這類稽核記錄,其中會包含受影響後端的伺服器主機名稱。

以下是記錄檔項目的範例,適用於 default 命名空間中名為 example-webhook 的服務代管的 Webhook 後端:

{
  ...
  resource {
    type: "k8s_cluster",
    "labels": {
      "location": "us-central1-c",
      "cluster_name": "example-cluster",
      "project_id": "example-project"
    }
  },
  labels: {
    invalid-cert.webhook.gke.io/example-webhook.default.svc: "No subjectAltNames returned from example-webhook.default.svc:8443",
    ...
  },
  logName: "projects/example-project/logs/cloudaudit.googleapis.com%2Factivity",
  operation: {
    ...
    producer: "k8s.io",
    ...
  },
  ...
}

受影響服務的主機名稱 (例如 example-webhook.default.svc) 會以字尾的形式,加入以 invalid-cert.webhook.gke.io/ 開頭的標籤名稱。您也可以從 resource.labels.cluster_name 標籤取得發出呼叫的叢集名稱,在本範例中,該標籤具有 example-cluster 值。

淘汰深入分析

您可以透過淘汰洞察,瞭解哪些叢集使用不相容的憑證。執行 1.22.6-gke.1000 以上版本的叢集可取得洞察。

其他叢集版本

如果叢集使用 1.22 次要版本中早於 1.22.3 的修補程式版本,或是早於 1.21.9 的任何修補程式版本,您可以透過下列兩種方式,判斷叢集是否會受到這項淘汰作業影響:

方法 1 (建議做法)升級叢集至支援透過記錄識別受影響憑證的修補程式版本。 請確認叢集已啟用 Cloud Logging。叢集升級後,每當叢集嘗試呼叫未提供適當 SAN 憑證的服務時,系統就會產生識別 Cloud Audit Logs 記錄。由於系統只會在嘗試通話時產生記錄,因此建議您升級後等待 30 天,讓所有通話路徑都有足夠的時間可供叫用。

建議使用記錄檔找出受影響的服務,因為這種做法會自動產生記錄檔,顯示受影響的服務,盡量減少手動作業。

選項 2:檢查叢集中 Webhook 或匯總 API 伺服器使用的憑證,判斷是否因缺少 SAN 而受到影響:

  1. 取得叢集中的 Webhook 和匯總 API 伺服器清單,並找出其後端 (服務或網址)。
  2. 檢查後端服務使用的憑證

由於以這種方式檢查所有憑證需要手動操作,因此只有在將叢集升級至 1.21 版之前,需要評估 Kubernetes 1.23 版淘汰項目造成的影響時,才應採用這種方法。如果可以將叢集升級至 1.21,請先升級叢集,然後按照選項 1 中的操作說明進行,以免手動操作。

找出要檢查的後端服務

如要找出可能受淘汰影響的後端,請在叢集中取得 Webhook 和匯總 API 服務的清單,以及相關聯的後端。

如要列出叢集中的所有相關 Webhook,請使用下列 kubectl 指令:

kubectl get mutatingwebhookconfigurations -A   # mutating admission webhooks

kubectl get validatingwebhookconfigurations -A # validating admission webhooks

您可以檢查 Webhook 設定中的 clientConfig.service 欄位webhooks.clientConfig.url 欄位,取得特定 Webhook 的相關後端服務或網址:

kubectl get mutatingwebhookconfigurations example-webhook -o yaml

這個指令會輸出類似以下的結果:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- admissionReviewVersions:
  clientConfig:
    service:
        name: example-service
        namespace: default
        port: 443

請注意,clientConfig 可以將後端指定為 Kubernetes 服務 (clientConfig.service),或指定為網址 (clientConfig.url)。

如要列出叢集中所有相關的 Aggregated API Service,請使用下列 kubectl 指令:

kubectl get apiservices -A |grep -v Local      # aggregated API services

這個指令會輸出類似以下的結果:

NAME                     SERVICE                      AVAILABLE   AGE
v1beta1.metrics.k8s.io   kube-system/metrics-server   True        237d

這個範例會從 kube-system 命名空間傳回 metric-server 服務。

您可以檢查 spec.service 欄位,取得特定匯總 API 的相關聯服務:

kubectl get apiservices v1beta1.metrics.k8s.io -o yaml

這個指令會輸出類似以下的結果:

...
apiVersion: apiregistration.k8s.io/v1
kind: APIService
spec:
  service:
    name: metrics-server
    namespace: kube-system
    port: 443

檢查服務的憑證

找出要檢查的相關後端服務後,即可檢查每個特定服務的憑證,例如 example-service

  1. 找出服務的選取器和目標埠:

    kubectl describe service example-service
    

    這個指令會輸出類似以下的結果:

    Name: example-service
    Namespace: default
    Labels: run=nginx
    Selector: run=nginx
    Type: ClusterIP
    IP: 172.21.xxx.xxx
    Port: 443
    TargetPort: 444
    

    在這個範例中,example-service 具有選取器 run=nginx 和目標通訊埠 444

  2. 找出符合選取器的 Pod:

    kubectl get pods --selector=run=nginx
    

    指令會輸出類似以下的結果:

    NAME          READY   STATUS    RESTARTS   AGE
    example-pod   1/1     Running   0          21m
    
  3. 設定通訊埠轉送

    kubectl localhost 到 Pod。

    kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
    

    在指令中取代下列項目:

    • LOCALHOST_PORT:要接聽的地址。
    • 步驟 1 中的 TARGET_PORTTargetPort
  4. 使用 openssl 列印服務使用的憑證:

    openssl s_client -connect localhost:LOCALHOST_PORT </dev/null | openssl x509 -noout -text
    

    這個範例輸出內容顯示有效的憑證 (含 SAN 項目):

    Subject: CN = example-service.default.svc
    X509v3 extensions:
      X509v3 Subject Alternative Name:
        DNS:example-service.default.svc
    

    這個範例輸出內容顯示缺少 SAN 的憑證:

    Subject: CN = example-service.default.svc
      X509v3 extensions:
          X509v3 Key Usage: critical
              Digital Signature, Key Encipherment
          X509v3 Extended Key Usage:
              TLS Web Server Authentication
          X509v3 Authority Key Identifier:
              keyid:1A:5F:29:D8:E9:3C:54:3C:35:CC:D8:AB:D1:21:FD:C3:56:25:C0:74
    
  5. 使用下列指令,移除在背景執行的連接埠轉送:

    $ jobs
    [1]+  Running                 kubectl port-forward pods/example-pod 8888:444 &
    $ kill %1
    [1]+  Terminated              kubectl port-forward pods/example 8888:444
    

檢查網址後端的憑證

如果 Webhook 使用url 後端,請直接連線至網址中指定的主機名稱。舉例來說,如果網址是 https://example.com:123/foo/bar,請使用下列 openssl 指令列印後端使用的憑證:

  openssl s_client -connect example.com:123 </dev/null | openssl x509 -noout -text

降低 1.23 升級風險

找出受影響的叢集和使用沒有 SAN 的憑證的後端服務後,請務必先更新 Webhook 和匯總 API 伺服器後端,改用具有適當 SAN 的憑證,再將叢集升級至 1.23 版

如果後端使用不相容的憑證,GKE 就不會自動將叢集升級至 1.22.6-gke.1000 以上版本,直到您更換憑證,或1.22 版結束標準支援為止。

如果叢集使用的 GKE 版本早於 1.22.6-gke.1000,您可以設定維護排除項目,暫時禁止系統自動升級子版本。

資源

如要進一步瞭解這項異動,請參閱下列資源:

  • Kubernetes 1.23 版本資訊
    • Kubernetes 是使用 Go 1.17 建構而成。這個版本的 Go 移除了使用 GODEBUG=x509ignoreCN=0 環境設定的功能,因此無法重新啟用已淘汰的舊版行為,也就是將 X.509 服務憑證的 CN 視為主機名稱。
  • Kubernetes 1.19Kubernetes 1.20 版本資訊
    • 如果沒有 SAN,系統會將 X.509 服務憑證的 CN 欄位視為主機名稱。這項已淘汰的舊版行為現在預設為停用。
  • Go 1.17 版本資訊
    • 已移除暫時的 GODEBUG=x509ignoreCN=0 標記。
  • Go 1.15 版本資訊
    • 如果沒有 SAN,系統會將 X.509 憑證的 CN 欄位視為主機,這項舊版行為已遭淘汰,且預設為停用。
  • RFC 6125 (第 46 頁)
    • 雖然使用 CN 值是現行做法,但已遭淘汰,建議憑證授權單位改為提供 subjectAltName 值。
  • 准入 Webhook