一个功能直接调用了 k8s 的 API, 在集群从 1.5 升级到 1.6 后突然报 403, 错误信息是
system:anonymous 用户对相应的资源没有权限
关于匿名请求
什么是 system:anonymous
用户? 这是 k8s 给没有被其它验证方法所拒绝的匿名请求分配的一个用户, 并且它属于 system:unauthenticated
这个组。
例如, apiserver 配置了 token 验证, 并且允许匿名请求。一个带了 bearer token 然而不能通过验证的请求会收到 401 Unauthorized
。一个没有带 token 的请求则被视为匿名请求。
继续 debug
出问题的 API 是通过 basic auth 的方式调用的, 并且以 username:password
的形式写在 url 里。 集群升级前, 能够通过验证, 但升级后却无法通过验证, 并且成为了一个匿名请求。
查阅相关的文档, 发现匿名请求在 1.5.1-1.5.x 是默认关闭的, 而在 1.6+ 则默认开启。因为 1) 无法通过验证, 2) 匿名请求被允许, 所以才收到了 403。但为什么升级了集群, 验证就无法通过了呢。
分析新旧集群请求的差异, 发现旧集群上, 验证也不是一次通过的。是第一次请求收到了 401, 然后第二次请求才通过。并且第二次请求带有 basic auth 的 header, 而前者则没有。这下问题很明确了, username:password
写在 url 里是无法被 api-server 所解析的, 在旧集群上, 匿名请求不被允许, 所以收到 401, 浏览器(猜测)看到 401, 于是把验证信息放到 header 里再发了一个请求, 这一次验证通过了~~ 在新集群上, 由于第一次请求返回了 403, 所以浏览器也不会再去尝试一次了。
归根结底,这还是之前使用 username:password
写在 url 里这种验证方式埋下的坑。这种方式已经被废弃, server 不解析也是合情合理的~
网友评论