憑證管理與安全傳遞

在 Kubernetes 環境中,憑證管理是確保系統安全的關鍵環節。無論是存取資料函式庫、處理使用者資訊或進行支付操作,應用程式都需要適當的存取權杖或帳號密碼組合。

最小許可權原則的應用

最小許可權原則在 Kubernetes 憑證管理中有兩個重要體現:

  1. 容器化程式碼的權限制:確保容器只能讀取其所需的憑證,不能存取其他敏感資訊
  2. 環境隔離:為不同環境(如生產、開發和測試)設定不同的憑證集,讓開發團隊成員可以在不需要完整生產環境憑證的情況下進行工作

憑證加密機制

憑證值保護敏感資料,因此必須在靜態和傳輸過程中都受到保護:

  • 靜態加密:憑證應始終以加密形式儲存在磁碟上,防止攻擊者透過檔案系統直接讀取
  • 傳輸加密:憑證在網路傳輸過程中應加密,防止網路監聽者攔截讀取

Kubernetes 透過 TLS 加密控制平面元件之間的流量來實作傳輸加密。接下來,我們將探討如何安全地儲存加密的憑證。

Kubernetes 憑證儲存機制

Kubernetes 的 Secret 資源型別提供了一種將憑證傳遞給程式碼的機制,而無需在 Pod 的 YAML 中明文顯示。Pod 規格透過名稱參照 Secret,而實際的憑證值則單獨設定。

注意:請謹慎管理用於定義 Secret 的 YAML 或 JSON 清單檔案。如果將這些清單檢入原始碼控制,任何有權存取該儲存函式庫的人都能存取憑證值。同時,Secret 清單檔案中以 base64 編碼的憑證值並非加密!

etcd 中的憑證儲存

預設情況下,憑證值與其他設定資訊一起儲存在 etcd 資料函式庫中,僅以 base64 編碼。

重要提醒:base64 編碼雖然使內容對人眼不可讀,但並不是加密。任何人只需透過 base64 解碼即可檢索原始資訊,無需金鑰。對攻擊者而言,base64 編碼實際上等同於明文。

任何獲得 etcd 資料庫存取權的人都能讀取其中的 base64 編碼憑證。雖然可以透過設定安全存取來控制,但仍存在風險:資料以未加密形式寫入磁碟,如果攻擊者獲得檔案系統存取權,資料可能被洩露。

為避免這種風險,應確保 etcd 叢集在磁碟上也進行加密。由於 API 伺服器可以存取 etcd 中的加密資料,因此還需要限制 API 存取。

叢集安全架構設計

安全邊界的建立

Kubernetes 提供了多層安全邊界,從外到內依次為:

  1. 叢集層:包含所有節點和控制平面元件,提供網路隔離
  2. 節點層:虛擬或實體機器,託管多個 Pod 和系統元件
  3. 名稱空間層:虛擬叢集,包含多個資源如服務和 Pod
  4. Pod 層:Kubernetes 用於分組容器的管理單位
  5. 容器層:結合 cgroups、名稱空間和寫時複製檔案系統的應用程式隔離單元

最大化這些防禦層需要開發人員和叢集/名稱空間管理員的共同努力,因為某些責任(如建立容器映像)屬於前者,而其他責任(如管理節點或名稱空間)則屬於後者。

安全策略實施

Kubernetes 提供兩種 Pod 級安全策略機制:

  1. 安全上下文與策略:限制 Pod 內程式的行為
  2. 網路策略:控制 Pod 間的通訊

安全上下文設定

安全上下文定義了 Pod 或容器級別的許可權和存取控制設定,包括:

  • 實作自主存取控制
  • 能力管理
  • 應用設定檔
  • 實作強制存取控制

例如,可以設定所有容器必須以特定使用者身份執行,或防止特權升級:

apiVersion: v1
kind: Pod
metadata:
  name: securepod
spec:
  securityContext:
    runAsUser: 1001
  containers:
  - name: webserver
    image: quay.io/mhausenblas/pingsvc:2
    securityContext:
      allowPrivilegeEscalation: false
  - name: shell
    image: centos:7
    command:
    - "bin/bash"
    - "-c"
    - "sleep 10000"

網路策略實施

限制 Pod 間的流量增加了安全層:

  • 即使外部攻擊者能夠到達叢集網路策略也能阻止攻擊者傳送到達 Pod 內應用程式的流量
  • 如果容器被入侵,網路策略可限制攻擊者探索網路並橫向移動到其他容器或主機的能力

預設情況下,所有型別的入站和出站流量都被允許,但可以使用網路策略控制 Pod 間的通訊。

認證與授權機制

身分驗證概念

Kubernetes 中的身分驗證流程如下:

  1. 客戶端向 API 伺服器提供憑證
  2. API 伺服器使用已設定的認證外掛之一來建立身份
  3. 身份提供者驗證請求資訊,包括使用者名和群組成員資格
  4. 如果憑證正確,API 伺服器繼續檢查許可權;否則回傳 HTTP 401 未授權錯誤

Kubernetes 支援多種認證策略:

  • 靜態密碼或權杖檔案
  • X.509 憑證
  • OpenID Connect (OIDC)
  • 引導權杖
  • 認證代理
  • Webhook 權杖認證

授權機制

授權在 Kubernetes 中透過 API 伺服器進行,評估請求屬性並允許或拒絕請求。預設情況下,許可權被拒絕,除非策略明確允許。

Kubernetes 提供多種授權模式:

  • 節點授權
  • 根據屬性的存取控制 (ABAC)
  • Webhook
  • 根據角色的存取控制 (RBAC)

RBAC 存取控制

RBAC 是 Kubernetes 中最重要的授權方法,包含以下元素:

  • 實體:需要執行操作的群組、使用者或服務帳戶
  • 資源:實體想要存取的 Pod、服務或憑證
  • 角色:用於定義資源操作規則
  • 角色繫結:將角色附加到實體,說明允許特定實體對指定資源執行的操作集

RBAC 角色分為兩種型別:

  1. 叢集範圍:叢集角色及其相應的叢集角色繫結
  2. 名稱空間範圍:角色和角色繫結

容器映像安全

映像掃描與修補

容器映像掃描器檢查映像中包含的套件,並報告任何已知的漏洞。為確保不在佈署中執行易受攻擊的程式碼,應定期掃描第三方容器映像和組織自己構建的映像。

一旦發現包含漏洞的容器映像,需要更新容器以使用已修復的套件版本。在容器佈署中,“修補"的關鍵是重建新的容器映像,然後重新佈署根據該新映像的容器。

映像儲存與版本控制

容器映像可以儲存在公共或私有登入檔中。許多注重安全的組織使用一個或多個私有登入檔,並要求只能佈署來自這些登入檔的映像。

執行私有註冊表意味著對讀寫映像的許可權有更大的控制。還可以佈署具有限網路存取的登入檔,例如使用防火牆,使得只有已知的 IP 地址可以存取它。

最小化映像以減少攻擊面

遵循"限制攻擊面"的原則,映像越小,攻擊面越小:

  • 透過最小化映像中包含的程式碼,可以減少漏洞的可能性
  • 很少有理由包含 SSH 守護程式
  • 映像中的其他工具可能不是應用程式碼所必需的
  • 如果應用程式碼可以構建為靜態二進位檔案,可以構建一個只包含該二進位檔案的映像

高階安全技術

動態准入控制

高階解決方案可能使用某種形式的動態准入控制,確保只有在映像已被掃描與掃描成功的情況下才佈署映像。此步驟還可以自動檢查映像是否可信。

服務網格在網路策略領域也將發揮作用,提供更細粒度的流量控制和安全功能。

Kubernetes 安全是一個多層次的挑戰,需要從叢集設定、認證授權、容器映像安全到執行時保護的全面方法。透過實施最小許可權原則、適當的憑證管理、嚴格的網路策略和安全上下文設定,可以顯著提高 Kubernetes 環境的安全性。

安全不是一次性的工作,而是一個持續的過程,需要定期審核、更新和改進。隨著新威脅的出現和技術的發展,保持警覺並採用最佳實踐對於維護 Kubernetes 佈署的安全至關重要。

機密管理:保護 Kubernetes 中的敏感資訊

在 Kubernetes 環境中,機密管理是確保系統安全的關鍵環節。無論是資料函式庫憑證、API 金鑰還是加密金鑰,這些敏感資訊都需要特別的保護機制。本文將探討 Kubernetes 機密管理的最佳實踐,從 etcd 加密到第三方解決方案,以及如何安全地將機密傳遞給容器化應用程式。

etcd 加密設定的安全考量

Kubernetes 的 etcd 加密設定案包含解鎖加密資料的金鑰。這個檔案的安全性至關重要,應確保只有執行 Kubernetes API 伺服器的使用者帳戶(通常是 root)才能讀取。

在實務上,玄貓建議定期輪換加金鑰。這種做法可以降低金鑰被長期使用而增加的洩露風險。此外,若您的環境中有多個 etcd 節點,應加密節點間的通訊,防止敏感資訊在傳輸過程中以明文形式傳遞。

利用第三方儲存系統增強機密安全性

許多專業人士認為,使用專門設計用於儲存敏感資訊的第三方系統,比將機密與其他資訊一起存放在 etcd 中更為安全。

主要雲端供應商都提供可與 Kubernetes 整合的金鑰管理系統。其他第三方解決方案包括 HashiCorp Vault 和 CyberArk Conjur。這些工具專為保護敏感資訊而設計,提供了更強大的安全保障。

商業容器安全工具通常提供與多種後端機密儲存系統的整合,並能控制存取許可權,確保只有特定容器能夠存取特定機密。在玄貓的實務經驗中,這種精細的存取控制對於遵循最小許可權原則至關重要。

將機密傳遞給容器化應用的方法

將機密(或任何其他型別的資訊)傳遞給容器,使應用程式能夠存取,主要有三種方式:

  1. 將機密建置到映像檔本身
  2. 透過環境變數傳遞機密
  3. 將包含機密的磁碟區掛載到容器中,讓程式碼從檔案讀取資訊

有人可能會想,容器應用程式可以透過某種網路活動查詢機密,但這又引發了另一個問題:如何在不需要某種憑證的情況下,防止惡意實體取得這些資訊?這些憑證本身就是需要先傳遞到容器中的機密,所以我們又回到了上述三種選項。

Kubernetes 機密支援後兩種方法,但由於我們即將討論的原因,第三種選項(掛載磁碟區)通常被認為是最安全的。

為何不應將機密建置到映像檔中

將機密直接建置到容器映像檔中是一個不好的做法,原因如下:

  • 任何能夠存取映像檔的人都能取得其中的機密。請記住,能夠存取映像檔的人群可能與需要生產環境憑證的人群不同。
  • 如果要更改機密值,需要重新建置映像檔。這可能導致停機時間:例如,如果更改資料函式庫憑證,應用程式在重建和重新佈署前無法存取資料函式庫。
  • 建置到映像檔中的內容很可能受到原始碼控制,不幸的是,透過 GitHub 等工具公開機密資訊的情況太常見了。即使您的儲存函式庫是私有的,也要考慮授權使用者可能會分叉您的儲存函式庫並公開它的可能性。

玄貓曾經遇過一個案例,開發團隊將 AWS 存取金鑰直接寫入 Dockerfile 中,結果這個映像檔被推播到公共儲存函式庫,導致憑證洩露並被用於挖礦活動。這種情況在實務中並不罕見,因此必須避免這種做法。

透過環境變數傳遞機密

十二因素應用宣言教導我們將設定資訊作為環境變數傳遞給應用程式。這允許我們將設定與程式碼分離,當需要在不同場景(生產、測試、本地開發等)執行相同程式碼時,這很有幫助。

您可以在執行時將環境變數傳遞給容器。這意味著您可以根據執行場景來設定容器映像檔(程式碼)。在 Kubernetes 中,「普通」環境變數可以直接在 pod YAML 中指定,或透過 ConfigMap 指定。但要小心:將機密值包含在您簽入程式碼控制的 YAML 檔案中,意味著這些機密可被能夠檢視原始碼的人存取。

為了緩解這個問題,Kubernetes 也支援機密資源,可以作為環境變數傳遞給 pod。您的 pod 規格或 ConfigMap YAML 透過名稱參照機密資源,而不是直接參照機密值,因此將該 YAML 置於程式碼控制下是安全的。

然而,環境變數中的資訊很容易「洩露」到您可能沒有考慮到的地方。讓我們看三個案例:

案例 1:當機日誌洩露

程式在當機時記錄其整個環境是很常見的。這可能被寫入檔案,或在許多佈署中,它會進入集中式日誌聚合系統。那些有權存取此係統的人是否也應該有權存取您的生產資料函式庫憑證?

案例 2:kubectl 命令洩露

檢視 kubectl describe pod <example> 的結果,您會發現環境變數以明文形式提供:

$ kubectl describe pod nginx-env-6c5b7b8ddd-dwpvk
Name: nginx-env-6c5b7b8ddd-dwpvk
...
Containers:
  nginx-env:
    ...
    Environment:
      NOT_SO_SECRET: some_value
...

您可能有些人被允許檢查叢集中執行的 pod,但他們不需要存取系統中最高許可權的憑證。

案例 3:Docker 檢查洩露

如果您使用 Docker 作為容器執行時,環境可以透過在主機上執行 docker inspect <container> 來存取:

$ sudo docker inspect b5ad78e251a3
[
  {
    "Id": "b5ad78e251a3f94c10b9336ccfe88e576548b4f387f5c7040...",
    ...
    "Config": {
      "Hostname": "nginx-env-6c5b7b8ddd-dwpvk",
      ...
      "Env": [
        "NOT_SO_SECRET=some_value",
        ...
      ]
    }
  }
]

環境變數可透過日誌或命令列被比需要存取機密憑證的人更廣泛的人群存取,這可被視為安全風險。您應該考慮這在您的應用程式和組織中是否是一個問題。

一些商業解決方案使用專有技術將機密注入環境,這意味著機密不能透過命令列透過 kubectl describedocker inspect 取得。然而,這種方法仍然無法防止透過將環境傾印到檔案或日誌中而洩露。

您可以使用 RBAC 限制透過 kubectl 的存取,使得只有一部分使用者可以存取特定的 pod。

透過檔案傳遞機密

將資訊傳遞到容器的最後一種機制是透過掛載到容器的磁碟區,其中機密值被寫入該磁碟區上的檔案。Kubernetes 支援透過磁碟區掛載將機密傳遞給 pod。容器化程式碼需要從這些檔案中讀取值。

如果掛載的磁碟區是臨時檔案系統,那就更好了。這意味著檔案不會寫入磁碟,而是儲存在記憶體中,從而幫助我們實作永不以明文形式儲存機密的目標。

檔案中儲存的值不能透過 docker inspectkubectl describe 存取。應用程式碼可能會將這些機密寫入不合適的地方,但這比無意中將機密作為環境變數傾印的一部分包含在內的可能性要小得多。

這種方法的優勢在於,機密資訊不會暴露在環境變數中,減少了被意外記錄或暴露的風險。使用臨時檔案系統(tmpfs)可以確保機密只存在於記憶體中,進一步增強了安全性。在實務中,玄貓發現這是在 Kubernetes 中處理機密的最安全方法。

機密輪換與復原

對於人類,不再建議要求頻繁更改密碼,但這一建議不適用於機器使用的機密。給定機密有效的時間越長,被洩露的可能性就越大。透過定期更改或「輪換」機密值,我們可以確保機密對攻擊者不再有用。

對於與應用程式相關的人類可讀和機器可讀憑證,您應該有一個機制,允許您在發現憑證被洩露時復原該值。如果您有定期的機密輪換流程,您可以確信在緊急情況下可以復原或更改機密,而不會對系統產生有害影響。

根據應用程式碼的編寫方式,您可能需要重新啟動 pod 才能使新的機密值生效。例如,應用程式可能在初始化過程中只讀取一次資料函式庫密碼(從檔案或環境變數);當密碼更改時,它需要重新啟動才能讀取新值。

應用程式中的另一種方法可能是重新讀取機密值,可能是定期進行,或者在使用當前儲存的值失敗時進行。如果應用程式碼能夠處理機密更新,這就引出了根據檔案的機密傳遞方法的一個好處:Kubernetes 可以更新寫入檔案的機密值,而不必重新啟動 pod。如果您使用 Kubernetes 中的環境變數機制傳遞機密,則沒有 pod 重新啟動就無法實時更新它們(儘管商業解決方案提供了這種功能)。

容器內部的機密存取

如果攻擊者獲得對容器的執行存取權,他們很可能會存取該容器內的機密。這包括透過 kubectl execdocker exec 的存取。

在這種情況下,執行時保護可以提供幫助。攻擊者能夠在容器內執行的工具越少越好。例如,如果機密儲存在檔案中,防止攻擊者能夠執行 catmoreless 等命令,會使其更難取得機密。

您還可以透過一開始就不將這些命令建置到容器映像檔中來限制攻擊者存取機密的能力。這是容器安全的基本原則之一:最小化容器中的工具和功能,減少攻擊面。

實作機密管理的最佳實踐

根據上述討論,玄貓建議以下機密管理最佳實踐:

  1. 使用檔案而非環境變數:優先考慮透過掛載磁碟區的方式將機密傳遞給容器,而不是使用環境變數。

  2. 實施機密輪換:建立定期輪換機密的流程,減少長期使用同一機密的風險。

  3. 考慮第三方解決方案:對於高度敏感的環境,考慮使用專門的機密管理解決方案,如 HashiCorp Vault 或雲端供應商的金鑰管理服務。

  4. 加密 etcd:確保 Kubernetes 的 etcd 資料函式庫已加密,保護儲存在其中的機密。

  5. 最小化容器內工具:構建最小化的容器映像檔,移除不必要的工具,減少攻擊者在取得容器執行許可權後能夠利用的工具。

  6. 實施 RBAC:使用 Kubernetes 的角色基礎存取控制,限制誰可以檢視和管理機密資源。

  7. 監控機密存取:實施監控和警示,以檢測對機密的異常存取模式。

機密管理是 Kubernetes 安全的關鍵組成部分。透過遵循這些最佳實踐,您可以顯著降低機密洩露的風險,保護您的應用程式和資料免受未授權存取。在設計系統時,始終考慮機密如何被存取、儲存和輪換,將安全性納入設計的核心。

Kubernetes 提供了多種機制來管理機密,但最終的安全性取決於您如何實施這些機制,以及您的整體安全策略。透過深入理解各種選項的優缺點,您可以為您的環境選擇最適合的機密管理方法。

Kubelet 的秘密存取許可權控制

在 Kubernetes 1.7 版本之前,任何 kubelet 都能存取任何 Secret 資源,這帶來了嚴重的安全隱憂。幸運的是,現代 Kubernetes 已實作節點授權機制,確保 kubelet 只能存取與其節點上排程的 Pod 相關的 Secret。

這項改進大幅降低了節點被入侵時的影響範圍。要確認此功能已啟用,請檢查 API Server 的 --enable-admission-plugins 引數是否包含 NodeRestriction

# 檢查 API Server 的啟動引數
kubectl describe pod kube-apiserver-master -n kube-system | grep enable-admission-plugins

這個命令會檢查 API Server 的啟動引數,確認 NodeRestriction 准入控制器已啟用。NodeRestriction 准入控制器限制 kubelet 只能修改自己的 Node 物件和與其節點相關的 Pod 物件,這是實作最小許可權原則的重要機制。

進階安全技術概覽

接下來,玄貓將帶領大家探討一系列能提升 Kubernetes 叢集安全性的進階技術。這些技術建立在基礎安全措施之上,有些甚至超出了 Kubernetes 本身的範疇,例如監控系統或服務網格等。

值得注意的是,許多本文討論的概念仍在 Kubernetes 社群中持續演進。玄貓鼓勵讀者積極參與社群討論,無論是作為終端使用者或是雲原生專案的貢獻者。Kubernetes 官方網站的社群區塊提供了多種參與方式,從郵件列表、Slack 頻道到實體活動。

監控、警示與稽核系統

監控與警示策略

在容器協調領域,Prometheus 已成為 Kubernetes 叢集監控的事實標準。由於 Kubernetes 環境中有太多活動元件(從節點到 Pod 再到服務),針對每個事件發出警示是不切實際的。

玄貓建議根據職責分工設計警示策略:

  flowchart TD
    A[監控事件] --B{事件型別?}
    B -->|節點相關| C[管理員處理]
    B -->|名稱空間相關| C
    B -->|Pod相關| D[開發團隊處理]

這種分層處理方式同樣適用於日誌管理,但在處理日誌時,還需特別注意敏感資料何時何地被寫入磁碟。

稽核機制

Kubernetes API Server 提供了強大的稽核功能,能夠記錄影響叢集的活動序列。稽核政策支援多種策略(從不記錄到記錄事件中繼資料、請求和回應內容),並可選擇簡單的日誌後端或使用 webhook 整合第三方系統。

以下是一個基本的稽核政策設定範例:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # 記錄 Pod 變更的所有內容
  - level: RequestResponse
    resources:
    - group: ""
      resources: ["pods"]
  # 對其他資源只記錄中繼資料
  - level: Metadata

這個稽核政策範例設定了兩條規則:第一條針對 Pod 資源的操作記錄完整的請求和回應內容,這有助於追蹤 Pod 的所有變更;第二條針對其他資源只記錄中繼資料,減少稽核日誌的體積同時保留關鍵訊息。稽核日誌是事後調查安全事件的重要資源。

主機安全強化

Kubernetes 安全討論常聚焦於 Kubernetes 本身的設定或容器化應用的安全性,但還有一層同樣重要的安全導向:執行 Kubernetes 的主機安全。

主機作業系統精簡化

遵循減少攻擊面的原則,最佳實踐是在主機上只執行必要的 Kubernetes 程式碼、其依賴項(如 Docker 等容器執行時)以及支援功能(如日誌或安全工具)。這種精簡化的作業系統設定通常被稱為「瘦作業系統」(thin OS)。

專為容器設計的發行版是實作主機精簡化的一種方法:

  1. Container Linux(前身為 CoreOS,現為 Red Hat 的一部分)
  2. RancherOS
  3. Red Hat Atomic

這些發行版通常包含其他安全特性,如唯讀根檔案系統。當然,使用一般用途的 Linux 發行版也可以,但值得檢查您是否使用了安裝了過多函式庫和工具的映像檔(特別是如果您習慣性地使用傳統佈署中的相同機器映像檔)。

節點迴圈更新策略

在雲原生佈署中,我們將節點視為「牛而非寵物」,應該能夠輕鬆建立新節點或替換故障節點,這應透過基礎架構即程式碼的方法自動化。這使得節點迴圈更新成為可能,您可以定期(或隨機)拆除並替換節點迴圈更新帶來兩大好處:

  1. 消除設定漂移:當您迴圈更新節點時,它會還原到由基礎架構即程式碼定義的預期狀態。如果存在任何「漂移」(例如,因為未被檢測到的攻擊者獲得了系統立足點),這種漂移會被移除。

  2. 實作應急演練:特別是對於小型或新佈署,頻繁替換節點實際上是一種應急演練。如果您經常替換節點,您會對系統應對節點故障的能力更有信心。這是朝向混沌工程邁出的一小步!

沙箱隔離與執行時保護

沙箱隔離的本質

沙箱隔離是將容器彼此隔離並且底層主機隔離的能力,使得在一個容器中執行的程式碼無法影響該容器之外的環境。

執行時保護機制

執行時保護是限制容器內可執行程式碼集合的概念。如果攻擊者能夠存取容器,但無法在其中執行自己的程式碼,潛在損害就會受到限制。

雖然這兩個概念的最終目標不同,但在實作它們的機制上存在一些重疊。例如,seccomp 或 AppArmor 設定檔案可以限制容器只能存取有限的系統呼叫集。這既限制了容器能做的事情(執行時保護),又透過減少對內核的存取來增加其隔離性(沙箱隔離)。

容器分享主機的核心,因此核心中的漏洞可能允許攻擊從一個容器逃逸並移動到另一個容器或主機。

主流沙箱與執行時保護技術

目前有多個專案和廠商致力於改進沙箱隔離和/或執行時保護,每個都有自己的優勢和特點:

  1. seccomp:限制應用程式可以使用的系統呼叫的核心機制。可透過 securityContext 或 PodSecurityPolicy 指定 seccomp 設定檔案。

  2. AppArmor 和 SELinux:核心安全模組,也可透過 Kubernetes 中的 securityContext 或 PodSecurityPolicy 設定。

  3. Kata Containers:在「輕量級」虛擬機器中執行每個應用程式(因此每個都有自己的核心)。

  4. Google 的 gVisor:透過在使用者空間實作的核心 API 在沙箱中執行容器程式碼。

  5. Nabla containers:使用單核心技術提供隔離並限制對分享內核的存取。

  6. 企業容器安全解決方案:如 Aqua Security 和 Twistlock 使用常規容器,配合專有的執行時保護技術,包括白名單/黑名單控制特定容器中可執行的可執行檔案集。

多租戶架構設計

在某些佈署中,使用同一叢集的多個「租戶」可能彼此不完全信任,或者可能不被叢集營運者信任。租戶可以是使用者組或應用程式。

使用者之間的信任程度取決於環境;例如,在平台即服務 (PaaS) 環境中,使用者可以上載並執行自己的應用程式,他們應被視為完全不受信任的。而在企業中,租戶可能對映到不同的組織團隊,他們確實在一定程度上合作並相互信任,但希望限制團隊外部人員惡意或無意中影響另一團隊應用程式的風險。

多租戶隔離的兩個層面

多租戶隔離有兩個部分:

  1. 控制平面隔離:確保使用者無法執行影響其他租戶資源的 kubectl 命令
  2. 執行時和網路環境隔離:確保容器工作負載不能相互幹擾或竊取資源

根據名稱空間的多租戶實作

Kubernetes 名稱空間為我們提供了控制平面多租戶的第一個構建塊。通常,每個租戶會有一個名稱空間。使用者被授予 RBAC 許可權,可以在對映到其租約的名稱空間內建立、更新和刪除資源。

資源配額允許限制每個名稱空間(從而每個租戶)的計算和儲存資源,以及 Kubernetes 物件(例如,名稱空間內允許的服務、秘密和永續性儲存區宣告的上限)。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
  namespace: team-a
spec:
  hard:
    pods: "10"
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    services: "5"
    secrets: "20"

這個資源配額範例限制了 team-a 名稱空間的資源使用:最多10個 Pod、4個 CPU 請求單位、8GiB 記憶體請求、8個 CPU 限制單位、16GiB 記憶體限制、5個服務和20個 Secret。這種配額機制確保一個團隊不會消耗過多資源而影響其他團隊。

在企業環境中,這可能已經足夠。根據名稱空間的 RBAC 控制意味著一個團隊無法更新他們不負責的應用程式碼和相關 Kubernetes 資源。配額意味著一個團隊的應用程式不能使用所有可用資源,導致另一個團隊資源不足。

工作負載隔離策略

然而,在完全不受信任的環境中,這種保護可能不夠。在這裡,租戶工作負載應該在容器級別彼此隔離,這樣如果一個容器發生逃逸(可能是因為使用者佈署了具有嚴重漏洞的程式碼,甚至可能是故意的),他們就無法影響或檢查其他租戶的應用程式或資料。

容器沙箱隔離主要是為瞭解決這個問題(例如,gVisor 方法根據 Google App Engine 中 Google 隔離使用者工作負載的方式)。

另一種工作負載隔離方法是為每個租戶分配一個或多個節點,然後排程 Pod,使工作負載只與來自同一租戶的其他工作負載共存。這很簡單(使用汙點和容忍),但除非每個租戶需要一個節點的計算資源,否則可能會浪費資源。

在不受信任的多租戶環境中,您需要強大的網路策略來隔離流量,使其不能在名稱空間之間流動:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-from-other-namespaces
  namespace: team-a
spec:
  podSelector: {}
  ingress:
  - from:
    - podSelector: {}

這個網路策略範例在 team-a 名稱空間中應用,它允許來自同一名稱空間中任何 Pod 的流量(透過空的 podSelector),但拒絕來自其他名稱空間的所有流量。這是實作名稱空間網路隔離的簡單但有效的方法。

動態准入控制

從 Kubernetes 1.9 開始,動態准入控制器允許在允許資源佈署到叢集之前進行靈活、可擴充套件的檢查機制。例如,Kelsey Hightower 的 Grafeas 教程包含一個驗證 webhook,確保只有簽名映像才被允許佈署。

動態准入控制器分為兩種型別:

  1. 驗證性 Webhook:可以拒絕不符合策略的請求
  2. 變更性 Webhook:可以修改請求以符合策略

以下是一個驗證性 Webhook 的簡化設定範例:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: image-signature-validator
webhooks:
- name: validator.example.com
  rules:
  - apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
    operations: ["CREATE", "UPDATE"]
  clientConfig:
    service:
      namespace: validation-system
      name: validator-service
      path: "/validate"

這個設定義了一個驗證性 Webhook,它會攔截所有 Pod 的建立和更新操作,並將請求傳送到 validation-system 名稱空間中的 validator-service 服務的 /validate 路徑進行驗證。這種機制可用於實施各種安全策略,如確保只有簽名映像被佈署、強制執行特定標籤或註解等。

網路保護進階策略

在傳統佈署中,很大一部分安全措施是根據網路的:防火牆和 虛擬私人網路 的使用立即浮現在腦海中。在雲原生世界中,類別似的方法致力於限制流量,使得只有經批准的流量才能進行。

容器安全解決方案多年來一直談論網路微分段或奈米分段,這些方法透過使用網路策略在 Kubernetes 佈署中變得相當普遍。

服務網格安全功能

服務網格(如 Istio 或 Linkerd)的理念是承擔大部分網路通訊和控制的負擔,使應用程式開發人員不需要關心這些非功能效能力。雖然它們提供了負載平衡和路由等多種功能,但在安全方面,它們提供了兩個特別有趣的功能:

1. 相互認證的 TLS 連線

服務網格攔截進出 Pod 的網路流量,並確保連線使用 TLS 在經過認證的元件之間建立。這自動確保所有通訊都被加密。即使攻擊者進入您的叢集,他們也難以攔截其中的網路流量。

  flowchart LR
    A[服務 A] -->|加密 TLS 流量| B[Sidecar 代理]
    B -->|加密 TLS 流量| C[Sidecar 代理]
    C -->|加密 TLS 流量| D[服務 B]

2. 服務網格網路策略

服務網格可以控制哪些服務可以相互通訊,增加另一層保護,使攻擊者更難在叢集內移動。

Kubernetes 網路策略定義了允許進出一組 Pod 的流量,因此您可能想知道 Kubernetes 和服務網格網路策略如何互動。

Kubernetes 網路策略在網路層面工作,根據 IP 地址和連線埠以及 Pod(由標籤識別),而服務網格策略在服務層面工作。Project Calico 的一系列部落格文章對此有很好的討論。

YAML 靜態分析

在許多組織中,與應用程式相關的 YAML 可能由可能不熟悉組織要求的安全策略的開發人員編寫(或者可能只是犯了錯誤)。靜態分析工具如 kubetest 和 kubesec 可用於查詢 YAML 設定檔案中的問題(例如,檢查 Pod 是否使用了 privileged 標誌),或強制執行特定的標籤策略。

就像映像掃描一樣,這是「左移」的一個例子,其中安全實踐在開發生命週期的早期就被處理和強制執行。

資源型攻擊防禦

Fork 炸彈防禦

Fork 炸彈是一個不斷啟動自身副本的程式,目的是使用所有可用資源,有效地建立拒絕服務攻擊。Kubernetes 透過允許您設定 Pod 內程式數量的限制來解決這個問題。

其他根據資源的攻擊可能涉及嘗試消耗過多的記憶體和 CPU,拒絕這些資源給合法工作負載。您可以設定資源限制來限制這種攻擊的影響:

apiVersion: v1
kind: Pod
metadata:
  name: resource-limited-pod
spec:
  containers:
  - name: app
    image: myapp:1.0
    resources:
      limits:
        cpu: "1"
        memory: "512Mi"
      requests:
        cpu: "0.5"
        memory: "256Mi"

這個 Pod 規格設定了資源限制和請求:容器最多可使用 1 個 CPU 核心和 512MiB 記憶體,並請求保證有 0.5 個 CPU 核心和 256MiB 記憶體可用。這種限制可以防止單個容器消耗過多資源,無論是因為程式錯誤還是惡意攻擊。

加密貨幣挖礦防禦

一個著名的對 Tesla 的攻擊利用控制平面不安全性,允許駭客使用公司的資源挖掘加密貨幣。遵循基本的 Kubernetes 安全建議可以大防止這種情況在您的叢集中發生。

確保只有受信任的映像可以在您的叢集中執行,這可以防止具有批准存取許可權的惡意行為者執行意外的挖礦映像。

執行時保護可以增加另一層防禦,確保即使批准的映像有允許程式碼注入到執行容器中的漏洞,該程式碼也無法執行。

監控異常活動,如意外的 CPU 使用率和意外的資源擴充套件,可以幫助發現您的資源何時被攻擊者使用。

Kubernetes 安全更新

Kubernetes 本身的安全問題不時被發現,該專案有一個處理這些問題的安全流程。專案檔案包括向安全團隊報告 Kubernetes 漏洞的說明。

如果您希望在 Kubernetes 漏洞公佈時立即收到警示,請訂閱 kubernetes-announce 郵件列表。

安全實踐總結

在容器化世界中,安全是一個多層面的挑戰,需要從多個角度進行防禦。從 Kubelet 許可權控制到主機安全,從沙箱隔離到多租戶架構,從網路策略到服務網格,每一層都提供了獨特的保護。

最有效的安全策略結合了這些技術,同時考慮到組織的特定需求和風險承受能力。記住,安全不是一次性的工作,而是一個持續的過程,需要不斷學習、適應和改進。

隨著容器技術和 Kubernetes 生態系統的不斷發展,新的安全挑戰和解決方案也會不斷出現。保持警覺,積極參與社群,並定期更新您的安全知識和實踐,是確保您的 Kubernetes 環境安全的最佳方式。

希望這篇文章能幫助您建立更安全的 Kubernetes 環境。祝您在生產環境中安全愉快地使用 Kubernetes!