bigywater.tech
Kubernetes · 26

TokenRequest:绑定对象的短期令牌

kubectl create token 背后的 TokenRequest 做了什么?它签出的令牌有效期、受众、绑定对象各有什么约束?删掉 Pod 之后令牌会立刻失效吗?这篇逐条实测,并用 TokenReview 看一个令牌在服务端被解析成什么样子。

600 秒
令牌有效期的下限,请求 5 分钟被拒绝(默认 3600 秒)
第 11 秒
删除被绑定的 Pod(或 SA)后,令牌从这一秒起开始返回 401,之前的 10 秒内仍然有效
315360000 秒
--duration=87600h(10 年)被接受:本集群没有给令牌有效期设上限

有效期

实测 · 本机执行输出
  不指定(默认):退出码 0;exp-iat=3600 秒(1.00 小时);aud=['https://kubernetes.default.svc.cluster.local']
  --duration=20m:退出码 0;exp-iat=1200 秒(0.33 小时);aud=['https://kubernetes.default.svc.cluster.local']
  --duration=10m(下限):退出码 0;exp-iat=600 秒(0.17 小时);aud=['https://kubernetes.default.svc.cluster.local']
  --duration=5m(低于下限):退出码 1;Invalid value: 300: may not specify a duration less than 10 minutes
  --duration=87600h(10 年):退出码 0;exp-iat=315360000 秒(87600.00 小时);aud=['https://kubernetes.default.svc.cluster.local']

kubectl create token app 默认签出有效期 3600 秒的 JWT(exp - iat = 3600),--duration=20m 就是 1200 秒,--duration=10m 是下限 600 秒;5m 被拒:may not specify a duration less than 10 minutes。上限由 apiserver 的参数决定,这个集群没有设,连 10 年(87600h)都被接受。需要短期令牌的场景要自己限制,不能指望服务端兜底。

受众

实测 · 本机执行输出
  默认受众:aud=['https://kubernetes.default.svc.cluster.local'];拿去调用 API Server(SelfSubjectReview):HTTP 201 username=system:serviceaccount:k20:app
  --audience=my-service:aud=['my-service'];拿去调用 API Server(SelfSubjectReview):HTTP 401
  TokenReview(spec.audiences=[my-service])验证 my-service 的令牌:authenticated=True;status.audiences=['my-service'];user=system:serviceaccount:k20:app
  TokenReview(不指定 audiences,按 API Server 自己的受众)验证同一个令牌:authenticated=False;error=[invalid bearer token, token audiences ["my-service"] is invalid for the target audiences ["https://kubernetes.default.s
  把令牌最后 6 个字符改掉(签名不对):authenticated=False;error=[invalid bearer token, go-jose/go-jose: error in cryptographic primitive]

令牌的 aud 声明说明它是发给谁用的。默认令牌的受众是 API Server(https://kubernetes.default.svc.cluster.local),可以调用 API;--audience=my-service 的令牌受众是别的服务,拿去调 API Server 得到 401。其他服务要验证它,调用 TokenReview 并带上自己的 spec.audiences:带上 [my-service] 得到 authenticated=True,不带则得到 token audiences ["my-service"] is invalid for the target audiences。令牌末尾改掉几个字符就是 invalid bearer token(签名校验失败)。

绑定对象

实测 · 本机执行输出
  把 SA other 的令牌绑到 SA app 的 Pod holder 上:退出码 1;error: failed to create token: cannot bind token for serviceaccount "other" to pod running with different serviceaccount name.
  --bound-object-kind=Pod --bound-object-name=holder:claims 的 kubernetes.io.pod={'name': 'holder', 'uid': 'af8ce2ac-7077-4217-94c1-69e92b1e74b9'};调用 API:HTTP 201 username=system:serviceaccount:k20:app;extra=['authentication.kubernetes.io/credential-id', 'authentication.kubernetes.io/node-name', 'authentication.kubernetes.io/node-uid', 'authentication.kubernetes.io/pod-name', 'authentication.kubernetes.io/pod-uid']
  删除被绑定的 Pod holder:删除后 10 秒内这个令牌还能通过认证,第 11 秒起 HTTP 401(Unauthorized)
  同一时刻没有绑定对象的令牌 t_def(绑定的是 ServiceAccount 本身)还有效:HTTP 201 username=system:serviceaccount:k20:app
  给 SA temp 签一个令牌(HTTP 201)再删掉 SA temp:删除 SA temp:删除后 10 秒内这个令牌还能通过认证,第 11 秒起 HTTP 401(Unauthorized)

令牌可以绑定到 Pod、Secret 等对象(--bound-object-kind / --bound-object-name);绑定的 Pod 必须使用同一个 ServiceAccount,否则签发就被拒绝。绑定后 claims 里有 kubernetes.io.pod(名字和 uid),调用 API 时 user.extra 里带 pod-name、node-name 等。对象删除后令牌失效,但不是立刻:这次实测删除之后又过了 10 秒仍通过认证,第 11 秒起才 401。没有绑定对象的令牌绑定的是 ServiceAccount 本身,SA 删了同样如此。

TokenReview

实测 · 本机执行输出
  默认令牌的 TokenReview:authenticated=True;user.username=system:serviceaccount:k20:app;user.uid=dbc4e7b8…;user.groups=['system:serviceaccounts', 'system:serviceaccounts:k20', 'system:authenticated']
    status.audiences=['https://kubernetes.default.svc.cluster.local'];user.extra={"authentication.kubernetes.io/credential-id": ["JTI=3f34eab7-df4b-4aae-8714-e03c71a57613"]}

TokenReview 把令牌解析成身份:username=system:serviceaccount:k20:app,groups 是 system:serviceaccounts、system:serviceaccounts:k20、system:authenticated,status.audiences 是这次验证命中的受众,user.extra 里的 credential-id: JTI=… 是令牌的 jti,方便审计日志对应。

分步演示

TokenRequest
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,apiserver 没有设置 --service-account-max-token-expiration);令牌用 kubectl create token 签发,claims 在宿主机上解 JWT;调用 API 用 SelfSubjectReview(POST /apis/authentication.k8s.io/v1/selfsubjectreviews,宿主机 Python 直连 apiserver 的回环端口,带 Bearer 令牌),验证用 TokenReview;“失效时间”由每秒一次的轮询得到,删除对象后第一个 401 出现在第 11 秒(另一次探测也是 12 秒左右);每种情形各一次
    • 没有验证:令牌过期本身(最短 10 分钟,没有等到过期);apiserver 参数 --service-account-max-token-expiration 设置后的截断;--service-account-extend-token-expiration;对 Secret、Node 的绑定;10 秒左右的延迟具体来自 apiserver 的哪个缓存(只观察到现象);JWKS 公钥发现端点(/openid/v1/jwks)
    京ICP备2026067502号-1京公网安备11010502063487号