Security Issues of Kubelet HTTP(s) Server
1. 认证介绍
Kubelet 在 10250 端口上提供了一个 HTTPS 的 API,通过这个 API 可以控制 Pods。Kubelet 对此 API 设置了几种认证方式,通过--authorization-mode
指定:
- ABAC (Attribute-Based Access Control)
- RBAC (Role-based access control)
- Webhook
- Node
- AlwaysAllow(不指定
--authorization-mode
时的默认值) - AlwaysDeny
在 Kubelet 的老版本(1.5 之前)不支持认证和授权,这就导致攻击者可以通过访问 10250 端口的 API 来获取容器权限。
2. 容器内命令执行
通过 /runningpods
获取正在运行的 Pod 列表:
需要的几个参数:namespace、pod_name 和 container_name。接着利用这几个参数请求 /run
:
即可在容器中运行任意命令,或者控制容器。
3. 信息泄漏
Kubelet HTTP API 源码文件在 /pkg/kubelet/server/server.go,代码如下:
ws.
Path(logsPath)
ws.Route(ws.GET("").
To(s.getLogs).
Operation("getLogs"))
ws.Route(ws.GET("/{logpath:*}").
To(s.getLogs).
Operation("getLogs").
Param(ws.PathParameter("logpath", "path to the log").DataType("string")))
s.restfulCont.Add(ws)
调用 getLogs
方法,接着调用 ServeLogs
:
func (kl *Kubelet) ServeLogs(w http.ResponseWriter, req *http.Request) {
// TODO: whitelist logs we are willing to serve
kl.logServer.ServeHTTP(w, req)
}
定位到:
func (kl *Kubelet) Run(updates <-chan kubetypes.PodUpdate) {
if kl.logServer == nil {
kl.logServer = http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))
}
if kl.kubeClient == nil {
glog.Warning("No api server defined - no node status update will be sent.")
}
实际上就是启动了一个 FileServer
,目录为 /var/log
。所以可以通过访问 /logs
来列出 /var/log
的目录,会造成一些信息泄露的问题。
另外如果挂载了 /var/log
到容器内的话,可以通过在容器内创建软链接到 /
,再利用 /logs
即可读取容器外的任意文件。不过在实际环境中我暂时还没有遇到过(难受)。
参考
- https://github.com/kayrus/kubelet-exploit
- https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/server.go