kubectl create token 背后的 TokenRequest 做了什么?它签出的令牌有效期、受众、绑定对象各有什么约束?删掉 Pod 之后令牌会立刻失效吗?这篇逐条实测,并用 TokenReview 看一个令牌在服务端被解析成什么样子。
不指定(默认):退出码 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: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,方便审计日志对应。