故障排除
第一阶段:缩小嫌疑范围(确定是谁挂了)
E:\CyberSecurity\00_NetworkSecurityTools\11_CloudAttackDefense\kubectl>kubectl --insecure-skip-tls-verify -s https://192.168.136.134:6443/ --token="bGciOiJSUzI1NiIsImtpZCI6Ik95YVV2Mm1XX1gtT2UtZGZNSmxHeEZUUzFnWTFTNVVFTkJUdkt0UnAybXcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjbHVzdGVycm9sZS1hZ2dyZWdhdGlvbi1jb250cm9sbGVyLXRva2VuLW04dGNkIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNsdXN0ZXJyb2xlLWFnZ3JlZ2F0aW9uLWNvbnRyb2xsZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyOGQ2MjNmYy1mOTkwLTRmY2ItYWJkZi1kMzRkZTNjMWVlZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Y2x1c3RlcnJvbGUtYWdncmVnYXRpb24tY29udHJvbGxlciJ9.Egefp3DsmkmVUtUXyBYTA6IcBA9xjs8UXCvJO3C-M2Qm1HzbNO7elD26qMxBZsBOEHBYueseDK3lI3JE0r9aoOZomATL187nCcjdlBVAmEEeGYSmMatlPzQi64GvGfqI_Rp1Z8NtqcdBBKiHa2NdYuvJ79IrJxS64AkCvzqm_l5U7rERkow0FHcxM8FevYuW3rD4PZ7XeFl2FIrXaMiqyox5-QsXjNxepjurWIvDNE815QuqlnJEIz68x1vr0P3xtW-v71IzEGGe0K2ohxDi81a3Pv-PkIM7SeEki6bUhoGuG30qle33Z93OaPgXqHp-snodpRJIow4HPgsBmLIAsg" -n kube-system get pods
Unable to connect to the server: dial tcp 192.168.136.134:6443: connectex: No connection could be made because the target machine actively refused it.
现象:Windows 客户端报错 connection refused。 初步判断:这说明端口不通,意味着服务没起来。但 K8s 组件很多,是谁没起来?
-
排查命令 1:
docker ps -a | grep etcd- 结果:Up About an hour(运行了一小时)。
- 推断:数据库(Etcd)是健康的。之前怀疑 Etcd 挂了导致 API Server 连不上的假设被排除。
-
排查命令 2:
docker ps -a | grep apiserver- 结果:Exited (2) About a minute ago(一分钟前异常退出,且不断重启)。
- 核心线索:状态不是 Up,说明 API Server 进程根本没跑起来。退出码 (2) 提示我们要么是配置写错了,要么是参数不对。
第二阶段:尸检(查看临死前的遗言)
既然知道是 API Server 挂了,我们需要知道它为什么挂。
-
排查命令 3(关键一击):
docker logs 15352688cb2e # 查看挂掉容器的日志-
结果(日志原文):
grpc: addrConn.createTransport failed to connect to {https://127.0.0.1:2379 ...} Err :connection error: desc = "transport: authentication handshake failed: EOF" panic: context deadline exceeded -
深度解读:
- failed to connect to https://…:证明 API Server 正在尝试用 HTTPS 协议去连 Etcd。
- handshake failed: EOF:握手失败,对端(Etcd)直接关闭了连接。这通常发生在加密协议不匹配时(比如一方讲加密,一方讲明文)。
-
第三阶段:核对证词(检查配置文件)
根据日志的指控,我们去检查“案发现场”的配置。
-
排查命令 4:
cat /etc/kubernetes/manifests/kube-apiserver.yaml # 以及结合你之前提供的 etcd.yaml 信息- 你的操作背景:你为了修复 Etcd 无法连接的问题,手动修改了 etcd.yaml,将其改为 http://0.0.0.0:2379(**HTTP 明文模式**)。
- 现场发现:但在 kube-apiserver.yaml 里,配置依然是 —etcd-servers=https://127.0.0.1:2379(**HTTPS 加密模式**)。
最终结论(真相大白)
通过以上三步,我们锁定了根本原因:
- API Server 拿着“加密证书”去敲门(HTTPS)。
- Etcd 开着“不加密的门”(HTTP)。
- Etcd 看到一堆乱码(加密握手包),觉得莫名其妙,直接挂断(EOF)。
- API Server 连不上数据库,以为数据库挂了,于是自我崩溃(Panic),导致无限重启。
排查公式总结: docker ps (看生死) → docker logs (看死因) → cat *.yaml (找配置冲突) → 解决问题。
通信协议导致K8sApiServer 无限重启(CrashLoopBackOff)
1. 这一步的核心逻辑:由“跨服聊天”变为“同频交流”
- 修改前(故障状态):
- Etcd(服务端)说:“我不加密,请讲明文(HTTP)。”
- API Server(客户端)说:“我有证书,我要讲加密语言(HTTPS)。”
- 结果:Etcd 听不懂,直接挂断电话(EOF),API Server 崩溃。
- 修改后(修复状态):
- 你修改了 kube-apiserver.yaml,把 —etcd-servers 改成了 http://…。
- 你删除了证书配置(因为明文不需要证书)。
- 结果:API Server 也讲明文了,两者握手成功,API Server 终于可以启动了。
2. 执行后的系统行为(自动化过程)
当你执行完 vi 修改并 :wq 保存后,Linux 系统会自动发生以下事情:
- Kubelet 监控:Kubelet 进程一直在盯着 /etc/kubernetes/manifests/ 目录。
- 发现变更:它检测到 kube-apiserver.yaml 的哈希值变了。
- 重启 Pod:
- 它会杀掉旧的、报错的 API Server 容器(Exited 状态的那个)。
- 它会根据你写的新配置,拉起一个新的 API Server 容器。
- 连接数据库:新的容器启动后,尝试用 HTTP 连接 127.0.0.1:2379 (Etcd)。
- 成功运行:连接成功,API Server 进入 Running 状态,并开始监听 6443 端口。
3. 你需要做的验证步骤
保存文件 20 秒后,请执行以下命令来确认修复成功:
步骤 A:检查容器状态
docker ps | grep apiserver
- 成功标志:看到状态是 Up X seconds 或 Up X minutes。
- 失败标志:依然是 Exited 或 Restarting(如果这样,请再次检查 yaml 缩进或是否拼写错误)。
步骤 B:检查端口监听
netstat -tpln | grep 6443
- 成功标志:看到有进程监听 6443 端口。这意味着你的 Windows 电脑终于可以通过网络连上它了。
4. 预告:修复后的下一个问题
当你做完这“最后一步”修复好 API Server 后,你会回到之前遇到的那个 401 Unauthorized 问题:
error: You must be logged in to the server
这是正常的! 因为你修好了路(网络连接),但你的钥匙(Token)可能因为这次大修而失效了。
接下来的动作: 一旦你确认 docker ps 里 API Server 活着,请直接在 Linux 上重新提取 Token,然后在 Windows 上使用新 Token 连接即可:
# 在 Linux 上找新 Token
kubectl get secrets -n kube-system
# 描述任意一个带 token 的 secret
kubectl describe secret -n kube-system <secret-name>
现在,请先按照你引用的这段话去修改配置文件吧!
Token鉴权
E:\CyberSecurity\00_NetworkSecurityTools\11_CloudAttackDefense\kubectl>kubectl --insecure-skip-tls-verify -s https://192.168.136.134:6443/ --token="bGciOiJSUzI1NiIsImtpZCI6Ik95YVV2Mm1XX1gtT2UtZGZNSmxHeEZUUzFnWTFTNVVFTkJUdkt0UnAybXcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjbHVzdGVycm9sZS1hZ2dyZWdhdGlvbi1jb250cm9sbGVyLXRva2VuLW04dGNkIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNsdXN0ZXJyb2xlLWFnZ3JlZ2F0aW9uLWNvbnRyb2xsZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyOGQ2MjNmYy1mOTkwLTRmY2ItYWJkZi1kMzRkZTNjMWVlZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Y2x1c3RlcnJvbGUtYWdncmVnYXRpb24tY29udHJvbGxlciJ9.Egefp3DsmkmVUtUXyBYTA6IcBA9xjs8UXCvJO3C-M2Qm1HzbNO7elD26qMxBZsBOEHBYueseDK3lI3JE0r9aoOZomATL187nCcjdlBVAmEEeGYSmMatlPzQi64GvGfqI_Rp1Z8NtqcdBBKiHa2NdYuvJ79IrJxS64AkCvzqm_l5U7rERkow0FHcxM8FevYuW3rD4PZ7XeFl2FIrXaMiqyox5-QsXjNxepjurWIvDNE815QuqlnJEIz68x1vr0P3xtW-v71IzEGGe0K2ohxDi81a3Pv-PkIM7SeEki6bUhoGuG30qle33Z93OaPgXqHp-snodpRJIow4HPgsBmLIAsg" -n kube-system get pods
E1129 09:10:27.495565 22016 memcache.go:265] couldn't get current server API group list: the server has asked for the client to provide credentials
E1129 09:10:27.507596 22016 memcache.go:265] couldn't get current server API group list: the server has asked for the client to provide credentials
E1129 09:10:27.511607 22016 memcache.go:265] couldn't get current server API group list: the server has asked for the client to provide credentials
E1129 09:10:27.514616 22016 memcache.go:265] couldn't get current server API group list: the server has asked for the client to provide credentials
E1129 09:10:27.517121 22016 memcache.go:265] couldn't get current server API group list: the server has asked for the client to provide credentials
error: You must be logged in to the server (the server has asked for the client to provide credentials)
好消息是:此时你的 API Server 已经复活了!(不再报 Connection refused,说明端口通了,服务起来了)。
坏消息是:鉴权(Authentication)失败了。 错误信息 You must be logged in to the server (HTTP 401 Unauthorized) 意味着:API Server 收到了你的 Token,但认为这个 Token 是无效的,拒绝承认你的身份。
结合你刚才“大修”了 kube-apiserver.yaml 的背景,原因有 99% 的可能是以下两点之一:
原因 1:ServiceAccount 签名密钥配置丢失(最可能)
Kubernetes 的 Token (JWT) 是需要用公钥/私钥进行验证的。 你刚才为了解决 Etcd 的 HTTP 问题,修改 kube-apiserver.yaml 时,是不是误删了配置 ServiceAccount 密钥的那几行?
如果 API Server 启动时找不到 —service-account-key-file,它就无法验证任何 Token 的真伪,从而拒绝所有 Token 登录。
请检查: 在 Linux (Master) 上执行:
grep "service-account" /etc/kubernetes/manifests/kube-apiserver.yaml
正确的情况应该至少包含以下内容之一(路径可能不同):
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key # 较新版本
- --service-account-issuer=...
如果这些行不见了,你需要把它们加回去!
原因 2:Token 是旧的,或者对应的 Secret 变了
虽然 Token 本身是有有效期的,但如果集群发生了重大变更(比如你重置了集群,或者重新生成了 sa.pub/sa.key 密钥对),那么之前的旧 Token 就会立刻失效,因为“印章”变了。
如何排查并解决?
第一步:查看 API Server 为什么拒绝这个 Token
这是最快找到原因的方法。请在 Linux 上查看 API Server 的日志:
# 1. 找到 API Server 的容器 ID
docker ps | grep apiserver
# 2. 查看日志(替换成你的容器ID),重点看报错
docker logs --tail=50 <容器ID>
请找类似这样的报错:
- Unable to authenticate the request due to an error: [invalid bearer token, …]
- Key verification failed
- crypto/rsa: verification error
第二步:尝试使用 8080 端口(绕过认证)
既然你是做靶场攻击练习,而且你之前的日志显示配置文件里有关于 insecure-port 的废弃警告,你可能开启了 8080 非安全端口。
如果你的 kube-apiserver.yaml 里有 —insecure-port=8080 和 —insecure-bind-address=0.0.0.0(或者默认监听本地),你可以尝试不带 Token、不带 HTTPS 直接连 HTTP:
在 Windows 上尝试:
kubectl -s http://192.168.136.134:8080 get pods -n kube-system
注意:是 http 不是 https,端口是 8080。
如果这能通,说明你是管理员权限(8080 端口默认绕过鉴权)。
第三步:重新获取 Token(如果 8080 能通)
如果 8080 能通,你可以用这个“后门”去重新获取一个肯定有效的 Token:
# 获取 secret 列表
kubectl -s http://192.168.136.134:8080 -n kube-system get secrets
# 找到一个类似 clusterrole-aggregation-controller-token-xxxx 的名字,然后获取它
kubectl -s http://192.168.136.134:8080 -n kube-system describe secret <secret的名字>
复制里面的 token 字段,再次尝试 HTTPS 连接。
总结
你现在的 Token 登录不上去,是因为 API Server 验证签名失败。 请先确认 kube-apiserver.yaml 里有没有 —service-account-key-file 这一行。如果没有,Token 永远不会生效。
旧Token解决办法
1. API Server 已经修好!
日志里反复出现这行:
ccResolverWrapper: sending new addresses to cc: [{http://127.0.0.1:2379 0 <nil>}]
- 解读:注意看,是 http:// 而不是 https://。
- 结论:这证明你修改 /etc/kubernetes/manifests/kube-apiserver.yaml 成功生效了。API Server 正在使用 HTTP 协议连接 Etcd,并且没有报错退出。之前的“无限重启”和“连接被拒”问题已经彻底解决。
2. 坏消息(但符合预期):Token 确实无效
日志里有大量红色的报错:
E1129 01:10:28... Unable to authenticate the request due to an error: invalid bearer token
E1129 01:41:17... Unable to authenticate the request due to an error: invalid bearer token
- 解读:这对应了你在 Windows 上收到的 You must be logged in 错误。
- 原因:
- API Server 活着,它收到了你的请求。
- 但是你 Windows 也就是命令行里用的那个 Token,被服务器判定为“无效”。
- 可能是因为 API Server 重启后,之前的 Token 过期了,或者之前的 Secret 数据因为 Etcd 的变动有了微小变化(比如 uid 变了)。
3. 忽略项:Etcd 的 MVCC 警告
日志里有一行:
watch chan error: etcdserver: mvcc: required revision has been compacted
- 解读:这是 K8s 和 Etcd 之间的版本同步小插曲。意思是“我想看以前的数据,但 Etcd 说太久远了已经被清理了”。
- 结论:不用管它。K8s 会自动处理这种情况(重新全量同步),这不会导致认证失败。
下一步行动指南(解决最后的问题)
既然路通了(API Server 活着),只是钥匙(Token)不对,现在的解决办法非常简单:在 Linux 上重新生成/获取一个新的 Token。
请在 Linux (Master 节点) 上依次执行以下命令:
第一步:确认 Linux 本地是好的
# 这条命令不需要 Token,因为它是直接读本地配置的
kubectl get pods -n kube-system
- 如果这条命令能列出 pod,说明集群完全正常。
第二步:提取一个新的 Token
既然之前的 Token 无效了,我们找一个现成的。
-
查看有哪些 Secret:
kubectl get secrets -n kube-system(找一个类似 coredns-token-xxxx 或者 bootstrap-token-xxxx 的名字)
-
获取 Token(假设你找到了 coredns-token-abcde):
kubectl describe secret coredns-token-abcde -n kube-system -
复制 Token: 复制 token: 后面那一长串字符。
第三步:回到 Windows 测试
用新复制的 Token 替换掉你原来的:
kubectl --insecure-skip-tls-verify -s https://192.168.136.134:6443/ --token="<这里粘贴新Token>" -n kube-system get pods
为什么你重启后 Token 还是无效?
Token 无效通常不是因为 Token 变了,而是因为 “验钞机”的规则变了。
- 公钥/私钥变了:
ServiceAccount Token 是由 Controller Manager 用私钥(sa.key)签名的,然后由 API Server 用公钥(sa.pub)验证的。
你刚才为了修复 API Server,修改了配置文件。如果你在过程中触碰了证书路径,或者系统重新生成了 /etc/kubernetes/pki/sa.pub 或 sa.key,那么以前签发的所有 Token 都会瞬间作废。
- 就像你换了家里的门锁,旧钥匙虽然没变,但打不开门了。
- Etcd 数据回滚/丢失: 日志里提到了 mvcc: required revision has been compacted。如果你重置过 Etcd 或者数据发生过损坏,旧 Token 对应的 Secret 对象可能在数据库里已经不存在或 ID 变了。
如何强制“重新生成”一个有效的 Token?
你不需要重启 K8s,你需要做的是触发 K8s 的自动修复机制。
方法 1:最简单——直接删掉旧的 Secret(推荐)
K8s 有个机制:ServiceAccount 必须有一个 Token Secret。如果你把这个 Secret 删了,Controller Manager 会立刻、马上、自动创建一个新的、有效的 Secret。
在 Linux 上执行:
-
查看当前的 Secret:
kubectl get secrets -n kube-system假设你看到一个叫 default-token-xxxxx 或者 clusterrole-aggregation-controller-token-xxxxx。
两个都可以删,建议删clusterrole-aggregation-controller-token-m8tcd
-
删除它:
kubectl delete secret <secret的名字> -n kube-system -
等待 1-2 秒,再次查看:
kubectl get secrets -n kube-system你会发现一个新的 Secret 已经被自动创建出来了(名字后面的随机码可能会变,或者时间变为刚刚)。
-
提取新 Token:
kubectl describe secret <新secret的名字> -n kube-system这个时候拿到的 Token,绝对是 100% 有效的。
方法 2:创建一个全新的 ServiceAccount(更稳妥)
如果你不想动现有的系统组件,可以创建一个专门给你测试用的账号。
在 Linux 上执行:
# 1. 创建一个账号叫 hacker
kubectl create serviceaccount hacker -n default
# 2. 给它绑定超级管理员权限 (cluster-admin)
kubectl create clusterrolebinding hacker-admin --clusterrole=cluster-admin --serviceaccount=default:hacker
# 3. 查看系统自动生成的 Secret 名字
kubectl get serviceaccount hacker -n default -o yaml
# 4. 根据上一步看到的 secret name 获取 Token
kubectl describe secret <上一步看到的secret-name> -n default
总结
不要再去重启 K8s 了,那解决不了 Token 签名失效的问题。 直接删掉旧的 Secret,让 K8s 自动给你发个新的,或者新建一个账号,这是最快解决 invalid bearer token 的方法。