返回文章列表

Open Policy Agent Kubernetes 安全策略擴充套件

本文探討如何使用 Open Policy Agent (OPA) 和 GateKeeper 擴充套件 Kubernetes 的安全策略管理,涵蓋 Rego 策略語言的基礎、策略評估方法、強制記憶體限制的策略實作、以及如何利用 GateKeeper 快取機制最佳化策略執行效率。此外,文章也介紹瞭如何使用 Falco 和

Kubernetes 資安

Kubernetes 原生 Pod 安全策略機制即將棄用,Open Policy Agent (OPA) 和 GateKeeper 成為更靈活的安全策略方案。Rego 策略語言允許定義細緻的規則,例如強制 Pod 記憶體資源請求。GateKeeper 快取機制能有效提升策略評估效率,減少 API 伺服器負載。此外,Falco 與 EFK 堆積疊的整合提供更全面的容器安全稽核和事件分析能力,彌補 Kubernetes 原生稽核功能的不足。透過這些工具,可以更有效地控管叢集資源,提升安全性。

使用開放策略代理(Open Policy Agent)擴充套件安全性

在設計和實施策略時,詳細程度至關重要。為了確保策略的完整性,使用現有的、經過測試的策略是一個好方法。GateKeeper 專案在其 GitHub 儲存函式庫中維護了多個預先測試的策略函式庫。在嘗試建立自己的策略之前,應先檢查是否已有現成的策略可用。

Rego 與策略評估

本文概述了 Rego 的基本原理及其在策略評估中的運作方式。雖然沒有涵蓋所有內容,但為進一步查閱 Rego 檔案提供了良好的參考起點。接下來,我們將學習如何建立依賴於請求以外資料的策略,例如叢集中的其他物件。

強制記憶體限制

到目前為止,本章節中建立的策略都是自包含的。在檢查映像是否來自預授權的登入檔時,所需的資料僅來自策略和容器。然而,這通常不足以做出策略決策。在本文中,我們將建立一個依賴於叢集中其他物件的策略。

使用案例

在向 API 伺服器提交任何 Pod 時,至少應包含記憶體需求。然而,在某些名稱空間中,這並不那麼有意義。例如,kube-system 名稱空間中的許多容器沒有 CPU 和記憶體資源請求。

有多種方法可以處理這種情況。一種方法是佈署約束範本,並將其應用於每個需要強制記憶體資源請求的名稱空間。這可能導致重複的物件,或需要明確更新策略以將其應用於特定的名稱空間。另一種方法是向名稱空間新增標籤,讓 OPA 知道它需要所有 Pod 物件具有記憶體資源請求。由於 Kubernetes 已經具有用於管理記憶體的 ResourceQuota 物件,因此我們也可以確定名稱空間是否具有 ResourceQuota,如果有,則知道應該有記憶體請求。

建立強制記憶體請求的策略

我們的下一個範例將建立一個策略,規定在具有 ResourceQuota 的名稱空間中建立的任何 Pod 都必須具有記憶體資源請求。該策略本身應該很簡單。偽程式碼如下所示:

if (hasResourceQuota(input.review.object.metadata.namespace) &&
    containers.resource.requests.memory == null) {
  generate error;
}

困難的部分是瞭解名稱空間是否具有 ResourceQuota。

啟用 GateKeeper 快取

GateKeeper 快取透過在 gatekeeper-system 名稱空間中建立 Config 物件來啟用。將以下組態新增到叢集中:

apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
  name: config
  namespace: "gatekeeper-system"
spec:
  sync:
    syncOnly:
    - group: ""
      version: "v1"
      kind: "Namespace"
    - group: ""
      version: "v1"
      kind: "ResourceQuota"

這將開始在 GateKeeper 的內部 OPA 資料函式庫中複製 Namespace 和 ResourceQuota 物件。

模擬測試資料

為了自動化策略測試,我們需要建立測試資料。在前面的範例中,我們使用注入 input 變數的資料。快取資料儲存在 data 變數中。具體來說,為了存取我們的資源配額,我們需要存取 data.inventory.namespace["ns-with-quota"]["v1"]["ResourceQuota"]["memory-quota"]。這是從 Rego 中查詢 GateKeeper 中資料的標準方式。

{
  "inventory": {
    "namespace": {
      "ns-with-no-quota": {},
      "ns-with-quota": {
        "v1": {
          "ResourceQuota": {
            "memory-quota": {
              "kind": "ResourceQuota",
              "apiVersion": "v1",
              "metadata": {
                "name": "memory-quota",
                "namespace": "ns-with-quota"
              },
              "spec": {
                "hard": {
                  "requests.memory": "1G",
                  "limits.memory": "1G"
                }
              }
            }
          }
        }
      }
    }
  }
}

詳細解說

上述 JSON 資料結構模擬了 GateKeeper 快取中的資料,用於測試我們的策略。透過建立 data 物件,我們可以注入模擬版本的資料,從而在不將程式碼佈署到叢集中的情況下測試我們的策略。

重點整理

  • 使用現有的、經過測試的策略可以提高策略的完整性。
  • Rego 是用於定義和評估策略的語言。
  • GateKeeper 提供了一種機制來快取叢集中的資料,以便在策略評估中使用。
  • 透過模擬測試資料,可以自動化測試我們的策略。

策略開發最佳實踐

  1. 重用現有策略:在開發新策略之前,先檢查是否已有現成的策略可用。
  2. 詳細設計和測試:確保策略設計周密,並進行充分的測試。
  3. 利用 GateKeeper 快取:使用 GateKeeper 快取機制來存取叢集中的資料。
  4. 模擬測試資料:透過模擬測試資料來自動化測試我們的策略。

使用 Open Policy Agent 擴充套件安全性

建置與佈署策略

如同之前的操作,在撰寫策略之前,我們已經先寫好了測試案例。接下來,我們將檢視我們的策略:

package k8senforcememoryrequests

violation[{"msg": msg, "details": {}}] {
    invalidMemoryRequests
    msg := "No memory requests specified"
}

invalidMemoryRequests {
    data.inventory.namespace[input.review.object.metadata.namespace]["v1"]["ResourceQuota"]
    containers := input.review.object.spec.containers
    ok_containers = [ok_container |
        containers[j].resources.requests.memory ;
        ok_container = containers[j]
    ]
    count(containers) != count(ok_containers)
}

內容解密:

  1. package k8senforcememoryrequests:定義了 Rego 策略的套件名稱,用於識別和組織相關的規則。
  2. violation 規則:這是 GateKeeper 的標準報告規則,用於輸出違規訊息。當 invalidMemoryRequests 成立時,會設定 msg 為 “No memory requests specified”,並將其包含在違規訊息中。
  3. invalidMemoryRequests 規則:檢查 Pod 是否在具有 ResourceQuota 的名稱空間中執行,並且其容器是否指定了記憶體請求。
    • data.inventory.namespace[input.review.object.metadata.namespace]["v1"]["ResourceQuota"]:檢查特定名稱空間中是否存在 ResourceQuota 物件。如果不存在,則規則失敗並離開。
    • containers := input.review.object.spec.containers:載入 Pod 的所有容器。
    • ok_containers = [ok_container | containers[j].resources.requests.memory ; ok_container = containers[j] ]:使用列表推導式建立一個只包含已指定記憶體請求的容器的列表。
    • count(containers) != count(ok_containers):比較總容器數量和已符合記憶體請求設定的容器數量。如果數量不相等,表示至少有一個容器未指定記憶體請求,規則成功。

要佈署此策略,請將 chapter11/enforce-memory-request/yaml/gatekeeper-policy-template.yamlchapter11/enforce-memory-request/yaml/gatekeeper-policy.yaml 新增到您的叢集中。

使用 OPA 強制實施 Pod 安全策略

在 Kubernetes 中,現有的 Pod 安全策略實作將不會進入 “GA” 狀態。使用 OPA 和 GateKeeper 可以在 OPA 中強制實施相同的策略,而不是在 API 伺服器上。GateKeeper 的策略釋出於 https://github.com/open-policy-agent/gatekeeper/tree/master/library/pod-security-policy

主要差異

  1. 宣告式定義:使用 GateKeeper,您必須在 Pod 定義中宣告所有內容,以便 GateKeeper 有東西可以稽核。這與 Kubernetes 的 Pod 安全策略不同,後者會改變 Pod 定義以符合策略。

  2. 策略指派:GateKeeper 使用名稱空間和標籤選擇器來匹配策略,而 Kubernetes 標準實作則使用 RBAC 和 Pod 的 serviceAccount 及請求的功能來決定使用哪個策略。

  3. 策略分割:GateKeeper 的策略函式庫被分割成多個物件。要套用一個強制執行非特權容器在特定使用者範圍內執行的策略,您需要兩個單獨的策略約束實作和兩個單獨的約束。

使用Falco與EFK進行稽核

在大多數執行Kubernetes叢集的環境中,您需要有一個稽核系統來監控叢集的執行狀態。Kubernetes本身具備一些稽核功能,但往往過於有限,無法滿足企業對完整稽核軌跡的需求。幸運的是,有許多第三方日誌系統可供選擇,例如Splunk、Datadog等付費系統,以及EFK(Elasticsearch、Fluentd、Kibana)堆積疊等開源系統。

探索稽核

Kubernetes的原生稽核功能主要集中在API存取事件上,但這並不足以滿足大多數企業的需求。企業通常需要擴充套件或自定義稽核目標,以涵蓋更廣泛的事件型別。Falco是一個開源專案,可以為您的Pod提供增強的稽核功能,記錄API伺服器未記錄的事件。

為什麼需要Falco?

當使用者在Pod中執行命令時,例如使用kubectl exec -it <pod name> bash,這會向API伺服器傳送請求,但後續在Pod中執行的命令不會被記錄。這對於企業來說是一個很大的稽核漏洞,因為這可能導致惡意行為未被檢測到。

引入Falco

Falco是一個開源的容器安全工具,可以檢測並報警異常行為。它可以監控系統呼叫,並根據預定義的規則進行報警。Falco可以與EFK堆積疊整合,提供強大的日誌收集和分析功能。

Falco的組態檔案

Falco的組態檔案定義了要監控的事件和規則。您可以自定義這些檔案以滿足特定的需求。

佈署Falco

要佈署Falco,您需要在Kubernetes叢集中安裝Falco的DaemonSet。DaemonSet將在每個節點上執行一個Falco例項。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: falco
spec:
  selector:
    matchLabels:
      name: falco
  template:
    metadata:
      labels:
        name: falco
    spec:
      containers:
      - name: falco
        image: falcosecurity/falco:latest
        securityContext:
          privileged: true

Falco核心模組

Falco需要一個核心模組來監控系統呼叫。您可以選擇使用核心模組或eBPF探針。

使用EFK堆積疊進行日誌收集和分析

EFK堆積疊是一個強大的日誌收集和分析工具。它包括Elasticsearch(用於儲存和索引日誌)、Fluentd(用於收集和轉發日誌)和Kibana(用於視覺化日誌資料)。

佈署EFK堆積疊

要佈署EFK堆積疊,您需要在Kubernetes叢集中安裝Elasticsearch、Fluentd和Kibana。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
重點回顧
  • Falco是一個開源的容器安全工具,可以檢測並報警異常行為。
  • EFK堆積疊是一個強大的日誌收集和分析工具。
  • 將Falco與EFK堆積疊整合,可以提供全面的稽核功能。

問題與解答

  1. OPA和GateKeeper是相同的東西嗎?
    • A. 是
    • B. 否

答案:B. 否

  1. Rego程式碼在GateKeeper中如何儲存?
    • A. 儲存為ConfigMap物件。
    • B. 需要掛載到Pod中。
    • C. 需要儲存為Secret物件。
    • D. 儲存為ConstraintTemplate。

答案:D. 儲存為ConstraintTemplate

內容解密:

Rego是一種用於定義策略的語言,GateKeeper使用Rego來定義和管理策略。Rego程式碼儲存在ConstraintTemplate中,這些範本定義了策略的結構和規則。

  1. 如何測試Rego策略?
    • A. 在生產環境中測試。
    • B. 使用內建於OPA的自動化框架。
    • C. 首先編譯成Web Assembly。

答案:B. 使用內建於OPA的自動化框架

內容解密:

OPA提供了內建的測試框架,用於測試Rego策略。可以使用opa test命令執行測試,並使用-v選項檢視詳細的執行跟蹤。

  1. 在Rego中如何寫一個for迴圈?
    • A. 不需要寫,Rego會自動識別迭代步驟。
    • B. 使用for all語法。
    • C. 初始化迴圈計數器。
    • D. Rego中沒有迴圈。

答案:B. 使用for all語法

內容解密:

Rego使用for all語法來實作迭代。這種語法允許您對集合中的每個元素進行操作。

  1. 如何除錯Rego策略?
    • A. 使用IDE附加到GateKeeper容器。
    • B. 在生產環境中除錯。
    • C. 在程式碼中新增trace函式,並使用opa test -v檢視執行跟蹤。
    • D. 使用System.out陳述式。

答案:C. 在程式碼中新增trace函式,並使用opa test -v檢視執行跟蹤

內容解密:

在Rego程式碼中新增trace函式,可以輸出除錯資訊。使用opa test -v命令執行測試,可以檢視詳細的執行跟蹤,從而幫助除錯Rego策略。