Kata Containers創始人王旭:安全容器導論

支付寶技術團隊發表於2019-12-30
從2015年5月初開始創業開發 HyperContainer (runV) 到現在,也快五年了,在這個時候還來寫一篇什麼是安全容器,顯得略有尷尬。不過,也正是經過這五年,越來越多到人開始感到,我需要它卻說不清它,這個時候來給大家重新解釋 “安全容器” 也正是時候。

緣起:安全容器的命名

Phil Karlton 有一句名言——

電腦科學界只有兩個真正的難題——快取失效和命名。

就容器圈而言,我相信命名絕對配得上這句話,這毫無疑問是一件讓老開發者沉默,讓新人落淚的事情。

僅就係統軟體而言,我們當今比較通行地稱為 Linux 容器(LinuxContainer)的這個概念,曾經用過的名字大概還有——jail, zone, virtualserver, sandbox... 而同樣,在早期的虛擬化技術棧裡,也曾經把一個虛擬機器環境叫做容器。畢竟這個詞本身就指代著那些用來包容、封裝和隔離的器物,實在是太過常見。以至於,以嚴謹著稱的 Wikipedia 裡,這類技術的詞條叫做“系統級虛擬化”,從而回避了“什麼是容器”這個問題。

當2013年 Docker 問世之後,容器這個概念伴隨著“不可變基礎設施”、“雲原生”這一系列概念,在隨後的幾年間,以摧枯拉朽之勢顛覆了基於“軟體包+配置”的細粒度組合的應用部署困境,用簡單地宣告式策略+不可變容器就清爽地描述了軟體棧。應用怎麼部署似乎離題了,我們這裡想要強調的是——

雲原生語境下的容器,實質是“應用容器”——以標準格式封裝的,執行於標準作業系統環境(常常是Linux ABI)上的應用打包——或執行這一應用打包的程式/技術。

這個定義是我在這裡寫下的,但是它並不是我的個人意志,這是基於 OCI (Open ContainerInitiative) 規範這一共識的,這個規範規定了容器之中的應用將被放置在什麼環境中,如何執行,比如啟動容器根檔案系統上的哪個可執行檔案,用什麼使用者,需要什麼樣的 CPU、記憶體資源,有什麼外接儲存,有什麼樣的共享需求等等。

有了這一共識做基礎,我們來說安全容器,這又是一段命名血淚史。當年,我的聯合創始人趙鵬是用“虛擬化容器”命名的我們的技術的,為了搏人眼球,用了“Secure as VM, Fast asContainer”的大字標語,自此,被容器安全性問題戳中心坎的人們立刻用“Secure Container”來稱呼這類東西,一發而不可收。而我們的內心中,這項技術提供了一層額外的隔離,隔離可能意味著安全性中的一環,也意味著某些運維效率、某些最佳化可能或者其他的功能。實際上,給安全容器這樣的定義更合理——

一種執行時技術,為容器應用提供一個完整的作業系統執行環境(常常是LinuxABI),但將應用的執行與宿主機作業系統隔離開,避免應用直接訪問主機資源,從而可以在容器主機之間或容器之間提供額外的保護。

 

間接層:安全容器的精髓

安全問題的唯一正解在於允許那些(導致安全問題的)Bug發生,但透過額外的隔離層來阻擋住它們。

—— LinuxCon NA 2015, Linus Torvalds

為了安全,為什麼要引入間接層?因為以 Linux 之類的目前主流宿主機作業系統的規模,是無法從理論上驗證程式是沒有 Bug 的,而一旦合適的 Bug 被合適地利用,安全性風險就變成了安全性問題了,框架和修補並不能確保安全,所以,進行額外的隔離、縮減攻擊面,就成了緩解安全問題的法寶——我們不能確保沒有漏洞,但我們透過組合來減少漏洞被徹底攻破的風險。


Kata: 雲原生化的虛擬化

2017年12月,我們在 KubeCon上對外發布了 Kata Containers 安全容器專案,這個專案的兩個前身——我們發起的的 runV 和Intel 發起的 Clear Container 都釋出於2015年5月(是的,早於上面 Linus 的引語)。這組專案的思路很簡單 ——

1. 作業系統本身的容器機制沒辦法解決安全性問題,需要一個隔離層;

2. 虛擬機器是一個現成的隔離層,AWS這樣的雲服務已經讓全世界相信,對戶來說,"secure of VM" 是可以滿足需求的;

3. 虛機裡面只要有個核心,就可以支援 OCI 規範的語義,在核心上跑個 Linux 應用這並不太難實現;

4. 虛機可能不夠快,阻礙了它在容器環境的應用,那麼可不可以擁有 "speed of container" 呢?

現在,如果最後一個問題可以解決,那麼它就是我們要的“安全的容器”了——這就是 Kata Containers。

目前 Kata Containers 通常是在 Kubernetes 環境中使用的,Kubelet 透過CRI 介面讓 containerd 或 CRI-O 執行執行時操作,通常映象操作由這些 CRI Daemon 來進行,而根據請求,把 Runtime 操作寫成一個 OCI Spec 交給 OCI Runtime 執行。這裡,對於 1.2 以上的 containerd 和 1.5 版本上後的 Kata Containers(對應 ),通常是利用 containerd 來完成的:

  • 每個 Pod 會有一個 shim-v2 程式來為 containerd/CRI-O 執行各種執行時操作,這個程式和整個 Pod 的生命週期一致,透過一個 ttRPC 介面為 containerd/CRI-O 提供服務;
  • Shim-v2 會為 Pod 啟動一個虛擬機器作為 PodSandbox提供隔離性,其中執行著一個 Linux 核心,通常這個 Linux 核心是一個裁剪過的核心,不會支援沒有必要的裝置;
  • 這裡用的虛擬機器可以是 Qemu 或是 Firecracker,如果是 Firecracker,那麼根本就沒有模擬的裝置,而如果是 Qemu,透過配置和補丁,也會讓它儘量小一些,支援的其他虛擬機器還包括 ACRN 和 cloud-hypervisor,未來後者可能會被越來越多的用到;
  • 這個虛擬機器在啟動的時候可能根本就是一個 initrd 而沒有完整作業系統,或者有個極小的作業系統,總之,它完全不是按照一臺模擬機的作業系統來配置的,它只是支撐容器應用執行的基礎設施,以及相關的應用環境 Metrics 採集或應用跟蹤除錯需要的資源;
  • 容器本身的 rootfs 會在 Sandbox 啟動之後,在收到 contaienrd/CRI-O 的建立容器的 OCI 請求之後,以熱插拔的方式動態插入到虛機中,容器的 rootfs 準備和虛機本身的啟動是可以並行的;
  • 依照 CRI 語義和 OCI 規範,Pod 裡可以啟動多個相關聯的容器,它們被放在同一個虛機裡,並且可以互相共享 namespace;
  • 外來的儲存卷可以以塊裝置或檔案系統共享的方式插入到 PodSandbox 中,但對於 Pod 裡的容器來說,它們都是載入好的檔案系統,目前開始逐漸普及的檔案系統方式是專為 Kata 這樣的場景設計的 virtio-fs,它不僅比傳統的 9pfs 更快、有更完整的 POSIX 檔案系統的支援,而且藉由所謂 vhost-user 和 DAX 技術,它還可以在不同的 Pod 之間共享相同儲存內容的快取頁 (page-cache),讓它們可以和普通的 runC 容器一樣,節約寶貴的記憶體;
  • 對於網路,使用 tcfilter,可以直接支援各種 CNI 的外掛來提供容器網路,這樣的好處是無需做什麼調整就自然的工作,但是效率上因為做一次橋接會有損失,在生產環境中,也可以考慮使用 enlightened 網路模式,用一個特製的 CNI 外掛來高效接入容器網路。

可以看到,首先 Kata Containers 是個全功能的容器執行時引擎,它用起來完全不像是傳統虛機,分明就是個容器引擎,並且,透過“少用不必要的記憶體”和“共享能共享的記憶體”來降低記憶體的開銷,更小的記憶體不僅開銷更小,啟動也更輕快,對於大多數場景來說,這實現了"secure of VM, speed of container"。在安全性之外,它比起傳統的虛機,更具有容器的彈性,更少了機器的那種物理操作手感,我們把這種技術稱為 “雲原生化虛擬化”或者 “面向雲原生的虛擬化”技術。

 

gVisor: 程式級虛擬化

在 Kata Containers 之後半年的哥本哈根KubeCon 上,Google 開源了他們內部開發了五年的 gVisor 安全容器作為回應。

如果說 Kata Containers 是對透過對有隔離技術進行組合和改造來構建容器間的隔離層的話,gVisor 的設計顯然是更加簡潔的——gVisor 是一個用 Go 語言重寫的執行在使用者態的作業系統核心,稱為 Sentry,它並不依賴於虛擬機器,相反,它藉助“平臺(Platform)”的能力,讓宿主機把應用的所有訪問都重新轉交給 Sentry,在 Sentry 中處理後再將一些必要的操作請宿主機幫忙來完成。

可以說 gVisor 在做的是一個純粹的面向應用的隔離層,從 Linux ABI 到 Linux ABI 的“過濾器”。全新寫作的優勢在於不需要遷就太多已有技術棧的桎梏,可以寫得更輕,啟動肯定也會更快,事實上,資源的伸縮也更方便,或者說更容器一些。好多作業系統圈的朋友都毫不掩飾地說,他們更喜歡 gVisor 的架構,如果能解決一些目前不容易解決掉的問題的話。

gVisor 作為隔離層,它的安全性依據在於:

  • 首先是攻擊面變小,宿主作業系統將只為沙箱裡的應用執行大約20%的 Linux 系統呼叫。透過研究,gVisor 的作者們發現,大多數攻擊都是透過一些不常用系統呼叫中的缺陷進行的,不常用的系統呼叫的實現路徑一般也比較少被審閱,相對於那些熱路徑來說,安全性要更差一些,gVisor 的設計讓應用對那些不常用系統呼叫的訪問根本不會落到宿主機作業系統核心上,從而避免了大部分的攻擊;
  • 其次是他們發現了最最常被攻擊到的系統呼叫是 open(),於是他們直接將真有必要的 open()呼叫交給了一個專門的稱為 Gopher 的程式來執行,從而可以更容易被限制、審計和管控;
  • 最後,他們是用高階語言 Go 寫的核心,優勢當然是更加記憶體安全,當然,他們也坦誠,這個語言其實不太“系統級”,他們為此不得不做了很多手腳,也為 Go Runtime 貢獻了很多修改。

當然,gVisor 的架構是很漂亮,但重新實現一個核心這件事情,除了 Google 這樣的巨頭恐怕也沒有幾家可以做(類似的基本做到的也就是微軟的初代 WSL了),而且這個超前的設計還是有些現實問題:

  • 首先,就是它不是 Linux,所以,在相容性方面和 Kata 這樣的解決方案尚有差距;
  • 其次,對於當前的 Linux 系統呼叫方式和 CPU 指令系統,每個系統呼叫的攔截都會有相當的效能開銷,儘管全棧最佳化可以有一定緩解,但對系統呼叫比較多的場景來說,效能損失無法忽略。

所以,短時間內 gVisor 方案並不能成為一個終極解決方案,當然,它不僅可以適應一些特定的場景,而且帶來的啟示性可能對未來的作業系統乃至 CPU 指令集的演進發生作用,從而推動我們可以擁有一個更完美的安全容器解決方案。

 

安全容器:不止於安全

安全容器的隔離層讓應用的問題——不論是惡意攻擊,還是意外錯誤——都不至於影響宿主機,也不會在不同的 Pod 之間相互影響。而且實際上,額外隔離層帶來的影響並不僅是安全,對於排程、服務質量和應用資訊的保護都有好處。

傳統的作業系統容器技術是核心程式管理的一個延伸,容器程式本身是一組關聯的程式,對於宿主機的排程器來說是完全可見的,一個 Pod 裡的所有容器或程式,同時也都被宿主機排程和管理。這就意味著,在有大量容器的環境下,宿主機核心的負擔很重,在很多實際環境中已經可以觀察到這個負擔帶來的開銷了。而採納安全容器之後,從宿主機上是看不到這些完整的資訊的,隔離層同時也降低了宿主機的排程開銷,減少了維護負擔,避免了容器之間、容器和宿主機之間的服務質量干擾。從另一個方向看,安全容器作為一道屏障,可以讓宿主機的運維管理操作不能直接訪問到應用的資料,這樣,把使用者的應用資料直接保護在沙箱裡就可以降低對使用者的授權要求,保障使用者的資料私密性。

當我們的目光向投向未來,可以看到,安全容器不僅僅是在做安全隔離,因為安全容器隔離層的核心,相對於宿主機的核心是獨立的,專門對應用服務,從這個角度說,主機/應用的功能之間做合理的功能分配和最佳化,展現出讓人期待的潛力,將來的安全容器,可能不僅是隔離性開銷的降低,甚至是提升應用的效能——

隔離,讓雲原生基礎設施更完美。


Kata Containers開源地址:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69904796/viewspace-2671176/,如需轉載,請註明出處,否則將追究法律責任。

相關文章