从 1.23 版开始,Kubernetes 不再支持使用证书中的 X.509 通用名称 (CN) 字段执行服务器身份验证。Kubernetes 已改为仅依赖 X.509 主题备用名称 (SAN) 字段中的信息。
为了防止您的集群受到影响,在将集群升级到 Kubernetes 版本 1.23 之前,您必须为网络钩子和聚合 API 服务器后端替换没有 SAN 的不兼容证书。
Kubernetes 为什么不再支持没有 SAN 的后端证书
GKE 运行的是开源 Kubernetes,它使用 kube-apiserver 组件,通过传输层安全协议 (TLS) 联系您的 webhook 和聚合 API 服务器后端。kube-apiserver 组件是使用 Go 编程语言编写的。
在 Go 1.15 之前,TLS 客户端使用两个步骤来验证所连接的服务器的身份:
- 检查服务器的 DNS 名称(或 IP 地址)是否呈现为服务器证书上的 SAN 之一。
- 作为后备,请检查服务器的 DNS 名称(或 IP 地址)是否与服务器证书上的 CN 相同。
2011 年,RFC 6125 已完全弃用了基于 CN 字段的服务器身份验证。各种浏览器和其他安全关键型应用均不再使用该字段。
为了与更广泛的 TLS 生态系统保持一致,Go 1.15 移除了其验证过程中的第 2 步,但留下了一个调试开关 (x509ignoreCN=0
) 来启用旧行为,从而简化迁移过程。Kubernetes 1.19 版是使用 Go 1.15 构建的第一个版本。版本 1.19 到 1.22 的 GKE 集群默认会启用此调试开关,以便给客户留出更充裕的时间来替换受影响的网络钩子和聚合 API 服务器后端的证书。
Kubernetes 1.23 版是使用 Go 1.17 构建的,其中移除了该调试开关。GKE 将您的集群升级到 1.23 版后,调用将无法从集群的控制平面连接到未提供具有适当 SAN 的有效 X.509 证书的 webhook 或聚合 API 服务。
确定受影响的集群
对于运行版本至少为 1.21.9 或 1.22.3 的补丁程序的集群
对于启用了 Cloud Logging 且使用补丁程序版本 1.21.9 和 1.22.3 或更高版本的集群,GKE 提供 Cloud Audit Logs 日志来识别从集群调用受影响后端的操作。您可以使用以下过滤条件来搜索日志:
logName =~ "projects/.*/logs/cloudaudit.googleapis.com%2Factivity"
resource.type = "k8s_cluster"
operation.producer = "k8s.io"
"invalid-cert.webhook.gke.io"
如果您的集群未调用使用受影响证书的后端,则不会看到任何日志。如果您的确看到此类审核日志,便会发现其中包含受影响后端的主机名。
以下是由 default 命名空间中名为 example-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 的证书的 Service 时,都会生成标识性 Cloud Audit Logs 日志。由于日志仅在调用尝试时生成,因此建议在升级后等待 30 天,以便有足够的时间来调用所有调用路径。
建议使用日志来识别受影响的服务,因为这种方法将自动生成日志,显示受影响的服务,从而最大限度地减少手动工作量。
方法 2:检查集群中网络钩子或聚合 API 服务器使用的证书,以确定它们是否因没有 SAN 而受到影响:
- 获取集群中的网络钩子和聚合 API 服务器列表,并确定其后端(服务或网址)。
- 检查这些后端服务使用的证书。
鉴于以这种方式检查所有证书所需的手动工作量,只有在将集群升级到 Kubernetes 1.21 版之前需要评估 Kubernetes 1.23 版中相关弃用项的影响的情况下,才应使用此方法。如果您可以将集群升级到 1.21,则应先升级到此版本,然后按照方法 1 中的说明避免手动操作。
确定要检查的后端服务
要确定可能受此次弃用影响的后端,请获取网络钩子和聚合 API Service 及其在集群中的关联后端的列表。
如需列出集群中的所有相关网络钩子,请使用以下 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 Service (clientConfig.service
) 或网址 (clientConfig.url
)。
如需列出集群中的所有相关聚合 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
Service。
您可以通过检查 spec.service
字段来获取给定聚合 API 的关联 Service:
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
检查一个 Service 的证书
确定要检查的相关后端 Service 之后,您可以检查每个特定 Service 的证书,例如 example-service
:
找到该 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
:要侦听的地址。TARGET_PORT
:来自第 1 步的TargetPort
。
使用
openssl
输出 Service 所使用的证书: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
检查网址后端的证书
如果网络钩子使用 url
backend,请直接连接到网址中指定的主机名。例如,如果网址为 https://example.com:123/foo/bar
,请使用以下 openssl
命令输出后端所使用的证书:
openssl s_client -connect example.com:123 </dev/null | openssl x509 -noout -text
降低 1.23 升级的风险
一旦您确定受影响的集群及其后端服务使用没有 SAN 的证书,您必须在将集群升级到 1.23 版之前更新网络钩子和聚合 API 服务器后端,以使用具有适当 SAN 的证书。
除非您替换证书或者 1.22 版达到标准支持服务终止期限,否则 GKE 不会自动升级其后端使用不兼容证书的 1.22.6-gke.1000 版或更高版本的集群。
如果您的集群所用的 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 值,但它已被弃用,我们建议证书授权机构改为提供
- 准入网络钩子