故障排除

第一阶段:缩小嫌疑范围(确定是谁挂了)

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. 排查命令 1

    docker ps -a | grep etcd
    
    • 结果:Up About an hour(运行了一小时)。
    • 推断数据库(Etcd)是健康的。之前怀疑 Etcd 挂了导致 API Server 连不上的假设被排除。
  2. 排查命令 2

    docker ps -a | grep apiserver
    
    • 结果:Exited (2) About a minute ago(一分钟前异常退出,且不断重启)。
    • 核心线索:状态不是 Up,说明 API Server 进程根本没跑起来。退出码 (2) 提示我们要么是配置写错了,要么是参数不对。

第二阶段:尸检(查看临死前的遗言)

既然知道是 API Server 挂了,我们需要知道它为什么挂。

  1. 排查命令 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)直接关闭了连接。这通常发生在加密协议不匹配时(比如一方讲加密,一方讲明文)。

第三阶段:核对证词(检查配置文件)

根据日志的指控,我们去检查“案发现场”的配置。

  1. 排查命令 4

    cat /etc/kubernetes/manifests/kube-apiserver.yaml
    # 以及结合你之前提供的 etcd.yaml 信息
    

最终结论(真相大白)

通过以上三步,我们锁定了根本原因:

  • 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 系统会自动发生以下事情:

  1. Kubelet 监控:Kubelet 进程一直在盯着 /etc/kubernetes/manifests/ 目录。
  2. 发现变更:它检测到 kube-apiserver.yaml 的哈希值变了。
  3. 重启 Pod
    • 它会杀掉旧的、报错的 API Server 容器(Exited 状态的那个)。
    • 它会根据你写的新配置,拉起一个新的 API Server 容器。
  4. 连接数据库:新的容器启动后,尝试用 HTTP 连接 127.0.0.1:2379 (Etcd)。
  5. 成功运行:连接成功,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 无效了,我们找一个现成的。

  1. 查看有哪些 Secret

    kubectl get secrets -n kube-system
    

    (找一个类似 coredns-token-xxxx 或者 bootstrap-token-xxxx 的名字)

  2. 获取 Token(假设你找到了 coredns-token-abcde):

    kubectl describe secret coredns-token-abcde -n kube-system
    
  3. 复制 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 变了,而是因为 “验钞机”的规则变了

  1. 公钥/私钥变了: ServiceAccount Token 是由 Controller Manager 用私钥(sa.key)签名的,然后由 API Server 用公钥(sa.pub)验证的。 你刚才为了修复 API Server,修改了配置文件。如果你在过程中触碰了证书路径,或者系统重新生成了 /etc/kubernetes/pki/sa.pub 或 sa.key,那么以前签发的所有 Token 都会瞬间作废
    • 就像你换了家里的门锁,旧钥匙虽然没变,但打不开门了。
  2. 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 上执行:

  1. 查看当前的 Secret

    kubectl get secrets -n kube-system
    

    假设你看到一个叫 default-token-xxxxx 或者 clusterrole-aggregation-controller-token-xxxxx。

    两个都可以删,建议删clusterrole-aggregation-controller-token-m8tcd

  2. 删除它

    kubectl delete secret <secret的名字> -n kube-system
    
  3. 等待 1-2 秒,再次查看:

    kubectl get secrets -n kube-system
    

    你会发现一个新的 Secret 已经被自动创建出来了(名字后面的随机码可能会变,或者时间变为刚刚)。

  4. 提取新 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 的方法。