news 2026/10/21 3:00:38

K8s 1.32手动生成ServiceAccount Token:短期与长期方案详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
K8s 1.32手动生成ServiceAccount Token:短期与长期方案详解

做K8s运维的朋友应该都遇到过这类需求:CI/CD流水线要调用集群API做发布,监控系统要采集集群指标,或者外部应用需要读集群资源状态。最直接的办法就是给外部系统准备一个ServiceAccount(后面统一叫SA)的token,让它拿着这个token通过API Server认证。如果你的集群还是1.24之前的旧版本,事情很简单——创建SA之后系统会自动生成一个对应Secret,token就在里面躺着,复制出来就能用。但从1.24开始这个默认行为被砍掉了,到了K8s 1.32及之后的版本,你创建完SA之后等半天也看不到那个带token的Secret。

我最初也在这个地方卡了很久,查文档、翻源码才搞明白。这篇文章就用我实际踩坑的经历,把K8s 1.32以上集群手动生成SA token的方法一次讲清楚,包括短期token和长期token两条路线怎么选、怎么组装外部kubeconfig、以及那些文档里不会写的坑。无论你是刚接触K8s的新手,还是正在帮外部系统对接集群的老人,这篇都值得收藏。

1. 为什么新版集群不再"自动生成"SA token

1.1 旧机制里到底发生了什么

在1.24之前的版本里,只要执行kubectl create sa xxx,控制平面里的一个控制器就会自动创建一个同名的Secret,这个Secret的type是kubernetes.io/service-account-token,里面data.token字段就是SA的长期token。这个token没有过期时间,任何持有它的人都能以这个SA的身份调用API。

更关键的是,Pod在创建时如果指定了SA且没有关闭自动挂载,kubelet会把对应Secret挂载到Pod里的/var/run/secrets/kubernetes.io/serviceaccount/token,容器内应用读这个文件就能访问集群API。

这套机制用了很多年,但它有两个越来越让安全团队头疼的问题:一是token长期有效,一旦泄漏很难控制损失,只能靠删SA或者改权限来兜底;二是token跟Secret绑定,没法按需设置有效期和用途边界,审计和轮换都麻烦。

1.2 TokenRequest API是替代方案

为了解决上面这些问题,K8s引入了TokenRequest API,核心思路是从"给一个无限期的静态token"变成"按需签发一个短期token"。在一个大版本周期内,这个API迭代成熟后,官方就决定从1.24开始默认不再自动创建SA对应的Secret。

现在Pod里的serviceaccount挂载方式也变了,默认走的是投影卷(Projected Volume),kubelet会周期性地通过TokenRequest向API Server请求一个短时token,写进只读文件里。Pod内的应用拿到的token通常过期时间是一小时左右,kubelet会在过期前自动续期,旧token直接失效。这样即使某个Pod的token被拿走了,风险窗口也被压缩得很小。

1.3 1.32里手动创建Secret还灵不灵

我一开始以为1.32彻底禁用了老方式,后来实测发现并没有。虽然系统不再自动创建一个全新Secret,但如果你手动声明一个Secret,设置好type字段和对应annotation,控制平面里的旧控制器仍然会识别它,帮你在Secret里填充token。

这意味着现在有两条并行的路可以走:一条是走TokenRequest API,拿短期token,适合单个任务、短生命周期场景;另一条是手动建Secret,继续拿长期token,适合那些没法频繁续期的外部系统。两条路我都验证过,1.32版本下都能正常使用。

2. 动手前先理清权限和服务身份

2.1 SA、Secret、RBAC这三层关系

拿到一个token之后,它在K8s里的身份映射是这样的:token本身只是凭证,API Server解出token里的信息后,会确认它对应的是哪个SA,然后用这个SA绑定的RBAC规则来决定能做什么操作。

所以整个链路是:token证明你是哪个SA → 该SA在哪个命名空间 → 该命名空间下RBAC绑定了哪些权限。

我在实操中见过不少"token生成对了但还是调不通"的案例,最后查下来基本都是RBAC这一层没配置好。比如token对应的SA在prod命名空间,但只给这个SA绑定了dev命名空间的Role,那调prod的API自然就是403。

2.2 给外部系统一个清晰的最小权限

不管外部系统是只读巡检还是需要触发Job,都建议先画清楚它到底要调哪些API,然后按API分组去设计RBAC。最省事的做法当然是直接绑cluster-admin,但这是运维事故的高发源头,千万别图省事。

下面是一个只读权限的示例,适合监控巡检类外部系统:

kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: external-readonly rules: - apiGroups: [""] resources: ["pods", "services", "endpoints", "nodes", "namespaces"] verbs: ["get", "list", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: external-readonly-binding subjects: - kind: ServiceAccount name: ci-reader namespace: ci # 改成你真实SA所在namespace roleRef: kind: ClusterRole name: external-readonly apiGroup: rbac.authorization.k8s.io

如果外部系统只需要操作某一个命名空间的资源,那就用Role和RoleBinding,别用Cluster级别的,权限范围越小越安全。

2.3 短期token还是长期token:按场景选

这是我最常被问到的问题。我的建议其实很简单,看外部系统能不能自己续期:

  • 能自己续期的系统(比如SDK支持读取kubelet投影token、或者定时任务可以每次调用TokenRequest再重新加载kubeconfig),优先用短期token。
  • 没法改代码、只能塞一个固定token跑半年的老系统,就只能用Secret方式拿长期token。
  • CI/CD单次构建、一次性的数据迁移任务,用kubectl create token指定一个像8小时或24小时的有效期就非常合适。

下面这张表是我日常选型的参考:

对比维度kubectl create tokenSecret绑定SA
token有效期默认1小时,可通过--duration指定长期有效,不自动过期
轮换方式到期前重新生成删除重建Secret,换取新token
风险敞口小大,泄漏后影响时间长
适用场景CI/CD单次任务、短时操作无法改代码的外部系统
官方推荐度推荐兼容保留,不推荐新接入

3. 手动生成SA token的完整实操

3.1 准备阶段:创建SA并绑定权限

先建一个SA。我这里以外部监控系统要读取ci命名空间资源为例:

kubectl create ns ci kubectl create sa ci-reader -n ci

创建完验证一下:

kubectl get sa ci-reader -n ci

这时候你去kubectl get secret -n ci看,会发现没有任何跟ci-reader相关的Secret,这就是新版集群和旧版集群最直观的区别。

然后把上面那套RBAC配置保存成rbac.yaml,执行:

kubectl apply -f rbac.yaml

这里有个细节容易忽略:RBAC里的subjects用的是"kind: ServiceAccount",不是"kind: User"。我之前见过有同事把SA写成了User,结果怎么弄都是权限不足,因为这个API对象的subjects类型是固定的,SA必须用ServiceAccount类型。

3.2 方式A:kubectl create token生成短期token

新版kubectl自带了create token子命令,这是最推荐的方式。命令如下:

kubectl create token ci-reader -n ci --duration=8h --audience=https://kubernetes.default.svc

参数解释一下:

  • --duration指定过期时间,支持Go的时长格式,比如6h、24h、720h。默认是1小时。
  • --audience填API Server认可的受众标识。如果集群没做特殊配置,填https://kubernetes.default.svc一般都能通过。

执行完会直接输出一串JWT格式的token,形如eyJhbGciOiJSUzI1NiIsImtpZCI6...很长一串。这个token可以直接用在kubeconfig里,也可以放在HTTP请求的Authorization: Bearer头里。

我在实际使用中一般是把token写进环境变量,然后在脚本里用:

SA_TOKEN=$(kubectl create token ci-reader -n ci --duration=24h)

这样后续脚本里直接用$SA_TOKEN就行,不用复制粘贴,也避免token出现在shell历史里。

3.3 方式B:Secret绑定SA生成长期token

如果外部系统确实需要一个不过期的token,就手动创建Secret,并加上下面这个关键annotation。

apiVersion: v1 kind: Secret metadata: name: ci-reader-token namespace: ci annotations: kubernetes.io/service-account.name: ci-reader type: kubernetes.io/service-account-token

保存为secret.yaml后执行:

kubectl apply -f secret.yaml

等几秒钟,控制器会往这个Secret里写入token和ca.crt。验证一下:

kubectl get secret ci-reader-token -n ci -o yaml

看到的data字段里应该有三项:ca.crt、namespace、token。token字段的值是base64编码后的JWT字符串。

提取token的命令:

kubectl get secret ci-reader-token -n ci -o jsonpath='{.data.token}' | base64 -d

如果你在macOS上执行,有些老版本的base64命令不认-d参数,用--decode或者-D都可以。

这里有两个坑要重点说。第一个,Secret的type必须是kubernetes.io/service-account-token,写错成Opaque的话控制器不会往里面填token。第二个,annotation里的key是kubernetes.io/service-account.name,不是service-account-name,少一个点或者多了个横杠都不行。我有一次手滑把name拼成了names,结果token字段空了十分钟,排查的时候差点把集群翻了个底朝天。

3.4 组装外部系统的kubeconfig

外部系统拿到token之后,通常会配一个独立的kubeconfig文件来访问集群。我一般这样组装:

先拿到API Server地址和CA数据:

kubectl cluster-info

拿到类似https://192.168.1.100:6443这样的地址。然后:

kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}'

这一步拿到的也是一段base64编码的CA证书数据。到这里,token、API Server地址、CA数据三样东西都齐了,把它们拼成一个kubeconfig文件:

apiVersion: v1 kind: Config clusters: - name: external-cluster cluster: server: https://192.168.1.100:6443 certificate-authority-data: <上面拿到的base64数据> contexts: - name: external-context context: cluster: external-cluster namespace: ci user: external-user current-context: external-context users: - name: external-user user: token: <SA token字符串>

这个文件可以放到外部系统对应的目录里,比如/opt/monitor/kubeconfig,或者挂在外部容器的某个安全目录。

3.5 验证token能否正常访问集群

配置文件写好后,第一步先做本地验证:

kubectl --kubeconfig=external-kubeconfig auth whoami

输出里会显示USERNAME类似system:serviceaccount:ci:ci-reader,说明token认证是靠SA的身份,这个输出没问题的话再试一次资源操作:

kubectl --kubeconfig=external-kubeconfig get pods -n ci

能正常返回Pod列表,说明整个链路已经通了。如果这一步报错,大部分情况不是token有问题,而是CA数据或者RBAC的问题,下面第4部分会有排查清单。

4. 常见问题与排查实录

4.1 401 Unauthorized:audience不匹配

报错表现是HTTP 401,token拿去curl API Server完全认不了。这个问题多见于用TokenRequest生成的短期token,因为TokenRequest里会带audience字段,而API Server校验时要求audience匹配。

排查方式很简单,看看你生成token时是不是指定了奇怪的audience。大多数集群用默认的https://kubernetes.default.svc就好。如果你实在不确定集群接受什么audience,就用kubectl create token时不带--audience参数,让它用默认值。

4.2 token怎么7天就过期了

有同事反馈,用Secret绑定SA生成的token,一周后就访问不了了。这里要区分一下:如果你用的是kubectl create token方式,默认1小时过期非常正常;如果你用的是Secret方式但token还是过期了,那就要检查是不是集群里开了额外的token老化策略,比如某些配置或安全组件强制TTL。

另外一个常见原因:外部系统的kubeconfig里同时配置了token和client-certificate,而证书过期时间更短,表现上就像token失效了。建议外部kubeconfig里只保留token认证字段,别混着配客户端证书。

4.3 403 Forbidden:RBAC没生效

401是身份不被认可,403是身份认可但权限不足。这两个区别一定要分清。403的排查思路就是看RBAC:SA在哪个命名空间、绑定了哪个Role、Role里有没有对应资源的操作权限。

我遇到过一种很隐蔽的情况:用ClusterRoleBinding绑定了SA之后,ClusterRole里的apiGroups没写对。比如要读Deployment,apiGroups得写apps,即使同名的资源在多个apiGroup里,写错组就是没权限。这类问题光看报错信息往往看不出来,建议一条一条资源去试,缩小范围。

4.4 删除与吊销:让一个token立刻失效

长期token一旦泄漏,第一反应就是赶紧让它失效。对Secret方式来说,直接删掉Secret:

kubectl delete secret ci-reader-token -n ci

删掉之后所有持有这个token的请求都会变成401。对短期token来说,还没到过期时间就等它自然过期,或者如果是因为SA被删导致,最直接的办法是删掉绑定的SA,同命名空间下所有相关token都会一并失效。

4.5 base64解码在不同平台上的坑

提取Secret里的token要base64解码,大多数Linux发行版自带base64 -d,macOS自带的base64命令老版本只认-D,有些用GNU coreutils的macOS环境则两个参数都认,依具体环境而异。

我在文章里统一用base64 -d,如果你在macOS上报错,改成base64 --decode或者base64 -D即可。别小看这一点,我见过有同事直接复制走了base64编码后的原文当token用,结果请求一直失败,查了半天还怀疑是集群配置问题。

5. 安全使用建议

5.1 永远别绑cluster-admin

给外部系统配权限时,最容易犯的错误就是图省事绑个cluster-admin。我见过不止一次,外部监控系统拿着cluster-admin token,结果某天误操作把集群里重要的资源全删了。回头看,这个系统的正常功能只需要读Pod和节点,一个只读ClusterRole完全够用,当时图方便留下的隐患,出事之后整个团队连续加班了一周收拾残局。

最小权限原则在这件事上不是一句口号,外部系统的权限边界应该就覆盖它的正常业务范围,多出一点点都是在放大风险。

5.2 token的存放、传输与引用

SA token的敏感程度等同于一套API凭据,绝对不能直接写死在代码仓库或者镜像里。外部kubeconfig尽量放在专门的配置目录,权限收紧到只有运行用户能读。传输的话,如果系统支持,优先走密钥管理系统下发,而不是在聊天工具里转发明文token。

生产环境里我还见过一个细节:某些系统的日志会把HTTP头打出来,Authorization: Bearer后面紧跟的就是完整token,一次报错日志就能泄干净。如果外部系统是自己开发维护的,建议在日志脱敏处理上把Authorization字段排除掉。

5.3 轮换节奏与巡检

短期token的轮换机制可以交给kubelet或者定时任务处理,长期token就得人工规划轮换周期。我的经验是每90天轮换一次Secret绑定SA的token,做法是新建一个新名字的Secret,让外部系统切到新token后,再删除旧Secret。这个过程可以做成脚本,配合监控告警提示用到多少天。

巡检方面,我把下面几个SQL和维护动作固定在月度运维检查里:

  • 罗列所有type为kubernetes.io/service-account-token的Secret,标记出那些创建超过90天且不在白名单里的。
  • 检查ClusterRoleBinding里是否有绑定到外部SA的cluster-admin,一有就报警。
  • 检查外部kubeconfig文件真实使用的token对应的SA,是否仍然存在。

这套巡检看起来琐碎,但它能在token泄漏或者权限放大问题酿成大祸之前,把风险提前暴露出来。

我个人在实际运维中的体会是,K8s从自动生成长期token走向按需签发短期token,这个方向本身就是安全和易用性的一个平衡结果。短期token确实更安全,但也逼着我们这些集成方把认证的逻辑理顺,把token当成有生命周期的资源来管理。如果你在这篇文章里只记住一件事,那就记住:外部系统能用短期token就别用长期token,能拿到最小权限就别贪图admin权限。真按这个原则走,1.32集群里手动生成SA token这件小事,就能既满足业务需求又守住安全底线。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 2:59:49

基于深度学习的全链路智能舆情处置系统架构与实战

数字公关这个领域&#xff0c;看起来是文案和关系维护的战场&#xff0c;但真正做过危机处置的人都知道&#xff0c;背后最硬核的其实是技术中台。一款舆情系统能不能在30秒内抓住苗头、能不能判断这条帖子到底是真实吐槽还是水军发酵、能不能在事态升级前自动给出处置建议&…

作者头像 李华
网站建设 2026/10/21 2:59:29

风电场箱变智能在线监测:传感器选型、诊断算法与工程实践

1. 为什么风电场箱变需要一套“状态感知系统”干风电这行的朋友都清楚&#xff0c;风机塔筒之外&#xff0c;箱式变压器是全场最容易“被冷落”却最不该出问题的设备。它常年趴在机位旁边&#xff0c;风吹日晒、盐雾沙尘挨个尝遍&#xff0c;每天跟着风机负荷上下剧烈波动&…

作者头像 李华
网站建设 2026/10/21 2:59:01

AI视频自动化入门实战:从文案到成片全流程拆解

说实话&#xff0c;"AI视频自动化"这个念头在我脑子里转了大半年&#xff0c;一直没敢动手。原因很直白&#xff1a;怕被工具牵着鼻子走、怕搞出来的东西全是AI味儿、更怕投入一整天结果连个能看的片子都剪不出来。但最近情况变了——我被一个做知识切片的朋友刺激到…

作者头像 李华
网站建设 2026/10/21 2:57:55

fast-livo2多传感器融合SLAM实战:参数调优与踩坑记录

fast-livo2这款融合激光雷达、IMU与视觉的SLAM框架&#xff0c;我前前后后折腾了两个多月才算是摸透了脾气。最开始是在某高校实验室的室内测试场跑公开的ROS2数据包&#xff0c;第一次完整建图成功的时候&#xff0c;周围的人都挺兴奋&#xff0c;那种从零到一的感觉确实难忘。…

作者头像 李华
网站建设 2026/10/21 2:57:41

Docker封装CPLEX:解决Java运筹优化服务化部署难题

简介&#xff1a;本资源提供基于Docker容器化部署IBM ILOG CPLEX优化求解器的完整实践方案&#xff0c;面向Java开发者、运筹优化学习者及需要在隔离环境中快速集成CPLEX运行时组件的工程人员。方案聚焦于解决本地环境依赖复杂、CPLEX原生库路径配置繁琐、跨平台部署不一致等典…

作者头像 李华
网站建设 2026/10/21 2:57:26

智能虚拟互动系统架构设计与实战调优:从大模型应用到高可用落地

智能虚拟互动系统这两年特别火&#xff0c;但真正落地过的人都知道&#xff0c;从“能对话”到“好用、扛得住、成本可控”&#xff0c;中间隔着一条很深的沟。我最近刚做完一个类似的项目——某场馆的智能虚拟导览助手&#xff0c;同时接入了线下大屏和线上Web入口&#xff0c…

作者头像 李华