返回文章列表

Falco與EFK整合Kubernetes稽核

本文介紹如何利用 Falco 和 EFK 堆積疊在 Kubernetes 叢集中實作系統呼叫稽核。文章涵蓋了 Falco 規則、巨集和清單的定義,自定義規則的建立與附加,以及 Falco 的佈署方法。此外,還探討了 Falco 核心模組的安裝,包括使用安裝指令碼、driverkit 和核心標頭檔等不同方式。特別針對

資安 Kubernetes

Falco 作為 Kubernetes 叢集的執行時安全工具,能有效監控系統呼叫,並透過 EFK 堆積疊提供集中化的日誌管理和警示分析。在 Kubernetes 環境中佈署 Falco 時,核心模組的相容性至關重要。Falco 提供多種方式建立核心模組,包含使用預編譯模組、核心標頭檔或 driverkit。driverkit 工具能簡化核心模組的建立過程,尤其適用於 KinD 等特殊環境。透過本文提供的安裝指令碼和 driverkit 使用方法,能快速在 Kubernetes 叢集中佈署 Falco,並根據需求自定義規則,有效提升叢集安全性。

使用Falco與EFK進行稽核

瞭解Falco的規則、巨集和清單

在Falco中,規則(rules)、巨集(macros)和清單(lists)是三個基本的構成要素,用於定義和觸發安全事件的警示。

規則(Rules)

規則是Falco的核心,用於定義什麼樣的事件應該觸發警示。規則由條件(condition)、輸出(output)和優先順序(priority)組成。

巨集(Macros)

巨集是一種用於簡化規則條件的機制。它允許將複雜的條件表示式封裝成一個簡單的名字,從而使規則更易讀、更易維護。

- macro: k8s_api_server
  condition: (fd.sip.name="kubernetes.default.svc.cluster.local")

清單(Lists)

清單允許將多個專案分組到一個單一的物件中,該物件可以在規則、巨集或其他清單中使用。

- list: editors
  items: [vi, nano, emacs]

內容解密:

  1. 巨集的定義:在上述範例中,k8s_api_server 巨集定義了一個條件,用於檢查伺服器IP的網域名稱是否等於 kubernetes.default.svc.cluster.local
  2. 清單的使用:清單 editors 將多個編輯器名稱分組,使得在規則條件中可以直接參照該清單,而無需列舉所有編輯器名稱。

自定義規則的建立與附加

Falco提供了一組預設的規則檔案 falco_rules.yaml,但不建議直接修改該檔案。相反,應當在 falco_rules.local.yaml 檔案中新增或修改規則。

附加到現有規則

若要修改現有的規則,需要在 falco_rules.local.yaml 檔案中使用相同的規則名稱,並新增 append: true

- rule: program_accesses_file
  append: true
  condition: and not user.name=root

建立新規則

建立新規則只需在 falco_rules.local.yaml 檔案中新增新的規則定義。

佈署Falco

本章節提供了一個名為 falco-install.sh 的指令碼,用於佈署Falco到Kubernetes叢集。佈署Falco最常見的方法是使用官方的Helm chart或DaemonSet manifest。

內容解密:

  1. 佈署方法:Falco可以透過Helm chart或DaemonSet manifest佈署到Kubernetes叢集。
  2. 自定義佈署:本文使用了一個修改過的DaemonSet安裝方法,從GitHub倉函式庫中取得。

圖表翻譯:

此圖示展示了Falco的基本架構和元件之間的關係。

圖表翻譯: 此圖示呈現了Falco的工作流程,包括如何根據規則觸發警示,以及如何與Kubernetes叢集互動。圖中顯示了Falco規則如何根據監控資料觸發警示,並受到組態檔案的影響。

Falco 核心模組安裝詳解

在 Kubernetes 環境中使用 Falco 進行系統呼叫監控,需要佈署一個與主機作業系統核心版本相容的核心模組。本章節將詳細介紹如何使用包含的指令碼安裝 Falco,以及探討 Falco 核心模組的建立和佈署過程。

使用安裝指令碼佈署 Falco

執行安裝指令碼是佈署 Falco 的簡便方法。該指令碼位於 chapter12 資料夾中,名稱為 install-falco.sh。執行此指令碼將自動完成 Falco 的安裝。同時,資料夾中也提供了 delete-falco.sh 指令碼,用於從叢集中移除 Falco。

指令碼執行步驟解析

該安裝指令碼主要分為兩個部分:

  1. 建立 Falco 探針

    • 安裝 Go 語言環境
    • 提取 Falco 的 driverkit-builder 容器
    • 從 Git 下載 driverkit 原始碼並編譯
    • 使用 driverkit 建立 ubuntu-generic Falco 探針
    • falco.ko 複製到模組資料夾
    • 使用 modprobe 新增 Falco 探針
  2. 將 Falco 新增到叢集

    • 建立 Falco 名稱空間
    • falco/falco-config 中的檔案建立名為 falco-config 的 ConfigMap
    • 佈署 Falco DaemonSet

深入理解 Falco 核心模組

Falco 透過佈署核心模組來監控主機系統的系統呼叫。由於核心模組必須與主機核心相容,因此需要根據工作節點的主機作業系統選擇合適的模組。

Falco 載入或建立核心模組的方式

Falco 嘗試透過多種方式載入或建立核心模組:

  • 如果存在與主機核心相匹配的預編譯模組,Falco 將自動下載並使用該模組。
  • 如果沒有預編譯模組可用,Falco 將嘗試使用主機上已安裝的核心標頭檔構建模組。

使用 driverkit 建立 Falco 探針

目前,Falco 提供了一種早期存取的替代方法,使用名為 driverkit 的工具來建立探針。driverkit 根據主機機器的核心資訊自動建立新的探針。本文將詳細介紹如何使用 driverkit 為 KinD 叢集建立 Falco 探針。

在沒有預編譯模組的情況下建立核心模組

如果工作節點上沒有正確的核心標頭檔,Falco Pod 將嘗試下載與主機核心版本相匹配的預編譯探針。但在某些企業環境中,由於伺服器處於隔離狀態,無法連線網際網路,因此使用 driverkit 或核心標頭檔建立方法更為常見。

使用核心標頭檔建立 Falco 模組

對於 Ubuntu 系統,可以使用以下命令下載正確的核心標頭檔:

sudo apt install linux-headers-$(uname -r)

這將根據目前執行的核心版本安裝相應的核心標頭檔。安裝後,可以在 /lib/modules/ 目錄下驗證是否成功新增了對應的核心版本目錄。

為 KinD 叢集佈署 Falco

本文選擇使用 driverkit 方法建立核心模組,以簡化在 KinD 叢集上佈署 Falco 的過程。相較於使用核心標頭檔建立方法,driverkit 提供了一種更為便捷的解決方案。

為什麼選擇 driverkit

  • 簡化了在 KinD 環境中佈署 Falco 的過程。
  • 無需在每個工作節點上安裝核心標頭檔。
  • 自動化建立與主機核心相容的 Falco 探針。

Falco 安裝流程圖示

圖表翻譯: 此圖示展示了Falco的安裝流程。首先檢查是否存在預編譯的核心模組,如果存在則直接下載使用;如果不存在,則根據情況選擇使用核心標頭檔或driverkit來建立模組。最終將Falco佈署到叢集中,完成安裝流程。

使用 Driverkit 建立 Falco 核心模組

在某些特定的使用場景中,安裝核心標頭檔案可能會面臨挑戰或根本無法實作。如果無法使用標頭檔案來建立模組,可以利用 Falco 提供的一個名為 driverkit 的工具來建立核心模組。

Driverkit 簡介與支援的 Linux 發行版

Driverkit 允許為多種不同的 Linux 發行版建立核心模組。目前,該工具支援以下發行版:

  • Ubuntu-generic
  • Ubuntu-aws
  • CentOS 8
  • CentOS 7
  • CentOS 6
  • AmazonLinux
  • AmazonLinux2
  • Debian
  • Vanilla Kernel

開發團隊正在積極徵求其他發行版的建議,因此隨著 driverkit 的發展,可以預期將支援更多發行版。

使用 Driverkit 建立 Ubuntu 核心模組

Driverkit 的先決條件

在開始使用 driverkit 建立模組之前,需要滿足幾個先決條件:

  • 一個正在執行的 Docker 守護程式。
  • 已安裝 Go(由於我們使用的是 Ubuntu,因此將使用 longsleep/golang-backports)。
  • 目標核心版本和核心修訂版。

安裝 Falco 的 Driverkit

建立核心模組的第一步是安裝 driverkit 所需的依賴項:

  1. 首先,需要安裝 Go。由於我們使用的是 Ubuntu,可以使用 snap 安裝 Go:
sudo snap install --classic go
  1. 我們選擇使用 Docker 建構方法進行建構。driverkit 專案頁面中記載了多種建構方法,如果您想使用不同的建構方法,可以參考相關檔案。我們將提取 Docker 映像,以便在執行建構時準備就緒:
docker pull falcosecurity/driverkit-builder
  1. 下載容器後,可以建立 driverkit 可執行檔。建構過程將從 GitHub 下載原始碼,然後使用 Go 建立可執行檔。整個過程需要幾分鐘才能完成:
GO111MODULE="on" go get github.com/falcosecurity/driverkit
  1. 可執行檔將在您的 Go 路徑中建立。要驗證 driverkit 可執行檔是否成功建立,請輸入以下命令檢查版本:
driverkit -v
  1. 這可能會傳回版本號,或者在目前的早期版本中,可能只傳回以下內容:
driverkit version -+

如果 driverkit 命令傳回 -+ 或版本號,則表示成功建立。但是,如果在檢查版本時收到 driverkit: command not found 錯誤,則建構可能失敗,或者您的 Go 路徑在環境變數中未正確設定。如果在執行建構後找不到可執行檔,請驗證您的 Go 環境變數是否正確,然後再次執行 Go 建構步驟。

建立模組並將其新增至主機

在建立並驗證 driverkit 之後,我們可以建立我們的模組並將其新增至主機。在建立模組之前,需要知道主機的核心版本和修訂版。以我們在本文前幾章中使用的 KinD 叢集為例,Linux 有一些內建命令可以取得我們需要的兩個詳細資訊:

  1. 要取得核心版本,請執行 uname -v,而要取得修訂版,請執行 uname -r
uname -v
uname -r

此圖顯示了 Docker 主機的核心版本。

  1. 如果您正在使用安裝指令碼,我們將檢索選項並自動提供它們。如果您手動執行此步驟,可以使用以下兩行程式碼將資訊儲存在變數中,以傳遞給建構命令:
kernelversion=$(uname -v | cut -f1 -d'-' | cut -f2 -d'#')
kernelrelease=$(uname -r)

我們使用 cut 命令從 uname -v 命令中移除不必要的資訊,並將其儲存在名為 kernelversion 的變數中。我們還將 uname -r 命令的輸出儲存在名為 kernelrelease 的變數中。

  1. 現在,您可以使用我們提取的 Docker 映像和 driverkit 可執行檔來建立模組:
driverkit docker --output-module /tmp/falco.ko --kernelversion=$kernelversion --kernelrelease=$kernelrelease --driverversion=dev --target=ubuntu-generic

內容解密:

此命令使用 driverkit 工具,以 Docker 建構方法建立 Falco 核心模組。其中,--output-module 指定了輸出的模組檔案路徑,--kernelversion--kernelrelease 指定了目標核心的版本和修訂版,--driverversion 指定了驅動程式的版本,--target 指定了目標 Linux 發行版。

  1. 模組建構過程需要一分鐘,建構完成後,driverkit 將顯示新模組的位置:
INFO driver building, it will take a few seconds processor=docker
INFO kernel module available path=/tmp/falco.ko
  1. 最後一步是將新模組複製到正確的位置,並使用 modprobe 載入模組:
sudo cp /tmp/falco.ko /lib/modules/$kernelrelease/falco.ko
sudo depmod
sudo modprobe falco
  1. 您可以使用 lsmod 命令驗證模組是否已新增:
lsmod | grep falco

如果載入成功,您將看到類別似以下的輸出:

falco 634880 4

這樣,您就在主機上安裝了 Falco 模組,並且可以讓 KinD 叢集使用它。

在叢集上使用模組

在標準的 Kubernetes 叢集中,Falco 佈署會將 Falco 容器中的 /dev掛載點對映到主機的 /dev 掛載點。透過掛載 /dev,Falco pod 可以使用在工作節點主機作業系統上執行的核心模組。

在 KinD 中使用模組

您可能會問自己,將 Falco 模組新增到主機上如何使其可供 KinD 叢集使用?我們只將其新增到主機本身,而 KinD 叢集是在另一個 Docker 容器中執行的容器。那麼,KinD pod 如何使用來自 Docker 主機的模組?

Falco 模組載入流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Falco與EFK整合Kubernetes稽核

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml

圖表翻譯: 此圖表描述了 Falco 核心模組的載入流程。首先,建立 Driverkit,接著建立 Falco 核心模組,然後將模組新增至主機。最後,在 Kubernetes 叢集中佈署 Falco,並透過掛載 /dev 使 Falco Pod 能夠使用核心模組。