@@ 5,7 5,7 @@
\section{設計需求}
-本研究目標設想的 Kubernetes-as-a-Service 可以藉由 CScloud 的想法衍生改良,保留其共用叢集、基於 Kubernetes Namespace 的多租戶設計以及透過串接既有單一登入服務簡化身份驗證實做的特色,重新設計架構並著重於改善下列兩點:
+為達成本研究目標設想的 Kubernetes-as-a-Service,我們將 CScloud 的想法衍生改良,保留其共用叢集、基於 Namespace 的多租戶設計以及透過串接既有單一登入服務簡化身份驗證實做的特色,重新設計架構並著重於改善下列兩點:
\begin{onehalfspacing}
\begin{itemize}
@@ 14,18 14,17 @@
\end{itemize}
\end{onehalfspacing}
-% 這看要不要往下丟到 propose 設計本身
-由於架構變更,使得平台上自行撰寫的元件必須重新實做。以此為契機,我們採用可上線運行的高標準撰寫,並且著重其完備性,而非僅只進行機制的概念驗證。在實做過程中,我們也反覆審視此架構下對於使用者體驗的影響,並且透過擴展網頁界面功能以其他方式彌補。
+由於架構變更,使得平台上自行開發的元件必須重新實做。以此為契機,我們將採用可上線運行的高標準撰寫,並且著重其完備性,而非僅只進行機制的概念驗證。在實做過程中,我們也將反覆審視此架構下對於使用者體驗的影響,並且透過擴展網頁界面功能以其他方式彌補。
\subsection{安全性}
-二代架構設計將需要高權限、低使用量的使用者開通元件以及低權限、高使用量的使用者互動界面實做為單一一個單體式網頁服務,不同權限層級的操作間欠缺隔離手段。另外在實做上也欠缺資訊安全意識,其根據使用者操作在伺服器端呼叫 Helm CLI 的方式也容易產生漏洞。完全仰賴自行定義的 admission control 邏輯進行 Kubernetes 叢集本身的加固,由於 Kubernetes API 的複雜性,也容易由於未充分理解而有所缺失。
+二代架構設計將需要高權限、低使用量的使用者開通元件以及低權限、高使用量的使用者互動界面實做為單一一個單體式網頁服務,不同權限層級的操作間欠缺隔離手段。另外在實做上也欠缺資訊安全意識,其根據使用者輸入在伺服器端呼叫 Helm CLI 的方式也容易產生漏洞。完全仰賴自行定義的 admission control 邏輯進行叢集本身的加固,由於 Kubernetes API 的複雜性,也容易由於未充分理解而有所缺失。
-以系計中在運作方面上的特色而言,由於主力開發人力來自於碩士班研究生以及部份學士班的打工,人員更迭極為快速,並且提供的服務眾多,難以分配專屬人力,一人經常身兼多職維護多個產品,歷史上僅有少數人能夠深入了解既有服務實做細節。面對這樣的場景,以及考量到本平台的重要性,由初步規劃即必須嚴謹考量資訊安全,從架構起手進行防禦,以免在日後他人迭代維護時產生紕漏。
+以系計中在運作方面上的特色而言,其主力開發人員來自於碩士班研究生以及部份學士班的打工,更迭極為頻繁快速,且提供的服務眾多,難以分配專屬人力,一人經常身兼多職維護多個產品,歷史上僅有少數人能夠深入了解既有服務實做細節。面對這樣的場景,以及考量到本平台的重要性,由初步規劃即必須嚴謹考量資訊安全,從架構起手進行防禦,以免在日後他人迭代維護時產生紕漏。
\subsection{通用性}
-二代並沒有達成一代對於開放直接使用 Kubernetes API 的想法,欠缺通用性,在網頁控制界面的實做亦是以新的 PaaS 平台角度出發,Kubernetes 僅只屬於達成平台的手段,這樣的實做脈絡容易侷限於自身的使用經驗,而忽略其他潛在的需求。同樣由於系計中人力更迭的特性,較不利於累積經驗,這個方式難以產出功能全面的產品。Kubernetes 本身經過時間的洗禮,已發展為高度彈性且經過廣泛採用歷練的服務部屬框架,應由直接利用 Kubernetes 的角度設計,即可低成本的達成高通用性。
+二代並沒有達成一代對於開放直接使用 Kubernetes API 的想法,欠缺通用性,在網頁控制界面的實做亦是以新的 PaaS 平台角度出發,Kubernetes 僅只屬於達成平台的手段,這樣的實做脈絡容易侷限於自身的使用經驗,而忽略其他潛在的需求。同樣由於系計中人力更迭迅速的特性,較不利於累積經驗,這個方式難以產出功能全面的產品。Kubernetes 本身經過時間的洗禮,已發展為高度彈性且經過廣泛採用歷練的服務部屬框架,應由直接利用 Kubernetes 的角度設計,即可低成本的達成高通用性。
\section{CSKloud v3 架構設計}
@@ 35,17 34,17 @@
\caption{CSKloud v3 架構簡易示意圖}
\end{figure}
-針對這些需求,我們提出新的架構,稱為 CSKloud v3(以下簡寫 CSKloud)。我們將權限開通元件拆分,改採類似於一代的方式,透過自訂 Kubernetes resource 類型撰寫。一代的開通流程仰賴於管理者手動觸發,CSKloud 則是採取更自動的流程。透過 Kubernetes 對於身份驗證的設計,OIDC 驗證前不須針對新使用者進行設定,即可進行身份驗證,我們設計賦予所有使用者創立此自訂 resource 的權限,在網頁界面首次登入時自動創立,作為開通流程的觸發機制。同時權限開通元件本身並不會自行查詢使用者身份資訊,而是透過創立者的驗證資訊判斷。
+針對這些需求,我們提出新的架構,稱為 CSKloud v3(以下簡寫 CSKloud)。我們將權限開通元件獨立,改採類似於一代的方式,透過自訂 Kubernetes resource 類型撰寫。一代的開通流程仰賴於管理者手動觸發,CSKloud 則是採取全自動流程。透過 Kubernetes 對於身份驗證的設計,OIDC 驗證前不須針對新使用者進行設定,即可進行身份驗證,我們設計賦予所有使用者創立此自訂 resource 的權限,在網頁界面首次登入時自動創立,作為開通流程的觸發機制。同時權限開通元件本身並不會從外部來源查詢使用者身份資訊,而是透過創立者的驗證資訊判斷。
-對於叢集本身的加固,二代採用 webhooks 的形式自行定義 admission control,而 CSKloud 改以 Kubernetes 本身內建的 admission controllers 為主,有利於確保相關防禦的完備性,並且隨著 Kubernetes 的更迭,內建的 admission controllers 也會有對應的邏輯更新,大幅減少後續在維護上的負擔,同時其行為也更為通用,更容易對使用者描述,使得使用者可以對平台所提供的功能有更明確的認知。整個系統難免還是有內建 admission controllers 無法涵蓋的其餘需求,例如域名使用權的管控,這部份 CSKloud 以 CEL 重新實做取代 webhooks,以達到更好的效能及更低的運作成本。
+對於叢集本身的加固,二代採用 webhooks 的形式自行實做 admission control,而 CSKloud 改以 Kubernetes 本身內建的 admission controllers 為主,有利於確保相關防禦的完備性,並且隨著 Kubernetes 的更迭,內建的 admission controllers 也會有對應的邏輯更新,大幅減少後續在維護上的負擔,同時其行為也更為通用、更容易對使用者描述,使用者得以對平台所提供的功能有更明確的認知。整個系統難免還是有內建 admission controllers 無法涵蓋的其餘需求,例如域名使用權的管控,這部份 CSKloud 以 CEL 重新實做取代 webhooks,以達到更好的效能及更低的運作成本。
-CSKloud 達成一代願景中的開放使用者直接存取 Kubernetes API,使用者可以透過標準 Kubernetes 客戶端(如 kubectl\footnote{kubectl: Kubernetes 官方提供的 CLI (指令列界面)型客戶端。})存取叢集,但仍然提供一個網頁界面。除了用以觸發前述的權限開通流程,這個網頁界面同時具備作為 Kubernetes 的通用型網頁界面的功能,由 Kubernetes 的角度出發設計,用意主要在輔助與簡化 Kubernetes 的使用,以及提供 kubectl 所缺乏的配額視覺化等在 CLI 場景難以實做的功能。
+CSKloud 達成一代願景中的開放使用者直接存取 Kubernetes API,使用者可以透過標準 Kubernetes 客戶端(如 kubectl\footnote{kubectl: Kubernetes 官方提供的 CLI (指令列界面)型客戶端。})存取叢集,但系統仍然提供一個網頁界面。除了用以觸發權限開通流程,這個網頁界面同時具備作為 Kubernetes 的通用型界面的功能,由 Kubernetes 的角度出發設計,用意主要在輔助與簡化使用,以及提供 kubectl 所缺乏的配額視覺化等在 CLI 場景難以實做的功能。
-在網頁界面的實做方面,由於 CSKloud 開放存取 Kubernetes API,可以將其直接作為網頁後端利用,而網頁界面本身透過 SPA 架構重新實做,免除另外維護網頁後端伺服器所產生的維運成本及資安考量,同時也可以利用 Kubernetes API 本身對資料更新的推送機制,搭配 SPA 動態控制內容的特性,達成即時的資訊更新,大幅地增強使用者體驗。同時將對於 Helm 的支援透過 WebAssembly 改由直接在瀏覽器端運行,並且將其功能完善,開放更多的 Helm Charts 提供安裝。
+在網頁界面的實做方面,由於 CSKloud 開放存取 Kubernetes API,可以將其直接作為網頁後端利用,因此採用 SPA 架構重新實做網頁界面,免除另外維護網頁後端伺服器所產生的維運成本及資安顧慮,同時也利用 Kubernetes API 對資料更新的推送機制,搭配 SPA 動態控制內容的特性,達成即時的資訊更新,大幅地增強使用者體驗。另外將對於 Helm 的支援透過 WebAssembly 改由直接在瀏覽器端運行,並且將其功能完善,開放更多的 Helm Charts 提供安裝。
\section{叢集加固實做}
-由於 Kubernetes 的功能廣泛,有許多的功能具有較大的權限,間接具備控制整座叢集的能力,在一個共有的平台下,有部屬不受信任的工作負載的可能,使用 admission control 限制功能是必要的,對此我們以引入 Kubernetes 內建的 admission controllers 為主,輔以 CEL 進一步實做缺乏的邏輯。我們主要引入下列內建的 admission controllers:
+Kubernetes 功能廣泛,有許多功能牽涉較大的作業系統權限,間接具備控制整座叢集的能力。共有的平台有被部屬不受信任的工作負載之可能,使用 admission control 限制功能是必要的。對此我們以引入 Kubernetes 內建的 admission controllers 為主,輔以 CEL 進一步實做缺乏的邏輯。我們主要引入下列內建的 admission controllers:
\begin{onehalfspacing}
\begin{itemize}
@@ 58,33 57,33 @@ CSKloud 達成一代願景中的開放使用者直接存取 Kubernetes API,使
\subsection{PodSecurity}
\label{sec:PodSecurity}
-容器一般被視為一個與宿主端 (host) 隔離的環境,但由於容器具有自成一體 (self-contained) 的特性,能夠大幅簡化部屬管理,在 Kubernetes 的場合更可以統一管理叢集內部各節點的容器,因此容器也常被用來部屬與宿主端有關的底層基礎設施。此場景需要局部地關閉容器的隔離功能,來達成如管理宿主端網路環境等操作。對此,Kubernetes 在 Pod 的 \verb|spec| 欄位設計多個開關,提供解除部份隔離機制的途徑。
+容器一般被視為一個與宿主端 (host) 隔離的環境,但由於容器具有自成一體 (self-contained) 的特性,能夠大幅地簡化部屬管理,在 Kubernetes 的場合更可以統一管理叢集內部各節點的容器,因此容器也常被用來部屬與宿主端有關的底層基礎設施。此場景需要局部地關閉容器的隔離功能,來達成如管理宿主端網路環境等操作。對此,Kubernetes 在 Pod 的 \verb|spec| 欄位設計多個開關,提供解除部份隔離機制的途徑。
-即使並未關閉任何預設的隔離機制,對於一般的工作負載,我們也應遵循最小權限原則,例如以非 root 的身份執行等,針對容器內的執行身份,在 Pod 內也可以進行設定。另外,Kubernetes 除了傳統容器隔離技術外,也支援進一步設定其餘的安全與 mandatory access control (MAC)\footnote{MAC: 針對特定行程的操作與其目標(如讀寫特定檔案、使用特定網路資源)進行限制的機制。} 機制,例如 seccomp、SELinux、AppArmor 等。
+即使並未關閉任何預設的隔離機制,對於一般的工作負載,我們也應遵循最小權限原則,例如以非 root 的身份執行等。針對容器內的執行身份,在 Pod 內也可以進行設定。另外,Kubernetes 除了傳統容器隔離技術,也支援進一步設定額外的安全與 mandatory access control (MAC)\footnote{MAC: 針對特定行程的操作與其目標(如讀寫特定檔案、使用特定網路資源)進行限制的機制。} 機制,例如:seccomp、SELinux、AppArmor 等。
面對如此多元的安全性相關設定,以及其產生的無數組合,我們需要一個標準評判 Pod 的安全性。Kubernetes 提出了 Pod Security Standards,並且將可能的設定分為三個政策層級:privileged、baseline 與 restricted。Privileged 可以放寬隔離機制,baseline 包含未特別指定任何設定的場景,restricted 則是進一步要求提升安全性設定。對於執行這些政策檢查,Kubernetes 提供了 \verb|PodSecurity| admission controller。
-大多數政策類型的 admission controllers,包含 \verb|PodSecurity|,設計上皆能夠以 Namespace 為單位設定政策,為了確保平台安全性,我們針對使用者的 namespaces 實施 restricted 政策。
+大多數政策類型的 admission controllers,包含 \verb|PodSecurity|,設計上皆能夠以 Namespace 為單位設定政策,為了確保平台安全性,我們針對使用者的 Namespaces 實施 restricted 政策。
\subsection{PodTolerationRestriction}
\label{sec:PodTolerationRestriction}
-在典型的 Kubernetes 叢集規劃下,節點分為兩大類:control plane 與 worker nodes。Control plane 負責運行叢集本身的元件,例如 kube-apiserver 與各式 controllers 等;而 worker nodes 負責運行一般的工作負載。Control plane 的元件通常也是以容器的形式部屬,而其節點也會納入叢集本身的管轄下,然而我們不希望 control plane 節點運行一般工作負載,避免影響到叢集控制邏輯的運行。Kubernetes 提供 taints 機制,用來標示 Node 的屬性,以及屬性應帶來的效果。以這個場景為例,我們標示這個 Node 為 control plane 並且不允許納入排程。此外,taints 機制同時也拿來自動標記異常的節點,例如節點資源即將耗盡的場景,並且藉此調整排程機制,優先使用其他節點。
+在典型的 Kubernetes 叢集規劃下,節點分為兩大類:control plane 與 worker nodes。Control plane 負責運行叢集本身的元件,例如 kube-apiserver 與各式 controllers 等;而 worker nodes 負責執行一般的工作負載。Control plane 的元件通常以容器的形式部屬,而其節點也會納入叢集本身的管轄下,然而我們不希望 control plane 節點執行一般的工作負載,避免影響到叢集控制邏輯的運行。Kubernetes 提供 taints 機制,用來標示 Node 的屬性,以及屬性應帶來的效果。以這個場景為例,我們標示此 Node 為 control plane 並且不允許納入排程。此外,taints 機制也用來自動標記異常的節點,例如節點資源即將耗盡,並且藉此調整排程機制,優先使用其他節點。
-與 taints 相對,Pod 可以設定 tolerations 來抑制 taints 的效果。例如在擴充 Kubernetes API 的場景,我們需要部屬實做自訂 resource 種類邏輯的 controller,這個 controller 屬於叢集控制邏輯的一部分,我們會希望規劃在 control plane 運行。在部屬此 controller 時,我們便會設定前述 taints 相對的 tolerations 解除限制,並且搭配其他排程設定強制排程至 control plane。
+與 taints 相對,Pod 可以設定 tolerations 來抑制 taints 的效果。例如在擴充 Kubernetes API 時,我們需要部屬實做自訂 resource 種類邏輯的 controller,這個 controller 屬於叢集控制邏輯的一部分,我們會希望規劃在 control plane 運行。部屬此 controller 時,我們便會設定與前述 taints 相對的 tolerations 解除限制,並且搭配其他排程設定強制排程至 control plane。
-為了避免一般使用者濫用這個機制,我們採用 \verb|PodTolerationRestriction| 來限制使用者能填寫的 tolerations。\verb|PodTolerationRestriction| 可以針對 Namespace 設定其中 Pods 可使用的 tolerations 白名單,我們將其限制為只允許系統內部會預設填入的項目。
+為了避免一般使用者濫用這個機制,我們採用 \verb|PodTolerationRestriction| 來限制使用者能填寫的 tolerations。\verb|PodTolerationRestriction| 可以針對 Namespace 設定其中 Pods 可使用的 tolerations 白名單,我們限制為只允許系統內部會自動填入的項目。
\subsection{AlwaysPullImages}
-在 Kubernetes 下,容器 images 的下載策略(\verb|imagePullPolicy| 欄位)有三種:\verb|Always|、\verb|IfNotPresent| 與 \verb|Never|。\verb|Always| 在啟動容器之前總是會檢查容器的 image 的更新,若有更新即重新下載;\verb|IfNotPresent| 是當節點上尚未有該 image 時才會下載;\verb|Never| 則是不主動下載,仰賴節點上的存放狀況。在容器結束執行後,Kubernetes 並不會主動刪除 image 資料,而是只有在儲存空間有壓力時才會刪除,藉此減少下載 image 的負擔。
+Kubernetes 中容器 images 的下載策略(\verb|imagePullPolicy| 欄位)有三種:\verb|Always|、\verb|IfNotPresent| 與 \verb|Never|。\verb|Always| 在啟動容器之前總是會檢查容器的 image 的更新,若有更新即重新下載;\verb|IfNotPresent| 是指當節點上尚未有該 image 時才會下載;\verb|Never| 則是不主動下載,仰賴節點上的存放狀況。在容器結束執行後,Kubernetes 並不會主動刪除 image 資料,而是只有在儲存空間有壓力時才會刪除,藉此減少下載的負擔。
-在容器生態下,images 主要可分為公開存取以及私人的兩種。下載公開存取的 images 不須經過身份驗證,而私人的 images 則是需要。由於 \verb|IfNotPresent| 與 \verb|Never| 在節點已經存有指定 image 時,不會進行任何更新檢查,因此也不需進行身份驗證,如此在共用叢集的狀況下,便形成了一個可能用來存取他人遺留在節點上的私人 images 的途徑。對此,我們採用 \verb|AlwaysPullImages| 將下載策略一律複寫為 \verb|Always|。
+在容器生態下,images 主要可分為公開存取以及私人的兩種。下載公開存取的 images 不須與儲存庫進行身份驗證,而私人的 images 則是需要。由於 \verb|IfNotPresent| 與 \verb|Never| 在節點已經存有指定 image 時,不會進行任何更新檢查,因此也不需進行身份驗證,如此在共用叢集的狀況下,便可能被用來存取他人遺留在節點上的私人 images。對此,我們採用 \verb|AlwaysPullImages| 將下載策略一律複寫為 \verb|Always|。
\subsection{CEL}
\label{sec:CEL}
-對於防止使用者在 control plane 上運行容器,\ref{sec:PodTolerationRestriction} \verb|PodTolerationRestriction| 仍然不足。預設在 control plane 上的 taint 只有防止排程,使用者實際上可以繞過排程直接指定節點。一個解決方法是修改 control plane 上的 taint,改為防止執行而非單純防止排程,但由於這個 taint 由 Kubernetes 安裝工具提供,實際上已被廣泛使用,修改容易造成管理上的負擔,若欠缺注意更有可能造成部屬叢集元件時意外安排到 worker nodes 上,間接影響叢集服務品質。於是我們採取另外撰寫邏輯,防止使用者繞過排程。這同時也有附加的優勢:使用者提交的工作負載一律會經過平台的排程機制,使資源的充分、平均利用更有保障。
+對於防止使用者在 control plane 上運行容器,\ref{sec:PodTolerationRestriction} \verb|PodTolerationRestriction| 仍然不足。預設在 control plane 上的 taint 只有防止排程,使用者實際上可以繞過排程直接指定節點。一個解決方法是將此 taint 改為防止執行而非單純防止排程,但由於這個 taint 來自於 Kubernetes 官方安裝工具的預設行為,實際上已被廣泛利用,修改容易造成管理上的負擔,若欠缺注意更有可能造成部屬叢集元件時意外安排到 worker nodes 上,間接影響叢集服務品質。於是我們採取另外撰寫邏輯,防止使用者繞過排程。這同時也有附加的優勢:使用者提交的工作負載一律會經過平台的排程機制,使資源的充分、平均利用更有保障。
\begin{figure}[htb]
\centering
@@ 93,9 92,9 @@ CSKloud 達成一代願景中的開放使用者直接存取 Kubernetes API,使
\label{fig:code-pod-policy}
\end{figure}
-以 CEL 實做 validating admission control 邏輯需要以 ValidatingAdmissionPolicy resource 先行定義,在以 ValidatingAdmissionPolicyBinding resource 將之啟用。圖 \ref{fig:code-pod-policy} 即為實做防止繞過排程的 ValidatingAdmissionPolicy。首先我們只對開放給使用者的 Namespace 進行限制,透過我們權限開通的設計,以具有 \verb|u-| 前綴來判斷。再來由於排程機制對 Pod 指定節點與使用者直接指定修改的欄位相同,我們需要避免限制到叢集系統本身。這點由於我們的權限規劃,使用者沒有列舉 Nodes 的權限,我們以此分別使用者與系統。最後我們檢查欄位狀況。% TODO check if updated
+以 CEL 實做 validating admission control 邏輯需要由 ValidatingAdmissionPolicy resource 先行定義,再以 ValidatingAdmissionPolicyBinding resource 將之啟用。圖 \ref{fig:code-pod-policy} 即為實做防止繞過排程的 ValidatingAdmissionPolicy。首先我們只對開放給使用者的 Namespace 進行限制,透過 \ref{sec:provisioner} 權限開通的設計,以具有 \verb|u-| 前綴來判斷。再來由於排程機制對 Pod 指定節點與使用者直接指定修改的欄位相同,我們需要避免限制到叢集系統本身。這點由於我們的權限規劃,使用者沒有列舉 Nodes 的權限,我們以此分別使用者與系統。最後我們檢查欄位狀況,確保在更新時值保持不變,或者在創立時未被指定。
-另一個需要自訂邏輯的場景是域名使用權的管控。針對用來設定反向代理的 Ingresses,我們一樣先判斷操作的 Namespace 是否為使用者面向的,再進一步進行限制。需要限制的有:禁止使用 \verb|defaultBackend| 欄位(全域、不符合任何規則時的 fallback route),以及所有反向代理規則中的 \verb|host| 必須要符合域名白名單。域名白名單的部份參考其餘政策相關內建 admission controllers 的設計,採用在 Namespace 上標記的白名單作為設定手段,後續再藉由 \ref{sec:provisioner} 權限開通設定此白名單。
+另一個需要自訂邏輯的場景是域名使用權的管控。針對用來設定反向代理的 Ingresses,我們一樣先判斷操作的 Namespace 是否為使用者面向的,再進一步進行限制。需要限制的有:禁止使用 \verb|defaultBackend| 欄位(全域、不符合任何規則時的 fallback route),以及所有反向代理規則中的 \verb|host| 必須要符合域名白名單。白名單參考其餘政策相關內建 admission controllers 的設計,採用在 Namespace 上標記作為設定手段,後續再藉由 \ref{sec:provisioner} 權限開通設定此白名單。
\section{權限開通實做}
\label{sec:provisioner}
@@ 106,7 105,6 @@ CSKloud 達成一代願景中的開放使用者直接存取 Kubernetes API,使
\centering
\includegraphics[width=0.5\textwidth]{assets/provisioner-user-spec.png}
\caption{權限開通自訂 resource 種類 User spec 範例}
- \label{fig:code-pod-policy}
\end{figure}
每個使用者會創立一個與其系計中帳號名稱相同的 User,其中 \verb|spec| 的 \verb|profile| 欄位帶有其身份組資訊,由網頁界面自動判斷填入。身份組影響對齊開放配額的大小。對於創立代表自身 User 所需的權限,我們透過 RBAC 允許所有使用者創立 User,再透過 admission control 將其限制名稱必須與身份相同。分兩階段設計有助於簡化 RBAC 實做,使 RBAC 實做上不須枚舉使用者名稱一一事先對應,同時也減少叢集上相關設定的 resources 個數,有助於減少管理上的負擔。對於 \verb|profile| 欄位的真實性,我們一樣透過 admission control 與身份資訊比對。