Kubernetes(k8s)部署安全最佳實踐

Kubernetes 提供了很多能夠提高應用安全的方法。要進行這些配置,就要掌握 Kubernetes 的相關知識,同時也要清楚的瞭解安全需求。這裏我們關注的安全內容集中在容器的生命週期上:構建、傳輸以及運行,並且針對 Kubernetes 進行了特別的裁剪。我們自己的 SaaS 就是運行在 Google Cloud Platform 上的 Kubernetes 中,已經採用了這些最佳實踐。

下面是我們對於安全部署 Kubernetes 應用的一些建議。

確保鏡像無漏洞

運行帶有漏洞的容器會讓你的環境身處險境。只要運行中的系統的所有組件都不存在已知漏洞,就能夠避免很多被攻擊的機會。

安全漏洞的持續掃描

容器中可能有一些過期組件,這些過期組件往往會包含已知漏洞(CVE)。新的漏洞層出不窮,因此對安全漏洞的掃描工作必須持續進行。

適時應用安全更新

一旦在運行的容器中發現了安全漏洞,就該對源鏡像進行更新並部署。爲了避免破壞鏡像和容器的繼承性,儘量不要在容器中直接進行更新(例如 apt-update)。 Kubernetes 的滾動更新功能可以漸進式的爲運行中的應用更新鏡像,這一功能讓應用更新變得簡單優雅。

只使用可靠的鏡像

要避免受到有漏洞甚至惡意的容器的威脅,鏡像的准入就需要受到有效管理。和隨意下載運行軟件一樣,下載運行不可靠的鏡像也是高危行爲,必須杜絕。

使用私庫來保存你的鏡像,並保證只向其推送可靠鏡像。這樣就縮小了戰場面積,避免大量不確認的公開鏡像涌入你的環境。另外建議在持續構建流程中加入漏洞掃描之類的安全環節。

持續集成管線要控制門檻,只允許使用受確認的代碼進行鏡像構建。鏡像構建成功後,應該進行漏洞掃描,排除問題後才能推入私庫,進行下一步的部署。過程中發現問題,應該終端構建過程,阻止安全質量低下的鏡像進入私庫。

限制對 Kubernetes Node 的直接訪問

對 Kubernetes Node 的 SSH 訪問會降低主機的安全性。應該讓用戶儘量使用 kubectl exec,這一命令提供了對容器環境的直接訪問,而不需要接觸宿主機。

還可以使用 Kubernetes 的 Authorization Plugins 來對用戶的資源訪問進行進一步控制。這一插件允許定義對命名空間、容器以及操作的基於角色的訪問控制。

在資源之間建立管理邊界

限制用戶權限能夠降低出錯和入侵造成的危害。Kubernetes 命名空間讓你可以把資源分割爲不同名稱的羣組之中。一個命名空間中創建的資源對其他命名空間是不可見的。缺省情況下,Kubernetes 用戶創建的資源都存在於 default 命名空間中。可以創建其他的命名空間,並把資源和用戶綁定上去。可以使用 Kubernetes Authorization 插件來創建策略,讓不同用戶分別訪問各自的命名空間和對應的資源。

例如下面的策略讓 “Alice” 能夠從命名空間 “fronto” 中讀取 Pod:

{ "apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": { "user": "alice", "namespace": "fronto", "resource": "pods", "readonly": true } }

設定資源配額

容器運行中如果沒有資源限制,那麼系統就可能處於 DoS 或鄰里不和的情境之中。要降低或阻止這一風險,就需要設定資源配額。缺省情況下,所有的 Kubernetes 集羣資源都可以不受限的訪問 CPU 和內存。可以爲命名空間創建配額策略,來限制 Pod 的 CPU 和內存消費。

下面的例子是一個命名空間的資源配額定義,限制運行 Pod 數量爲 4,CPU 的使用限制在 1-2 之間,內存使用在 1-2 G 之間:

apiVersion: v1
kind: ResourceQuota
metadata:
 name: compute-resources
spec:
 hard:
 pods: "4"
 requests.cpu: "1"
 requests.memory: 1Gi
 limits.cpu: "2"
 limits.memory: 2Gi

將資源配額指派給命名空間:

kubectl create -f ./compute-resources.yaml --namespace=myspace

規劃網絡分區

在同一個 Kubernetes 集羣上運行不同的應用,引入了一個風險就是應用之間的互相訪問。要確保容器只能訪問允許訪問的範圍,網絡分區是很重要的。Kubernetes 中的一大挑戰就是在 Pod、Service 以及容器之間的網絡劃分,造成這一問題的根本在於容器網絡的動態分配過程,讓容器可以跨越 Node 進行網絡互訪。

Google Cloud Platform 用戶收益於自動防火牆規則功能,能夠阻止跨集羣的通信。使用 SDN 或者防火牆能夠達到類似的效果。KuberntesNetwork SIG 正在進行這方面的努力,目的是增強 Pod 之間的通信策略。新的網絡策略 API 將會用於創建 Pod 之間的防火牆規則,限制容器應用的網絡訪問。

下面的例子是一條網絡策略,用於控制 “backend” Pod,只允許來自於 “frontend” Pod 的訪問。

POST /apis/net.alpha.kubernetes.io/v1alpha1/namespaces/tenant-a/networkpolicys
{ "kind": "NetworkPolicy", "metadata": { "name": "pol1" }, "spec": { "allowIncoming": { "from": [{ "pods": { "segment": "frontend" } }], "toPorts": [{ "port": 80, "protocol": "TCP" }] }, "podSelector": { "segment": "backend" } } }

網絡策略的更多信息可以閱讀 SIG-Networking: Kubernetes Network Policy APIs Coming in 1.3

Pod 和容器的安全上下文

設計容器和 Pod 的時候,一定要配置 Pod、容器以及卷的安全上下文。安全上下文是部署 Yaml 中的一個屬性,他控制了 pod/container/volume 的安全參數,下面列出一些重要的參數:

安全上下文設置 描述
SecurityContext->runAsNonRoot 容器應該用非 root 用戶運行
SecurityContext->Capabilities 設置 Linux 分配給容器的性能
SecurityContext->readOnlyRootFilesystem 容器是否可以寫入 root 文件系統
PodSecurityContext->runAsNonRoot 阻止 Pod 中的容器以 root 用戶運行

下面是一個帶有安全上下文的 Pod 定義:

apiVersion: v1
kind: Pod
metadata:
 name: hello-world
spec:
 containers: # specification of the pod’s containers # ...
 securityContext:
 readOnlyRootFilesystem: true
 runAsNonRoot: true

如果用特權形式(–privileged)運行容器,可以用 DenyEscalatingExec 控制。這一開關拒絕在特權容器上使用 Exec 和 Attach 命令。具體情況可以參考 Admission 文檔

記錄日誌

Kubernetes 支持集羣級別的日誌,集中收集日誌到中央服務。當集羣創建之後,STDOUT 和 STDERR 就能夠被 Node 中的 Fluent 蒐集起來,並彙總到 Google Stackdriver Logging 或者 Elasticsearch,並用 Kibana 進行查看。

總結

Kubernetes 爲安全提供了很多特性。對這些特性進行學習和了解,才能夠制定出符合應用需求的安全方案。

我們建議實施文中提到的最佳實踐,使用 Kubernetes 的動態配置能力,結合持續集成,無縫提高安全保障能力。

本文轉自中文社區-Kubernetes(k8s)部署安全最佳實踐

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章