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

從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開源地址:

https://katacontainers.io/

發佈了138 篇原創文章 · 獲贊 611 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章