Kubernetes 中的 Seccomp:從一開始就需要了解的 7 件事

筆記。 翻譯。:我們向您展示英國公司 ASOS.com 的高級應用程式安全工程師翻譯的一篇文章。 以此為基礎,他開始發表一系列出版物,致力於透過使用 seccomp 來提高 Kubernetes 的安全性。 如果讀者喜歡這個介紹,我們將關注作者並繼續他未來關於該主題的材料。

Kubernetes 中的 Seccomp:從一開始就需要了解的 7 件事

本文是關於如何本著 SecDevOps 精神創建 seccomp 設定檔而不訴諸魔法和巫術的系列文章中的第一篇。 在第 XNUMX 部分中,我將介紹在 Kubernetes 中實作 seccomp 的基礎知識和內部細節。

Kubernetes 生態系統提供了多種保護和隔離容器的方法。 這篇文章是關於安全計算模式,也稱為 賽康。 其本質是過濾容器可供執行的系統呼叫。

為什麼它如此重要? 容器只是在特定機器上運行的進程。 它像其他應用程式一樣使用核心。 如果容器可以執行任何系統調用,惡意軟體很快就會利用這一點繞過容器隔離並影響其他應用程式:攔截訊息、更改系統設定等。

seccomp 設定檔定義應允許或停用哪些系統呼叫。 容器運行時在啟動時啟動它們,以便核心可以監視它們的執行。 如果容器內的任何程式(即您的依賴項或其依賴項)開始執行不允許執行的操作,使用此類設定檔可以限制攻擊向量並減少損壞。

了解基礎知識

基本的 seccomp 設定檔包括三個元素: defaultAction, architectures (或者 archMap)和 syscalls:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "sched_yield",
                "futex",
                "write",
                "mmap",
                "exit_group",
                "madvise",
                "rt_sigprocmask",
                "getpid",
                "gettid",
                "tgkill",
                "rt_sigaction",
                "read",
                "getpgrp"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(中等-基本-seccomp.json)

defaultAction 確定本節中未指定的任何系統呼叫的預設命運 syscalls。 為了讓事情變得更簡單,讓我們專注於將使用的兩個主要值:

  • SCMP_ACT_ERRNO — 阻止系統呼叫的執行,
  • SCMP_ACT_ALLOW - 允許。

在第 architectures 列出了目標架構。 這很重要,因為在核心層級應用的過濾器本身取決於系統呼叫標識符,而不是設定檔中指定的名稱。 容器運行時會將它們與使用前的標識符進行比對。 這個想法是,根據系統架構,系統呼叫可以有完全不同的 ID。 例如係統調用 recvfrom (用於從套接字接收訊息)在 x64 系統上 ID = 64,在 x517 上 ID = 86。 這裡 您可以找到 x86-x64 架構的所有系統呼叫的清單。

在該部分 syscalls 列出所有系統呼叫並指定如何處理它們。 例如,您可以透過設定建立白名單 defaultActionSCMP_ACT_ERRNO,並在該部分中調用 syscalls 分配 SCMP_ACT_ALLOW。 因此,您只允許在該部分中指定的呼叫 syscalls,並禁止所有其他。 對於黑名單,您應該更改值 defaultAction 和相反的行動。

現在我們應該談談不太明顯的細微差別。 請注意,以下的建議假設您正在 Kubernetes 上部署一系列業務應用程序,並且希望它們以盡可能少的權限運行。

1.AllowPrivilegeEscalation=false

В securityContext 容器有一個參數 AllowPrivilegeEscalation。 如果它安裝在 false,容器將以 (on) 少量 no_new_priv。 該參數的含義從名稱中顯而易見:它防止容器啟動比其本身擁有更多權限的新進程。

設定此選項的副作用 true (預設)是容器運行時在啟動過程的一開始就套用 seccomp 設定檔。 因此,運行內部運行時進程所需的所有系統呼叫(例如設定使用者/群組ID、刪除某些功能)必須在設定檔中啟用。

到一個做瑣碎事情的容器 echo hi,需要以下權限:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "brk",
                "capget",
                "capset",
                "chdir",
                "close",
                "execve",
                "exit_group",
                "fstat",
                "fstatfs",
                "futex",
                "getdents64",
                "getppid",
                "lstat",
                "mprotect",
                "nanosleep",
                "newfstatat",
                "openat",
                "prctl",
                "read",
                "rt_sigaction",
                "statfs",
                "setgid",
                "setgroups",
                "setuid",
                "stat",
                "uname",
                "write"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(hi-pod-seccomp.json)

……而不是這些:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "brk",
                "close",
                "execve",
                "exit_group",
                "futex",
                "mprotect",
                "nanosleep",
                "stat",
                "write"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(hi-container-seccomp.json)

但話又說回來,為什麼這是個問題呢? 就我個人而言,我會避免將以下系統呼叫列入白名單(除非確實需要它們): capset, set_tid_address, setgid, setgroups и setuid。 然而,真正的挑戰是,透過允許您完全無法控制的進程,您將設定檔與容器運行時實現聯繫起來。 換句話說,有一天你可能會發現,在更新容器運行時環境(無論是由你,還是更有可能由雲端服務提供者)後,容器突然停止運作。

提示#1:運行容器 AllowPrivilegeEscaltion=false。 這將減少 seccomp 設定檔的大小,並使它們對容器執行時間環境的變化不太敏感。

2. 在容器層級設定 seccomp 設定檔

seccomp 設定檔可以在 pod 層級設定:

annotations:
  seccomp.security.alpha.kubernetes.io/pod: "localhost/profile.json"

...或在容器層級:

annotations:
  container.security.alpha.kubernetes.io/<container-name>: "localhost/profile.json"

請注意,當 Kubernetes seccomp 時,上述語法將會改變 將成為GA (此事件預計在 Kubernetes 的下一個版本 - 1.18 - 大約翻譯中出現)。

很少人知道 Kubernetes 一直都有 漏洞這導致 seccomp 設定檔被應用到 暫停容器。 運行時環境部分彌補了這一缺點,但該容器並沒有從 Pod 中消失,因為它用於配置其基礎設施。

問題是這個容器總是以 AllowPrivilegeEscalation=true,導致第1段所述的問題,並且這是無法改變的。

透過在容器層級使用 seccomp 配置文件,您可以避免此陷阱,並且可以建立針對特定容器自訂的設定檔。 這必須在開發人員修復錯誤並且新版本(可能是 1.18?)可供所有人使用之前完成。

提示#2:在容器層級設定 seccomp 設定檔。

從實際意義上講,這條規則通常可以作為以下問題的通用答案:「為什麼我的 seccomp 設定檔可以與 docker run但部署到 Kubernetes 叢集後不起作用?

3.僅以運行時/預設作為最後的手段

Kubernetes 有兩個內建設定檔選項: runtime/default и docker/default。 兩者都是由容器運行時實現的,而不是 Kubernetes。 因此,它們可能會有所不同,具體取決於所使用的運行時環境及其版本。

換句話說,由於運行時的更改,容器可能有權訪問一組不同的系統調用,它可能會使用或不會使用這些系統調用。 大多數運行時使用 Docker 實現。 如果您想使用此配置文件,請確保它適合您。

輪廓 docker/default 自 Kubernetes 1.11 起已被棄用,因此請避免使用它。

在我看來,個人資料 runtime/default 完全適合其創建目的:保護用戶免受與執行命令相關的風險 docker run 在他們的車上。 然而,當涉及到在 Kubernetes 叢集上運行的業務應用程式時,我敢說這樣的設定檔過於開放,開發人員應該專注於為他們的應用程式(或應用程式類型)建立設定檔。

提示#3:為特定應用程式建立 seccomp 設定檔。 如果不可能,請為應用程式類型建立設定文件,例如,建立一個包含 Golang 應用程式的所有 Web API 的高級設定檔。 僅使用運行時/預設作為最後的手段。

在以後的文章中,我將介紹如何建立受 SecDevOps 啟發的 seccomp 設定檔、如何自動化它們以及如何在管道中測試它們。 換句話說,您沒有理由不升級到特定於應用程式的設定檔。

4. 不受限制不是一個選擇。

首次 Kubernetes 安全審計 事實證明,預設情況下 停用seccomp。 這意味著如果您不設定 PodSecurityPolicy,這將在叢集中啟用它,所有未定義 seccomp 設定檔的 pod 將在 seccomp=unconfined.

在此模式下運作意味著會失去保護叢集的整個絕緣層。 安全專家不推薦這種方法。

提示#4:叢集中不應運行任何容器 seccomp=unconfined,特別是在生產環境。

5.“審核模式”

這一點並不是 Kubernetes 獨有的,但仍然屬於「開始之前需要了解的事情」類別。

事實上,建立 seccomp 設定檔一直具有挑戰性,並且在很大程度上依賴於反覆試驗。 事實是,用戶根本沒有機會在生產環境中測試它們,而不冒「放棄」應用程式的風險。

Linux 核心 4.14 發布後,可以在審核模式下執行設定檔的一部分,在 syslog 中記錄有關所有系統呼叫的信息,但不會阻止它們。 您可以使用參數啟動此模式 SCMT_ACT_LOG:

SCMP_ACT_LOG:如果 seccomp 與過濾器中的任何規則不匹配,則 seccomp 不會影響進行系統呼叫的線程,但會記錄有關係統呼叫的資訊。

以下是使用此功能的典型策略:

  1. 允許需要的系統調用。
  2. 阻止來自您知道沒有用的系統的呼叫。
  3. 在日誌中記錄有關所有其他呼叫的資訊。

一個簡化的範例如下圖所示:

{
    "defaultAction": "SCMP_ACT_LOG",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "sched_yield",
                "futex",
                "write",
                "mmap",
                "exit_group",
                "madvise",
                "rt_sigprocmask",
                "getpid",
                "gettid",
                "tgkill",
                "rt_sigaction",
                "read",
                "getpgrp"
            ],
            "action": "SCMP_ACT_ALLOW"
        },
        {
            "names": [
                "add_key",
                "keyctl",
                "ptrace"
            ],
            "action": "SCMP_ACT_ERRNO"
        }
    ]
}

(中混合 seccomp.json)

但請記住,您需要阻止所有您知道不會使用且可能會損害叢集的呼叫。 編制清單的良好基礎是官方 Docker 文件。 它詳細解釋了預設設定檔中阻止哪些系統呼叫以及原因。

然而,有一個問題。 雖然 SCMT_ACT_LOG 它自 2017 年底以來就受到 Linux 核心的支持,直到最近才進入 Kubernetes 生態系統。 因此,要使用此方法,您需要 Linux 核心 4.14 和 runC 版本不低於 v1.0.0-rc9.

提示#5:可以透過結合黑名單和白名單來建立用於生產測試的審核模式設定文件,並且可以記錄所有異常。

6.使用白名單

白名單需要額外的工作,因為您必須識別應用程式可能需要的每個調用,但這種方法極大地提高了安全性:

強烈建議使用白名單方法,因為它更簡單、更可靠。 每當添加潛在危險的系統呼叫(或危險標誌/選項,如果它在黑名單上)時,就需要更新黑名單。 此外,通常可以在不改變參數本質的情況下改變參數的表示,從而繞過黑名單的限制。

對於 Go 應用程序,我開發了一個特殊的工具,該工具伴隨應用程式並收集執行期間進行的所有呼叫。 例如,對於以下應用程式:

package main

import "fmt"

func main() {
	fmt.Println("test")
}

……讓我們開始吧 gosystract 如下:

go install https://github.com/pjbgf/gosystract
gosystract --template='{{- range . }}{{printf ""%s",n" .Name}}{{- end}}' application-path

……我們得到以下結果:

"sched_yield",
"futex",
"write",
"mmap",
"exit_group",
"madvise",
"rt_sigprocmask",
"getpid",
"gettid",
"tgkill",
"rt_sigaction",
"read",
"getpgrp",
"arch_prctl",

目前,這只是一個範例,隨後將提供有關這些工具的更多詳細資訊。

提示#6:僅允許您真正需要的呼叫並阻止所有其他呼叫。

7. 奠定正確的基礎(或為意外行為做好準備)

無論您在其中寫入什麼內容,核心都會強制執行該設定檔。 即使這並不完全是你想要的。 例如,如果您阻止對類似呼叫的訪問 exitexit_group,容器將無法正確關閉,甚至像這樣的簡單命令 echo hi 把他掛起來o 無限期。 因此,您將在叢集中獲得較高的 CPU 使用率:

Kubernetes 中的 Seccomp:從一開始就需要了解的 7 件事

在這種情況下,公用事業公司可以提供救援 strace - 它將顯示問題可能是什麼:

Kubernetes 中的 Seccomp:從一開始就需要了解的 7 件事
sudo strace -c -p 9331

確保設定檔包含應用程式在運行時所需的所有系統呼叫。

提示#7:注意細節並確保所有必要的系統呼叫都列入白名單。

關於本著 SecDevOps 的精神在 Kubernetes 中使用 seccomp 的系列文章的第一部分到此結束。 在以下部分中,我們將討論為什麼這很重要以及如何自動化流程。

譯者PS

另請閱讀我們的博客:

來源: www.habr.com

添加評論