北美时间11月26日,Kubernetes爆出严重安全漏洞,该漏洞由Rancher Labs联合创始人及首席架构师Darren Shepherd发现。该漏洞CVE-2018-1002105(又名Kubernetes特权升级漏洞,https://github.com/kubernetes/kubernetes/issues/71411 )被确认为严重性9.8分(满分10分),恶意用户可使用Kubernetes API服务器链接到后端服务器以发送任意请求,并经过API服务器的TLS凭证进行身份验证。这一安全漏洞的严重性更在于它能够远程执行,攻击并不复杂,不须要用户交互或特殊权限。git
漏洞被发现并验证后,Kubernetes快速响应并已经发布了修补版本v1.10.十一、v1.11.五、v1.12.3和v1.13.0-rc.1。仍在使用Kubernetes v1.0.x至Kubernetes v1.9.x版本的用户,被建议即刻中止并升级到修补版本。github
本文由该漏洞的发现者、Rancher Labs联合创始人及首席架构师Darren Shepherd所写。他描述了本身发现这一漏洞的完整通过,剖析了问题的机制与原理,并分享了相应的解决方案以及他本人对Kubernetes、对开源社区的见解。golang
Rancher Labs联合创始人及首席架构师 Darren Shepherd,同时也是Docker生态核心组织Docker治理委员会(DGAB)的全球仅有的四位我的顶级贡献者之一。web
Amazon ALB的问题后端
这一切都始于2016年,当时Rancher Labs刚发布了Rancher 1.6。2016年年中的时候,亚马逊发布了ALB,这是一个新的HTTP(7层)负载均衡器。ALB的设置比ELB容易得多,所以咱们会建议用户使用ALB。随后很快,咱们开始收到有关ALB后端设置失败的报告,不少随机请求只会获得40一、40三、40四、503的报错。然而,Rancher Labs的团队没法重现这些错误,咱们从社区成员那里获得的日志都没有无法成为参考。咱们看到了HTTP请求和响应,但没法将其与代码相关联。那个时候,咱们只好认为是由于ALB发布不久、产品自己可能存在些错误。除了ALB,咱们以前从未遇到任何其余负载均衡器的问题。所以那时,咱们只得最终告诉用户不要使用ALB。api
时间到了今年8月,又有Rancher社区成员向Rancher 2.1提交了一样的问题(https://github.com/rancher/rancher/issues/14931)。仍和之前同样,使用ALB会致使奇数401和403错误。这极大地引发了个人关注,由于Rancher 1.x和2.x之间没有共同的代码,并且ALB如今应该也已经至关成熟了。反复深刻研究后,我发现问题与不处理非101响应和反向代理缓存TCP链接有关。若您想要真正理解这个问题,您必须了解TCP链接重用、websockets如何使用TCP链接以及HTTP反向代理。缓存
TCP链接重用安全
在一种很是天真的HTTP方法中,客户端将打开TCP socket,发送HTTP请求,读取HTTP响应,而后关闭TCP socket。很快你就会发现你花了太多时间打开和关闭TCP链接。所以,HTTP协议具备内置的机制,以便客户端能够跨请求重用TCP链接。服务器
WebSocketswebsocket
Websockets是双向通讯,其工做方式与HTTP请求/响应流不一样。为了使用websockets,客户端首先会发送HTTP升级请求,服务器会以HTTP 101 Switch Protocols响应来响应这一请求。收到101以后,TCP链接将专用于websocket。在TCP链接的剩余生命周期中,它是被认为是专用于该websocket链接的。这就意味着此TCP链接永远不会被从新使用。
HTTP反向代理
HTTP反向代理(负载均衡器是一种反向代理)从客户端接收请求,而后将它们发送到不一样的服务器。对于标准HTTP请求,它只写入请求,读取响应,而后将响应发送到客户端。这种逻辑至关直接,并且Go也包含一个内置的反向代理:https://golang.org/pkg/net/http/httputil/#ReverseProxy。
相比之下Websockets就复杂一点。对于websocket,你必须查看请求,看到它是一个升级请求,而后发送请求,读取101响应,而后劫持TCP链接,而后开始来回复制字节。对于反向代理,它不会在此以后查看链接的内容,它只是建立一个“废弃管道”。标准Go库中不存在此逻辑,许多开源项目都编写了代码来执行此操做。
错误所在
关于错误所在,太长不看版的解释是,Kubernetes在启动“废弃管道”以前没有检查101响应。在代码的防护中,不检查101是挺常见的。(这也是咱们上文所说的Rancher用户会发现的Rancher 1.x和Rancher 2.x的问题的缘由,即便Rancher 1.x和Rancher 2.x使用的是完成不一样的代码。)错误的场景以下:
客户端发送websocket升级请求
反向代理向后端服务器发送升级请求
后端服务器以404响应
反向代理启动复制循环并将404写入客户端
客户端看到404响应并将TCP链接添加到“空闲链接池”
在这种状况下,若是客户端从新使用TCP链接,它将向TCP链接写入请求,它将经过反向代理中的“废弃管道”并将其发送到前一个后端。一般这不会很糟糕,例如在负载均衡器的状况下,由于全部请求都会转到同一组同类后端。可是,当反向代理是智能的,而且是由其执行身份验证、受权和路由(即Kubernetes所作的所有工做)时,就会出现此问题。
安全漏洞
由于101未被处理,因此客户端最终使用TCP链接,该链接是对某些先前访问的后端服务的“废弃管道”。这将致使特权升级。问题是,Kubernetes将仅在反向代理中执行许多请求的受权。这意味着若是我执行一个受权失败的websocket请求路由到一个kubelet,我能够保持与该kubelet的持久链接,而后运行我选择的任何API命令,不管我是否被受权。例如,您能够在任何pod上运行exec并复制出secrets。所以,在这种状况下,已经受权的用户基本上能够得到对kubelet的彻底API访问(一样的事情适用于经过kube-aggregation运行的服务)。
当您添加另外一个反向代理时,会出现另外一个问题。在这种状况下,您将HTTP负载均衡器放在Kubernetes API(非4层负载均衡器)以前。若是执行此操做,那个经过了身份验证的、运行着“废弃管道” 的TCP链接,将会被添加到一个任何用户均可以访问的空闲池中。那么,用户A建立了TCP链接,以后用户B仍可从新使用该链接。这样一来,未通过身份验证的用户就能够访问您的Kubernetes集群了。
此时你可能会感到恐慌,由于固然每一个人都会在kube-apiserver前放置一个负载均衡器。唔……首先,您必须运行HTTP负载均衡器,而不是TCP负载均衡器。负载均衡器必须了解HTTP语义才能产生此问题。其次,幸运的是大多数反向代理并不关心101个回复。这就是为何这个问题其实(在很多开源项目中)存在已久而未被发现的缘由。大多数负载均衡器在看到升级请求而非101响应后不会重用TCP链接。因此,若是您会受到这一漏洞的影响,那么您的Kubernetes设置应该已经不可靠了,您应该能看到随机失败或没法完成的请求。至少我知道ALB就是这样工做的,因此你升级到了已修补该漏洞的Kubernetes版本以前,不要使用ALB。
简而言之,Kubernetes的这一安全漏洞会容许具备正确权限的任何通过身份验证的用户得到更多权限。若是您正在运行硬件多租户集群(内含不受信任的用户),您确实应该担忧而且及时应对。若是您不担忧用户主动互相攻击(大多数多租户集群都是这样),那么不要惊慌,只需升级到已修补该漏洞的Kubernetes版本便可。最坏的状况,若是真的有未经身份验证的用户能够进入您的集群,您的负载均衡器也有可能会阻止这种状况。只要不是将API暴露给世界,而且有在其上放置一些适当的ACL,也许你的集群也仍是安全的。
Rancher为Kubernetes保驾护航
对于使用Rancher Kubernetes平台的用户,大家更无须紧张。
对于把集群部署在内网的用户,彻底不须要过于担忧此问题,由于外部没法直接入侵。
经过Rancher2.0或RKE部署的kubernetes集群的用户一样不用过于担忧。由于经过Ranche2.0或RKE部署的集群默认是禁止和匿名用户访问。针对经过pod exec/attach/portforward权限提权问题,目前Kubernetes发布通用的修复方法是经过升级到指定Kubernetes版原本修复,针对此Rancher也已经发布修复程序,具体修复方法请参考:https://forums.rancher.com/t/rancher-security-advisory-kubernetes-cve-2018-1002105/12598
感谢开源
我深入地感到,此次Kubernetes的这个安全漏洞的最初发现、修复和最终交付,证实了开源社区强大的生命力。我第一次发现这个问题,也是由于Rancher的非付费开源用户给予咱们的反馈。事实上,咱们已经确认了这一问题并无影响Rancher 2.x的付费客户,由于Rancher的HA架构刚好否认了ALB的行为,但咱们仍是去研究并解决了这个问题,由于咱们太爱咱们的开源用户了。也正是在研究和修复这个问题的过程当中,我发现了Kubernetes自身存在的安全隐患,并经过已创建的安全公开流程向Kubernetes社区反馈了该问题。