KubeCube 迎来了 v1.1 版本的发布,新增了 OAuth2 的 GitHub 登录支持、租户配额的算法优化、Warden 热插拔安装包的本地和远端拉取支持等新的特性,也修复了若干已知问题,详见 ChangeLog。
v1.1 版本中最主要的特性是 Auth-Proxy 能力的支持,使得部署更加轻量,无需侵入修改 kube-apiserver 的配置。用户可以使用 RESTful、client-go、kubectl 等方式访问被 KubeCube 纳管的 K8s 集群,享受统一的认证能力。
在 KubeCube v1.1 版本之前,KubeCube 使用 K8s 提供的 Auth-Webook 方式来拓展认证能力,该方式通过为 kube-apiserver 指定认证后端来达到认证拓展的目的,kube-apiserver 会使用认证 Webhook 返回的 UserInfo 去进行下一步的鉴权流程。
该方式虽然能够使用 K8s 原生的方式拓展认证能力,但是在实际使用中存在一定的不足。如 Issues#62 中所指出的,该方式需要修改 kube-apiserver 的启动参数,为其指定额外的认证 Webhook 后端,当我们的 K8s 集群是多 Master 节点的高可用集群时,需要修改每一个 Master 节点的 kube-apiserver 的配置,这在很多场景几乎是无法接受的。另外在一些云厂商的托管 K8s 场景下,往往只对用户提供工作节点,此时想修改 kube-apiserver 的配置是非常困难的。
对于 Auth-Webhook 面临的困境,我们设计了 Warden-Auth-Proxy 模块来解决问题。Warden-Auth-Proxy 即 K8s 集群的认证代理,它对外提供了类似 kubectl proxy
的代理能力。不同的是,它会解析 request 中的 Bearer Token 为 UserInfo,然后使用 K8s 的 impersonation 能力进行用户伪装。
值得一提的是,Auth-Proxy 模块之所以集成在作为 Cluster Agent 的 Warden 中,而不是集成在管控集群的 KubeCube 中,是因为在设计上希望做到两点:
Auth-Proxy 的原理并不复杂,但是在实现中,需要注意以下几个问题:
对于代理 kubectl exec
的场景,使用普通的 HTTP 代理并不可行,究其原因是因为通信协议不匹配。
不同于其他的 HTTP RESTful 请求,kubectl exec
命令实际是使用的 SPDY 协议,SPDY 协议是 google 开发的 TCP 会话层协议, SPDY 协议中将 HTTP 的 request/response 称为 Stream,并支持 TCP 的链接复用,同时多个 stream之间通过 stream-id 来进行标记,简单来说就是支持在单个链接同时进行多个请求响应的处理,并且互不影响 。
在代理 kubectl exec
请求时,需要 Upgrade HTTP 协议,即通过 101(switching protocal) 状态码切换至 SPDY 协议来继续与下游服务通信。
func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// 尝试协议 upgrade
if h.tryUpgrade(w, req) {
return
}
if h.UpgradeRequired {
h.Responder.Error(w, req, errors.NewBadRequest("Upgrade request required"))
return
}
...
// 构建 golang 经典的 ReverseProxy
proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: h.Location.Scheme, Host: h.Location.Host})
proxy.Transport = h.Transport
proxy.FlushInterval = h.FlushInterval
proxy.ErrorLog = log.New(noSuppressPanicError{}, "", log.LstdFlags)
if h.Responder != nil {
proxy.ErrorHandler = h.Responder.Error
}
proxy.ServeHTTP(w, newReq)
}
对于使用 kubeconfig 与集群通信的场景,默认的 kubeconfig 中的 cluster server
的地址往往直接指向 kube-apiserver,这使得用户与集群的通信没有经过 Warden-Auth-Proxy 代理。
因此,对于上述场景,我们需要在 kubeconfig 上做文章。KubeCube 提供下载 kubeconfig 的能力,使用当前 user 下载的 kubeconfig,包含了 user 的访问凭证,包含了该 user 所能访问的所有 cluster 的 context,user 可以自行切换 context 来对 KubeCube 纳管的集群进行访问。KubeCube 通过改写 kubeconfig 中的 kube-apiserver 地址为 Warden-Auth-Proxy 地址来使得用户通过该 kubeconfig 执行的 kubectl 或 client-go 请求会被 Warden-Auth-Proxy 所代理。
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: {member_1_cluster_ca_data}
server: {member_1_warden_auth_proxy_addr}
name: member-1
- cluster:
certificate-authority-data: {pivot_cluster_ca_data}
server: {pivot_warden_auth_proxy_addr}
name: pivot-cluster
contexts:
- context:
cluster: member-1
user: member-1-admin
name: member-1-admin@member-1
- context:
cluster: pivot-cluster
user: pivot-cluster-admin
name: pivot-cluster-admin@pivot-cluster
current-context: member-1-admin@member-1
kind: Config
users:
- name: member-1-admin
user:
token: {user_token}
- name: pivot-cluster-admin
user:
token: {user_token}
在对通信安全有较高要求的场景下,我们需要保证从 Client——>Warden-Auth-Proxy——>kube-apiserver
的通信链路是加密的,可靠的。我们使用以下方式加以保证:
insecure-skip-tls-verify
跳过,在后续版本中,会增加对 TLS 能力的支持。未来我们会持续提供更多功能,帮助企业简化容器化落地。也欢迎大家参与贡献,提出宝贵的建议。添加以下微信进入 KubeCube 交流群。
作者简介: 蔡鑫涛,网易数帆轻舟容器平台资深开发,KubeCube Committer