北美時間11月26日,Kubernetes爆出嚴重安全漏洞,該漏洞由Rancher Labs聯合創始人及首席架構師Darren Shepherd發現。該漏洞CVE-2018-1002105(又名Kubernetes特權升級漏洞,https://github.com/kubernetes...)被確認爲嚴重性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/ra...)。仍和之前同樣,使用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/ht...。
相比之下Websockets就複雜一點。對於websocket,你必須查看請求,看到它是一個升級請求,而後發送請求,讀取101響應,而後劫持TCP鏈接,而後開始來回複製字節。對於反向代理,它不會在此以後查看鏈接的內容,它只是建立一個「廢棄管道」。標準Go庫中不存在此邏輯,許多開源項目都編寫了代碼來執行此操做。
錯誤所在
關於錯誤所在,太長不看版的解釋是,Kubernetes在啓動「廢棄管道」以前沒有檢查101響應。在代碼的防護中,不檢查101是挺常見的。(這也是咱們上文所說的Rancher用戶會發現的Rancher 1.x和Rancher 2.x的問題的緣由,即便Rancher 1.x和Rancher 2.x使用的是完成不一樣的代碼。)錯誤的場景以下:
在這種狀況下,若是客戶端從新使用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/...
感謝開源
我深入地感到,此次Kubernetes的這個安全漏洞的最初發現、修復和最終交付,證實了開源社區強大的生命力。我第一次發現這個問題,也是由於Rancher的非付費開源用戶給予咱們的反饋。事實上,咱們已經確認了這一問題並無影響Rancher 2.x的付費客戶,由於Rancher的HA架構剛好否認了ALB的行爲,但咱們仍是去研究並解決了這個問題,由於咱們太愛咱們的開源用戶了。也正是在研究和修復這個問題的過程當中,我發現了Kubernetes自身存在的安全隱患,並經過已創建的安全公開流程向Kubernetes社區反饋了該問題。