自 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) 用戶端會透過兩步驟程序,驗證連線伺服器的身分:
- 檢查伺服器憑證的 SAN 中是否包含伺服器的 DNS 名稱 (或 IP 位址)。
- 如果無法使用上述方法,請檢查伺服器的 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 而受到影響:
- 取得叢集中的 Webhook 和匯總 API 伺服器清單,並找出其後端 (服務或網址)。
- 檢查後端服務使用的憑證。
由於以這種方式檢查所有憑證需要手動操作,因此只有在將叢集升級至 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
:
找出服務的選取器和目標埠:
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
。找出符合選取器的 Pod:
kubectl get pods --selector=run=nginx
指令會輸出類似以下的結果:
NAME READY STATUS RESTARTS AGE example-pod 1/1 Running 0 21m
設定通訊埠轉送
從
kubectl
localhost 到 Pod。kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
在指令中取代下列項目:
LOCALHOST_PORT
:要接聽的地址。- 步驟 1 中的
TARGET_PORT
。TargetPort
使用
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
使用下列指令,移除在背景執行的連接埠轉送:
$ 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 是使用 Go 1.17 建構而成。這個版本的 Go 移除了使用
- Kubernetes 1.19 和 Kubernetes 1.20 版本資訊
- 如果沒有 SAN,系統會將 X.509 服務憑證的 CN 欄位視為主機名稱。這項已淘汰的舊版行為現在預設為停用。
- Go 1.17 版本資訊
- 已移除暫時的
GODEBUG=x509ignoreCN=0
標記。
- 已移除暫時的
- Go 1.15 版本資訊
- 如果沒有 SAN,系統會將 X.509 憑證的 CN 欄位視為主機,這項舊版行為已遭淘汰,且預設為停用。
- RFC 6125
(第 46 頁)
- 雖然使用 CN 值是現行做法,但已遭淘汰,建議憑證授權單位改為提供
subjectAltName
值。
- 雖然使用 CN 值是現行做法,但已遭淘汰,建議憑證授權單位改為提供
- 准入 Webhook