Rancher 实战案例 | kube-api-auth 日志中出现大量错误信息怎么办?

发布于:2020 年 5 月 25 日 16:41

Rancher实战案例 | kube-api-auth日志中出现大量错误信息怎么办?

为了让大家能够在实际应用场景中更顺利地使用 Rancher,我们推出 Rancher 实战案例系列。该系列的文章均为生产环境中遇到的实际问题,Rancher 研发团队将基于此问题的解决过程,写出问题排查思路。本文为该系列的第一篇,分享 Rancher kube-api-auth 组件的一个问题排查记录。

前言

业界应用最广泛的 Kubernetes 管理平台 Rancher 经过多年的发展,无论是在开源社区还是在商业体系中,都拥有了大量用户。但是,正如你所知,没有任何产品是十全十美的,在用户的业务落地实践中,我们的产品也存在一些缺陷。而在我们的技术团队的支持下,许多问题也得到了改善和解决。本文我们精选了实战问题处理案例,一是分享 Rancher 技术团队成熟的经验供大家参考,二是让更多用户参与进来共同探索切磋技艺,我们坚信寻找答案的路途永远没有终点。

本文,我们将分享 Rancher kube-api-auth 组件的一个问题排查记录。

排查记录

问题描述

某客户的托管集群在经历一些操作后(操作记录未能还原),在某托管集群的 system 项目中的 kube-api-auth Pod 中不断有错误日志输出,错误信息如下:

Rancher实战案例 | kube-api-auth日志中出现大量错误信息怎么办?

由于操作记录没有还原,我们未能找到精准的重现方式。而且客户的环境只能远程操作,排查问题也非常不方便。

基本原理

Rancher 是支持多集群管理的平台,用户可以通过 rancher-server API 访问到托管集群的 Kubernetes API。在访问过程中,需要 authentication 信息,authentication 方式由 Rancher 提供。但是,在实际使用中要考虑一些特殊场景:

  1. 如果 rancher-server 宕机无法访问,用户能够直接访问托管集群 api
  2. 考虑到地理远近访问,用户有时候希望不通过 rancher-server,而直接访问托管集群 api

解决以上问题,就是 kube-api-auth 存在的价值,Rancher 会在所有的创建 RKE 集群中部署 kube-api-auth。Kuerbnetes 的 authentication 有很多方式,Rancher 在对接自己用户体系时,采用的是 webhook-token 方式,参考:

https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication

官网中也对集群访问方式有详细描述:

https://rancher.com/docs/rancher/v2.x/en/cluster-admin/cluster-access/ace/

另外一张架构图也很好说明了这两种机制:一种是通过 Rancher server 和 agent 的 tunnel 访问托管集群的 API,authentication 在 Rancher server 已经实现;另一种是直接访问托管集群 API,这时 authentication 主要靠托管集群内的 kube-api-auth 实现。

Rancher实战案例 | kube-api-auth日志中出现大量错误信息怎么办?

我们通过 kubectl 来更具体了解 kube-api-auth 的作用。Rancher 本身由生成集群 kubeconfig 的功能,你登录一个用户,可以得到的 kubeconfig 大致如下:

复制代码
apiVersion: v1
kind: Config
clusters:
- name: "c1"
cluster:
server: "https://*****/k8s/clusters/c-cn2rq"
certificate-authority-data: "xxxx"
- name: "c1-ip-172-31-24-41"
cluster:
server: "https://172.31.24.41:6443"
certificate-authority-data: "xxx"
users:
- name: "c1"
user:
token: "kubeconfig-user-gc4s9.c-cn2rq:**********"
contexts:
- name: "c1"
context:
user: "c1"
cluster: "c1"
- name: "c1-ip-172-31-24-41"
context:
user: "c1"
cluster: "c1-ip-172-31-24-41"
current-context: "c1"

我们可以看到几个关键信息:

  • User token 的格式,冒号分割的两部分,可以理解为 access key 和 secret
  • Context 包含两个,一个 rancher-server 入口,一个是托管集群 kube-api 入口;默认使用 rancher-server 入口

当我们用“c1”context 访问,使用 kubectl 随意获取一些资源,观察 kube-api-auth 的 logs,会发现没有任何输出。原因很简单,通过 rancher-server 入口访问,authentication 不走 webhook。它会在 rancher-server 中通过 tcp-proxy via websocket 方式访问托管集群 api,这种情况 authentication 没有走 webhook,直接内部证书授权方式。

当我们用“c1-ip-172-31-24-41” context 访问,观察 kube-api-auth 的 logs,会发现类似信息:

复制代码
time="2020-02-18T05:30:53Z" level=info msg="Starting Rancher Kube-API-Auth service on 127.0.0.1:6440"
time="2020-02-18T06:09:56Z" level=info msg="Processing v1Authenticate request..."
time="2020-02-18T06:09:56Z" level=info msg=" ...looking up token for kubeconfig-user-gc4s9.c-cn2rq"
time="2020-02-18T06:09:57Z" level=info msg="{\"apiVersion\":\"authentication.k8s.io/v1beta1\",\"kind\":\"TokenReview\",\"status\":{\"authenticated\":true,\"user\":{\"username\":\"user-gc4s9\"}}}"

这种情况下,kube-api-auth 是起作用的,而且在 logs 我们也能看 user token 信息,它完全能和 kubeconfig 里面的对应上。user token 的校验信息实际上是存在托管集群的某个 CRD 里面,kube-api-auth 的逻辑就是从 reqeust 信息中获取 token,并和本地 CRD 数据对照:

复制代码
# kubectl get clusterauthtokens -n cattle-system
NAME AGE
kubeconfig-user-gc4s9.c-cn2rq 13d
# kubectl get clusterauthtokens kubeconfig-user-gc4s9.c-cn2rq -n cattle-system -o yaml
apiVersion: cluster.cattle.io/v3
enabled: true
hash: $1:fad9a80a83333248:15:8:1:***********
kind: ClusterAuthToken
metadata:
creationTimestamp: "2020-02-05T03:06:18Z"
generation: 1
labels:
cattle.io/creator: norman
name: kubeconfig-user-gc4s9.c-cn2rq
namespace: cattle-system
resourceVersion: "1047"
selfLink: /apis/cluster.cattle.io/v3/namespaces/cattle-system/clusterauthtokens/kubeconfig-user-gc4s9.c-cn2rq
uid: 5ec4fc46-5030-45fb-b715-1117a5825b72
userName: user-gc4s9

这里我们需要注意 request user token 的格式,一定是冒号分割的两部分。一旦是非法格式,kube-api-auth 就会拒绝校验,并报出之前问题提到的 logs 信息:“found 1 parts of token”。

原因分析

根据上面分析的基本原理,我们可以知道触发 kube-api-auth 产生 error logs 有两个前提:

  • 通过 kube-api-auth 鉴权访问托管集群
  • 访问托管集群时 user-token 不合法

针对第一个前提,我们知道 Kubernetes 可以开启多种 authentication,在 RKE 中就支持了 X509 Client Certs/ServiceAccount/Webhook token 这些类型,多种 authentication 是可以并存的。Kubernetes 官方文档中有描述:

https://kubernetes.io/docs/reference/access-authn-authz/controlling-access/#authentication
Multiple authentication modules can be specified, in which case each one is tried in sequence, until one of them succeeds.

也就说对于某个 kube-api-client,如果 X509 Client Certs/ServiceAccount 的鉴权都失败,那么一定会走到 Webhook token。

X509 Client Certs 一般不会暴露用户使用,ServiceAccount 是常见的使用方式,ServiceAccount 的本质是会生成一个 secret(保存 JWT token),当 Pod 启动时,会放在固定目录下提供 kube-api-client 使用:

复制代码
root@ip-172-31-24-41:~# ls -ahl /var/run/secrets/kubernetes.io/serviceaccount
total 4.0K
drwxrwxrwt 3 root root 140 Feb 18 09:49 .
drwxr-xr-x 3 root root 4.0K Feb 18 09:49 ..
drwxr-xr-x 2 root root 100 Feb 18 09:49 ..2020_02_18_09_49_08.912945351
lrwxrwxrwx 1 root root 31 Feb 18 09:49 ..data -> ..2020_02_18_09_49_08.912945351
lrwxrwxrwx 1 root root 13 Feb 18 09:49 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Feb 18 09:49 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Feb 18 09:49 token -> ..data/token

假设一种场景,如果我们手动删除 ServiceAccount 对应的 secret,但不重建 Pod,这样导致 Pod 内的 secret 失效,然后观察 kube-api-auth 就可以看到大量 error log。这就是因为 secret 失效,导致 ServiceAccount 鉴权失败,进而 Kubernetes 尝试 Webhook token 鉴权,也就是通过 kube-api-auth。这时 kube-api-auth 获取 request token,而这个 token 是 kube-api-client 传过来失效的 secret JWT token,JWT token 和 webhook token 格式完全不同(没有冒号分割),就会看到“found 1 parts of token”。

解决方案

回到客户的问题本身,应该是某些造成了一些 serviceaccount 的 secret 被重建,比如:cattle serviceaccount,这个 serviceaccount 会用于运行 cluster-agent/node-agent/kube-auth-api 等组件。

这时,只要重建关键的 workload 就可以大概率解决。Rancher 托管的 workload 中,cluster-agent/node-agent/kube-auth-api 都关联了 cattle serviceaccount,重建这些 workload,让对应的 Pod 能够走默认的 serviceaccount 鉴权,就会减少报错概率。

总结

如前面所分析,Rancher 在 Kubernetes 中配置了多种鉴权模式,而 Kubernetes 在处理这些鉴权时,并没有严格固定的顺序。所以,只要 kube-auth-api 没有大批量日志错误是可以接受的,因为该请求后续可能被其他鉴权模式认证通过。反之,出现了大量 error log 则说明整个托管集群确实有问题,顺着本文思路排查,重建 cattle serviceaccount 大概率可以解决。另外,用户自己的 workload 如果依赖某个 serviceaccount,如果这个 serviceaccount 被重建,那么 workload 也会出现问题,这也是需要注意的。

阅读数:4 发布于:2020 年 5 月 25 日 16:41

评论

发布
暂无评论