1. 问题背景
1.1 环境概述

1.2 问题现象


安全漏洞扫描报告显示,服务器 100.80.201.209 的443端口SSL证书已过期。初步检查发现该端口由 kube-proxy 进程监听,但证书信息显示为Ingress Controller的默认证书。
2. 问题排查过程
2.1 初步检查
2.1.1 端口监听情况
在问题节点执行端口检查
shell
ss -lntp | grep 443
kube-proxy 8537 root 19u IPv4 38473 0t0 TCP *:443 (LISTEN)
确认:在节点 100.80.201.209 上,确实是 kube-proxy 进程(PID 8537)在监听 *:443。
2.1.2 集群证书状态
检查kubeadm管理的集群证书,确认均为有效状态
yaml
kubeadm alpha certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Jun 21, 2032 16:06 UTC 6y no
apiserver Jun 21, 2032 16:06 UTC 6y ca no
apiserver-kubelet-client Jun 21, 2032 16:06 UTC 6y ca no
controller-manager.conf Jun 21, 2032 16:06 UTC 6y no
front-proxy-client Jun 21, 2032 16:06 UTC 6y front-proxy-ca no
scheduler.conf Jun 21, 2032 16:06 UTC 6y no
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Jun 21, 2032 16:06 UTC 6y no
front-proxy-ca Jun 21, 2032 16:06 UTC 6y no
结果显示所有核心组件证书有效期至2032年。
2.2 深入排查
2.2.1 kube-proxy配置检查
进入kube-proxy容器检查配置。
yaml
[root@master ~]# kubectl exec -it -n kube-system kube-proxy-wz7vw /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
cat # cat /var/lib/kube-proxy/config.conf
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: ""
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: ""
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
发现:配置中未显式设置healthzBindAddress或metricsBindAddress为443端口。
2.2.2 node节点上进行证书信息验证
实际证书验证
shell
echo | openssl s_client -connect 127.0.0.1:443 -servername localhost 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates
关键证据
yaml
subject= /O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
issuer= /O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
notBefore=Dec 23 11:25:22 2023 GMT
notAfter=Dec 22 11:25:22 2024 GMT # 证书已过期
结论:443端口实际使用的是Ingress Controller的默认"假证书",且已过期。
2.2.3 网络规则分析
检查iptables规则,发现关键转发规则
shell
iptables -t nat -S | grep -E ":443|443 "
关键规则
shell
-A KUBE-SEP-3AJD4DEJDAE53EMT -p tcp -m tcp -j DNAT --to-destination 10.244.1.9:443
-A KUBE-SEP-5QSL3J6PKAUN3KGJ -p tcp -m tcp -j DNAT --to-destination 10.244.2.11:443
发现:所有到达节点443端口的流量都被DNAT重定向到Ingress Controller Pod IP
2.2.4 查看内核层面的连接跟踪
shell
# 查看当前所有经过 443 端口的活动连接/监听状态
conntrack -L -p tcp --dport 443 2>/dev/null | head -5
tcp 6 86396 ESTABLISHED src=100.80.201.209 dst=10.96.0.1 sport=43876 dport=443 src=100.80.201.231 dst=10.8.21.209 sport=6443 dport=43876 [ASSURED] mark=0 use=1
tcp 6 86383 ESTABLISHED src=100.80.201.209 dst=10.96.0.1 sport=45574 dport=443 src=100.80.201.233 dst=10.8.21.209 sport=6443 dport=45574 [ASSURED] mark=0 use=1
关键
yaml
conntrack命令显示的是出站连接,不是入站连接
conntrack 显示的是从本节点(100.80.201.209)出去连接到 API Server (10.96.0.1:443) 的出站连接
2.2.5 测试连通性并追踪
shell
# 使用 curl 测试,关注响应的 Server 头
curl -k -v https://127.0.0.1:443 2>&1 | grep -E "Server:|subject:"
* subject: CN=Kubernetes Ingress Controller Fake Certificate,O=Acme Co
关键
yaml
curl的结果直接证实了流量最终由Ingress Controller处理,因为它返回了那个熟悉的假证书。
现在整个过程是:kube-proxy并不是真正"处理"443流量,它只是设置iptables规则,
真正的TLS终止发生在Ingress Controller Pod内部。
2.2.4 Ingress Controller检查
定位集群中的Ingress Controller
shell
kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx
发现运行在ingress-nginx命名空间下的3个Pod实例。
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx ingress-nginx-controller-j4tmd 1/1 Running 0 45m 10.244.2.11 master1-std25.local <none> <none>
ingress-nginx ingress-nginx-controller-krmkl 1/1 Running 0 46m 10.244.1.9 master2-std24.local <none> <none>
ingress-nginx ingress-nginx-controller-nvqmc 1/1 Running 0 45m 10.244.3.14 master3-std26.local <none> <none>
3. 问题根本原因
3.1 流量转发机制
3.1.1 kube-proxy的实际角色
在iptables模式下,kube-proxy不直接处理数据包,而是:
1、维护iptables规则:监听Kubernetes API,根据Service和Endpoint变化动态更新规则
2、端口占用:绑定端口防止冲突,但实际流量由内核直接处理
3.1.2 完整流量路径
yaml
外部请求 → 节点IP:443 → 内核协议栈 → iptables PREROUTING链
→ KUBE-SERVICES链 → KUBE-SEP-*链 → DNAT重定向
→ Ingress Controller Pod:443 → Nginx处理(TLS解密)
→ 根据Ingress规则转发到后端服务
3.1.3 核心矛盾解释

3.2 证书过期原因
3.2.1 证书来源
yaml
过期证书: Ingress Controller的默认回退证书
生成机制: Nginx Ingress Controller启动时自动生成的自签名证书
有效期: 默认1年,用于未配置自定义TLS证书的情况
3.2.2 根本原因
yaml
默认证书过期:Ingress Controller使用的默认"假证书"已超过1年有效期
服务暴露方式:Ingress Controller Service的NodePort或LoadBalancer将443端口暴露
流量重定向:kube-proxy通过iptables规则将节点443端口的流量重定向到Ingress Controller Pod
4. 问题解决方案
4.1 临时解决方案:重启Ingress Controller
4.1.1 重启操作
由于Ingress Controller以DaemonSet形式部署:
shell
#重启ingress-nginx DaemonSet
kubectl -n ingress-nginx rollout restart daemonset ingress-nginx-controller
#观察重启状态
kubectl -n ingress-nginx get pods -w
4.1.2 验证修复
重启后在k8s集群所有节点上验证证书更新:
shell
echo | openssl s_client -connect 127.0.0.1:443 -servername localhost 2>/dev/null | \
openssl x509 -noout -dates
预期输出证书有效期已更新(延后1年)。
notBefore=Jan 6 14:35:02 2026 GMT
notAfter=Jan 6 14:35:02 2027 GMT # 有效期更新
4.2 长期解决方案:配置有效TLS证书
4.2.1 创建TLS Secret
准备有效的证书和私钥:
shell
# 创建TLS Secret
kubectl create secret tls your-domain-tls \
--cert=path/to/fullchain.pem \
--key=path/to/privkey.pem \
-n your-app-namespace
4.2.2 配置Ingress资源
在Ingress资源中引用有效证书:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: your-app-ingress
namespace: your-app-namespace
spec:
tls:
- hosts:
- your.domain.com
secretName: your-domain-tls # 引用有效证书
rules:
- host: your.domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: your-app-service
port:
number: 80
4.3 预防措施
4.3.1 证书监控
建立证书过期监控:
shell
#定期检查证书有效期的脚本示例
#!/bin/bash
end_date=$(echo | openssl s_client -connect 节点IP:443 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
expire_seconds=$(date -d "$end_date" +%s)
current_seconds=$(date +%s)
days_remaining=$(( (expire_seconds - current_seconds) / 86400 ))
if [ $days_remaining -lt 30 ]; then
echo "警告: 证书将在${days_remaining}天后过期"
fi
4.3.2 Ingress Controller配置优化
考虑修改Ingress Controller配置,使用更长有效期的默认证书或完全禁用默认证书。
5. 经验总结
5.1 关键发现
yaml
表象与实质:kube-proxy监听端口不一定是实际处理流量的组件
证书管理分离:集群核心证书与组件自身证书是独立管理的
网络路径理解:理解iptables DNAT机制是诊断Kubernetes网络问题的关键
5.2 最佳实践建议
yaml
生产环境证书管理:
避免使用自签名默认证书
为所有公开服务配置有效TLS证书
建立证书过期监控和自动续期机制
网络问题诊断方法:
从应用层(TLS证书)向下排查
检查iptables规则理解流量路径
区分kube-proxy的配置角色和实际数据路径
Ingress Controller管理:
明确记录和监控其默认证书有效期
考虑定期重启策略预防证书过期
在生产环境始终配置有效的自定义证书

5.3 技术要点回顾
yaml
kube-proxy iptables模式:配置规则但不处理数据,流量由内核直接转发
Ingress Controller默认证书:自动生成、1年有效期、用于未配置证书的情况
问题本质:默认证书过期导致的安全扫描告警,与集群核心证书无关
通过本次排查,不仅解决了具体的证书过期问题,更重要的是理解了Kubernetes网络流量的实际路径和各组件的协作方式,为后续类似问题的诊断提供了系统性的方法。