如何解決 Kubernetes 的多租戶難題

如何解決 Kubernetes 的多租戶難題

來自專欄 KubernetesMeetup 社區

原文作者:Jessie Frazelle

翻譯:夏天

技術校對:星空下的文仔

Kubernetes 是一種新內核(kernel)。與典型的操作系統內核相對應,我們可以將其稱為「集群內核」。對於嘗試部署應用程序的用戶來說,Kubernetes 非常棒。當然,我們依然面臨著以前在操作系統內核方面就曾面臨的許多挑戰。其中之一就是許可權隔離。在 Kubernetes 中,我們稱之為多租戶(multi-tenancy),或者一個集群中的多租戶隔離。

社區的多租戶工作組中關於多租戶模式問題的討論可謂經久不衰。 (如果你想查看這些 Google 文檔,你需要成為 kubernetes-wg-multitenancy Google 群組的成員。) 針對不同的模式問題,大家也給出了一些相應的建議。

Kubernetes 目前的租戶模式假定集群是安全邊界。你可以在 Kubernetes 之上構建 SaaS,但需要攜帶自己的可信 API,而不是使用 Kubernetes API。如果你想要安全地構建集群,那麼即使是在 SaaS 上你也需要考慮很多因素。

這篇文章我們關注的是「多租戶難題」(hard multi-tenancy)。租戶間互不信任,彼此認為對方是惡意的。多租戶的難點在於同一集群中的多租戶不能訪問其他租戶的任何內容。要解決這一難題,我們們首先就要讓安全邊界成為 Kubernetes namespace 對象。

多租戶模式難題尚未解決,但目前有一些建設性的建議。所有系統都有缺陷,沒有什麼是完美的。像 Kubernetes 這樣複雜而龐大的系統確實很容易受到攻擊。只要利用 Kubernetes 的一個漏洞得到管理員的全部許可權,那就全面崩潰了。系統安全和租戶間隔離不能被保證。接下來,我將在文章中介紹為什麼擁有多個安全層如此重要。

邏輯漏洞風險最高的攻擊面是 Kubernetes API,因此租戶之間必須進行隔離。遠程代碼執行風險最高的攻擊面是在容器中運行的服務,所以也必須進行多租戶隔離。

如果你看一看開源 repo 和 Kubernetes 的發展速度,就會發現 Kubernetes 與已佔據了 Windows,Mac OS X,Linux 和 FreeBSD 的宏內核有很多相似之處。幸運的是,目前已經有很多可以在宏內核(monolithic kernels)中實現許可權隔離的方案了。

在文中,我還提出了一個解決方案是內核嵌套(Nested Kernel):Intra-Kernel 隔離,即通過在宏內核中嵌入一個小內核來解決宏內核中許可權隔離的問題。

我們需要多個安全層

我們今天熟知的「沙箱」(sandboxes)被定義為具有多個安全層。例如,我為 contained.af playground 製作的沙箱具有由 seccomp,apparmor,kernel namespaces,cgroups,capabilities 和非特權 Linux 用戶定義的安全層,所有這些層不必重疊。如果用戶要使用 apparmor 或 seccomp bypass,並嘗試在容器內部調用 mount ,則 Linux 的 CAP_SYS_ADMIN 功能會阻止 mount 執行。

如果系統中存在一個漏洞,這些安全層可以確保它不至於影響整個系統。在解決 Kubernetes 中多租難題時也需要這個思路。這就可以解釋為什麼現有的所有建議都不夠完善。因為我們至少需要兩個安全層,而這些建議通常都只有一個。

要將 Intra-Kernel 隔離應用於 Kubernetes,我們需要兩個安全層。接下來我們進行更深入地探討。

通過 Namespace 隔離

現有的多租戶難題解決方案是把 Namespace 作為 Kubernetes 上多租戶的安全邊界。「Namespace」是由 Kubernetes 定義的。這些建議都有缺陷:如果你只利用 Kubernetes 的一部分,那麼你就可以擁有橫向擴展 Namespace 的許可權,因此可以橫向擴展租戶。

通過 Intra-Kernel 隔離,Namespace 仍然是安全邊界。但是,並非所有人都共享主要的 Kubernetes 系統服務,每個 Namespace 都擁有自己的「嵌套」 Kubernetes 系統服務。這意味著 api-server,kube-proxy 等都將單獨運行在該 Namespace 的一個 pod 中。部署到該 Namespace 的租戶將無法訪問實際的 root 級別 Kubernetes 系統服務,而只能訪問其 Namespace 中運行的那些服務。Kubernetes 中的一個漏洞不會讓整個系統崩潰,只會影響 Namespace。

另一個安全邊界是容器隔離本身。這些 pod 可能會被像例如 PodSecurityPolicy 和NetworkPolicy 這樣的現有資源進一步鎖定。隨著生態系統不斷地增長、創新,你甚至可以在容器之間運行虛擬機(katacontainers)進行硬體隔離,從而為集群中的服務提供最高級別保護。

對於那些熟悉 Linux Namespace 的人來說,你可以把它看作是一個克隆的 Kubernetes。他們的設計大致相似。

例如在 Linux 上克隆新的 Namespace 像這樣:

所以當你在 Intra-Kernel 隔離創建一個新的 Kubernetes Namespace 時,大致如下:

在 Linux 中,Namespace 控制進程是可見的。這適用於那些在 Kubernetes 中指定 Namespace 的用戶。由於每個 Namespace 都有自己的系統服務,因此所有的服務用戶都是可以看到的。

與上面的偽代碼不同,Kubernetes Namespace 將自動獲取每個系統服務的新組件。這更符合 Solaris Zones 或 FreeBSD Jails 的設計。

在我的博客文章《 Setting the Record Straight: Containers vs. Zones vs. Jails vs. VMs》中,我介紹了各種隔離技術之間的差異。在這個設計中,我們更接近於 Zones 或 Jails 的方法。容器配備了所有部件。Kubernetes 中的 Namespace 應該自動建立一個完全隔離的世界,就像 Zones 或 Jails 那樣,用戶不必擔心它們配置是否正確。

Linux 中 Namespace 的另一個問題是, Namespace 不是萬能的。這種設計可以確保 Kubernetes 的各個部分都是針對每個租戶進行隔離的。

通過資源控制隔離

上述設計仍然有一些尚未解決的問題。接下來我們來看看 Linux 中的另一個控制機制:Cgroups。Cgroups 控制流程是可行的,他們是資源控制的主人。

這個概念也適用於 Kubernetes Namespace。Cgroups 不像內存消耗和 CPU 那樣控制資源, 而是應用於節點(node)。一個 Namespace 內的租戶只能訪問指定的某些節點。所有的 Namespace 服務也將在機器級別被隔離。不同租戶的服務不會在同一台機器上運行。在未來這可能是一個設置,但默認情況下節點是不共享的。

該模型允許在我們的嵌套 API 伺服器在各個節點上指定使用一組 kubelet。

在這一點上,我們將租戶可以看到的東西(Kubernetes Namespace)和他們可以使用的東西(指定給 Namespace 的節點)進行隔離。

或者,如果 Namespace 的系統服務與嵌套的虛擬容器(katacontainers)隔離,並且你考慮了此設計文檔(docs.google.com/documen)中列出的所有其他變數。那麼,那些服務就可以共享節點。與上面的方法相比,這種方法在資源利用率方面表現更好。如下所示:

如果更進一步,像這個文檔(docs.google.com/documen)所說,隔離整個系統,將容器放進完全沙盒或者 VM 容器裡面,那麼所有服務都可以共享節點,這將進一步提高資源利用率。

跨越多個 Namespace 的租戶

工作組曾經幾次提出租戶可能需要跨越多個 Namespace 的問題。雖然我不覺得這應該是一個默認設置,但我看不到它有什麼問題。

我們再來看看 Namespace 在 Linux 中的工作方式以及我們是如何將它們用於容器中。每個 Namespace 都是一個文件描述符。你可以通過為想要共享的 Namespace 指定文件描述符,然後調用系統的 setns 函數的方式來在容器之間共享 Namespace。

在 Kubernetes 中,我們可以實施相同的方案。一個 superuser 可以指定一個 Namespace,讓有權訪問該 Namespace 的租戶可以實現共享。

總的來說,這個方案使用了內核隔離技術的以往的專業知識,並從過去的內核隔離技術中汲取了經驗教訓。

隨著 Kubernetes 生態系統的不斷擴大的,在租戶之間建立多個安全層是非常重要的。諸如故障安全默認設置,完全控制,最低許可權和最少通用機制等安全技術非常流行,但很難應用於宏內核。Kubernetes 默認共享一切,並且各不相同,它的驅動程序和插件,就像操作系統內核一樣。將相同的內核隔離技術應用於 Kubernetes 將是更好的許可權隔離解決方案。

這為我們帶來了什麼?

我們已經用完全隔離這種我們非常擅長的方式解決了我們的威脅模型。邏輯漏洞風險最高的攻擊面即 Kubernetes API 具有完全的邏輯分離,因為每個租戶都有自己的邏輯漏洞。遠程代碼執行風險最高的攻擊面(容器本身)與其他租戶完全虛擬化分離。這種隔離要麼通過指定的節點本身隔離到租戶,要麼通過運行使用硬體隔離的容器來隔離。其他租戶唯一可行的途徑是在某些服務中獲得遠程代碼執行,然後突破容器(和/或 VM)的限制。

通過節點資源控制進行的 Intra-Kernel 隔離(如第一個圖所示)與由一個 superuser 操作的兩個完全分離的集群是相同的。由於節點是為每個租戶指定的,因此大家的資源利用率都不會太高。

具有最高資源控制收益的模型可以安全地設置你的集群,以將嵌套虛擬機用作容器,或者將容器本身完全沙箱化,以使邊界是容器而不是節點。這減輕了運營商運行多個集群的痛苦,並且可以更有效地使用資源,同時還可以維持多層安全。

上面這些解決方案都不是一成不變的。這只是我解決這個問題的淺見。如果您對 Kubernetes 或其他方面的多租戶問題感興趣,請加入工作組。我期待在那裡與您進行更多討論。謝謝!

原文鏈接:medium.freecodecamp.org


推薦閱讀:

人工智慧新硬體,打開群體智能大時代
雲資料庫SQL Server 2008 R2版推出OSS版本數據上雲
從摩拜單車的雲技術看物聯網與雲計算的關係
雲計算:敢問路在何方
oVirt安裝配置——第二章(oVirt節點篇)

TAG:雲計算 | OpenStack | Kubernetes |