淺析容器運(yùn)行時(shí)安全加固
隨著云計(jì)算的蓬勃發(fā)展,云原生的概念于2013年被提出,Pivotal 公司的 Matt Stine 在概念中提出了云原生的4個(gè)要點(diǎn):DevOps、持續(xù)交付、微服務(wù)、容器。而在 2015 年 Google 主導(dǎo)成立了云原生計(jì)算基金會(huì)(CNCF),CNCF 也給出了對(duì)云原生(Cloud Native)的定義,其中包含三個(gè)方面:1)應(yīng)用容器化;2)面向微服務(wù)架構(gòu);3)應(yīng)用支持容器的編排調(diào)度。
隨著近幾年來云原生生態(tài)的不斷壯大,所有主流云計(jì)算供應(yīng)商都加入了該基金會(huì), CNCF 基金會(huì)中的會(huì)員以及容納的項(xiàng)目越來越多,原先的定義已經(jīng)限制了云原生生態(tài)的發(fā)展,到了 2018 年 CNCF 為云原生進(jìn)行了重新定位,同時(shí)指出云原生的代表技術(shù)包括容器、服務(wù)網(wǎng)格、微服務(wù)、不可變基礎(chǔ)設(shè)施和聲明式 API。圍繞這些概念、定義和代表技術(shù),最為基礎(chǔ)的就是容器和微服務(wù)。在容器應(yīng)用之前,相關(guān)的云計(jì)算的應(yīng)用多數(shù)運(yùn)行于虛擬機(jī)上,但虛擬機(jī)會(huì)有額外的資源浪費(fèi)和維護(hù)成本,并且其啟動(dòng)速度較慢。正是容器技術(shù)所具有的占用資源少、部署速度快和便于遷移等特點(diǎn),助力了云原生生態(tài)的蓬勃發(fā)展,其中 Docker 和 Kubernetes 是企業(yè)容器運(yùn)行時(shí)和容器編排的首要選擇。
而于此同時(shí),如何保證云原生環(huán)境的安全性也在不斷受到挑戰(zhàn)。在云原生技術(shù)應(yīng)用的過程中,大多數(shù)企業(yè)都遇到過不同程度的安全問題,無論是前兩年爆出的某著名車企的容器集群入侵事件,還是容器官方鏡像倉庫 Docker Hub 存在惡意鏡像,用戶在享受云原生相關(guān)技術(shù)便利的同時(shí),也產(chǎn)生了極大的安全擔(dān)憂。而作為云原生的基石——容器的安全性更是重中之重,為了滿足云原生業(yè)務(wù)上對(duì)安全防護(hù)工具的全面性、便捷性以及性能上的要求,圍繞著容器運(yùn)行時(shí)安全的多個(gè)內(nèi)核安全特性也在不斷發(fā)展,本文將對(duì)近年來針對(duì)容器運(yùn)行過程中的安全加固技術(shù)進(jìn)行逐一介紹。(在本文中,若無特殊說明,容器指代 Docker 容器)
1、容器安全概述
在實(shí)現(xiàn)云原生的主要技術(shù)中,容器作為支撐應(yīng)用運(yùn)行的重要載體,為應(yīng)用的運(yùn)行提供了隔離和封裝,成為云原生應(yīng)用的基礎(chǔ)設(shè)施底座。與虛擬機(jī)不同的是,虛擬機(jī)模擬了硬件系統(tǒng),每個(gè)虛擬機(jī)都運(yùn)行在獨(dú)立的 Guest OS 上,而容器之間卻共享操作系統(tǒng)內(nèi)核,并未實(shí)現(xiàn)完全的隔離。若虛擬化軟件存在缺陷,或宿主機(jī)內(nèi)核被攻擊,將會(huì)造諸多的安全問題,包括隔離資源失效、容器逃逸等,影響宿主機(jī)上的其他容器甚至整個(gè)內(nèi)網(wǎng)環(huán)境的安全(下圖展示了 VM 和容器在系統(tǒng)架構(gòu)上的差異)。
據(jù)《Sysdig 2022 云原生安全和使用報(bào)告》顯示,超過75%的運(yùn)行容器存在高危或嚴(yán)重漏洞、62%的容器被檢測出包含 shell 命令、76%的容器使用 root 權(quán)限運(yùn)行。鑒于云原生的攻擊手段的獨(dú)特性, 安全組織 MITRE 的對(duì)抗戰(zhàn)術(shù)和技術(shù)知識(shí)庫(ATT&CK 框架)在2021年推出了專門針對(duì)容器的攻擊模型。云原生安全在近年來獲得了大量的關(guān)注。
Google 在其 GCP 上討論容器安全風(fēng)險(xiǎn)時(shí),依據(jù)容器風(fēng)險(xiǎn)的來源,將其分為了三個(gè)方面:
- 基礎(chǔ)架構(gòu)安全:主要是指容器管理平臺(tái)能夠提供的基本功能的安全。
- 軟件供應(yīng)鏈安全:主要是指容器鏡像安全。
- 運(yùn)行時(shí)安全:確保安全響應(yīng)團(tuán)隊(duì)能夠檢測到環(huán)境中運(yùn)行的容器所面臨的安全威脅。
而 Google 的這個(gè)分類方法,其實(shí)也可以歸結(jié)抽象為對(duì)容器生命周期中三個(gè)過程的安全:
- 構(gòu)建時(shí)安全:在容器鏡像構(gòu)建過程中,分析構(gòu)建鏡像時(shí)所使用的命令和配置參數(shù),還原鏡像文件構(gòu)建過程,掌握命令使用的敏感操作,以及分析鏡像文件是否包含密碼、令牌、密鑰和用戶機(jī)密信息等敏感信息。同時(shí),分析鏡像的軟件組成,發(fā)現(xiàn)鏡像文件中包含的惡意文件、病毒和木馬,以及所使用的依賴庫和組件存在的安全漏洞,避免鏡像本身存在的安全風(fēng)險(xiǎn)。
- 部署時(shí)安全:分析鏡像無風(fēng)險(xiǎn)后,鏡像被提交至鏡像倉庫。在該階段,將檢查容器環(huán)境的鏡像倉庫配置,確保使用加密方式連接鏡像倉庫。當(dāng)鏡像倉庫中新增鏡像或使用鏡像創(chuàng)建容器時(shí),自動(dòng)化校驗(yàn)鏡像簽名或MD5值,確保鏡像來源可信且未被篡改,一旦發(fā)現(xiàn)鏡像來源不可信或被篡改,禁止使用該鏡像創(chuàng)建容器。
- 運(yùn)行時(shí)安全:當(dāng)確認(rèn)鏡像安全后,進(jìn)入到容器運(yùn)行階段。該階段主要是是保證容器運(yùn)行環(huán)境的安全,防止容器出現(xiàn)異常行為,這其中就包括主機(jī)環(huán)境配置安全、容器守護(hù)進(jìn)程配置安全、容器應(yīng)用的運(yùn)行安全。
在容器生命周期的三個(gè)過程中,攻擊者往往是在前兩個(gè)階段部署相關(guān)的惡意代碼,在容器運(yùn)行時(shí)對(duì)環(huán)境真正執(zhí)行相關(guān)的攻擊指令。因此,容器運(yùn)行時(shí)相比于其他兩個(gè)階段更直接、也更容易分析出環(huán)境中的惡意行為。與其他虛擬化技術(shù)類似,逃逸也是針對(duì)容器運(yùn)行時(shí)存在的漏洞最為嚴(yán)重的攻擊利用行為。攻擊者可通過利用漏洞“逃逸”出自身擁有的權(quán)限范圍,實(shí)現(xiàn)對(duì)宿主機(jī)或者宿主機(jī)上其他容器的訪問,其中最為簡單的就是造成宿主機(jī)的資源耗盡,往往會(huì)直接危害底層宿主機(jī)和整個(gè)云原生系統(tǒng)的安全。根據(jù)風(fēng)險(xiǎn)所在層次的不同,可以進(jìn)一步展開為:危險(xiǎn)配置導(dǎo)致的容器安全風(fēng)險(xiǎn)、危險(xiǎn)掛載導(dǎo)致的容器安全風(fēng)險(xiǎn)、相關(guān)程序漏洞導(dǎo)致的容器安全風(fēng)險(xiǎn)、內(nèi)核漏洞導(dǎo)致的容器安全風(fēng)險(xiǎn):
- 危險(xiǎn)配置導(dǎo)致的容器安全風(fēng)險(xiǎn):用戶可以通過修改容器環(huán)境配置或在啟動(dòng)容器時(shí)指定參數(shù)來改變?nèi)萜鞯南嚓P(guān)約束,但如果用戶為一些不完全受控的容器配置了某些危險(xiǎn)的配置參數(shù),就為攻擊者提供了一定程度的可以攻擊利用的安全漏洞,例如未授權(quán)訪問帶來的容器安全風(fēng)險(xiǎn),特權(quán)模式運(yùn)行帶來的容器安全風(fēng)險(xiǎn)。
- 危險(xiǎn)掛載導(dǎo)致的容器安全風(fēng)險(xiǎn):將宿主機(jī)上的敏感文件或目錄掛載到容器內(nèi)部,尤其是那些不完全受控的容器內(nèi)部,往往也會(huì)帶來安全風(fēng)險(xiǎn)。這種掛載行為可以通過環(huán)境配置來設(shè)定,也可以在運(yùn)行時(shí)進(jìn)行動(dòng)態(tài)掛載,因此這里單獨(dú)地歸為一類。隨著應(yīng)用的逐漸深化,掛載操作變得愈加廣泛,甚至為了實(shí)現(xiàn)特定功能或方便操作,使用者會(huì)選擇將外部敏感資源或文件系統(tǒng)直接掛載入容器,由此而來的安全問題也呈現(xiàn)上升趨勢。例如:掛載 Docker Socket 引入的容器安全風(fēng)險(xiǎn)、掛載宿主機(jī) procfs、sysfs 引入的容器安全問題等。
- 相關(guān)程序漏洞導(dǎo)致的容器安全風(fēng)險(xiǎn):所謂相關(guān)程序漏洞,指的是那些參與到容器運(yùn)行、管理的服務(wù)端以及客戶端程序自身存在的漏洞。例如,CVE-2019-5736、CVE-2021-30465、CVE-2020-15257等存在于 Container Daemon、runC 上的容器安全漏洞。
- 內(nèi)核漏洞導(dǎo)致的容器安全風(fēng)險(xiǎn):Linux 內(nèi)核漏洞的危害之大、影響范圍之廣,使得它在各種攻防話題下都占有一席之地,特別是在容器環(huán)境中由于容器與宿主機(jī)共享了內(nèi)核,攻擊者可以直接在容器中對(duì)內(nèi)核漏洞進(jìn)行利用攻擊。近年來,Linux 系統(tǒng)曝出過無數(shù)內(nèi)核漏洞,例如最有名氣的漏洞之一——臟牛(CVE-2016-5195)漏洞也能用來進(jìn)行容器逃逸。
安全容器的漏洞安全容器是為了解決內(nèi)核共享問題導(dǎo)致的安全風(fēng)險(xiǎn)所研發(fā)的一種運(yùn)行時(shí)技術(shù),它為容器應(yīng)用提供一個(gè)完整的操作系統(tǒng)執(zhí)行環(huán)境(常常是 Linux ABI),將應(yīng)用的執(zhí)行環(huán)境與宿主機(jī)操作系統(tǒng)隔離開,避免應(yīng)用直接訪問主機(jī)資源,從而可以在容器主機(jī)之間或容器之間提供額外的保護(hù)。例如,Kata Containers 就是為每一個(gè)容器運(yùn)行一個(gè)獨(dú)立虛擬機(jī),從而避免其與宿主機(jī)共享內(nèi)核。無論是理論上,還是實(shí)踐中,安全容器都具有非常高的安全性。然而在 2020 年 Black Hat 北美會(huì)議上,Yuval Avrahami 分享了利用多個(gè)漏洞成功從 Kata containers 逃逸的議題,安全容器首次被發(fā)現(xiàn)存在逃逸可能性,他使用發(fā)現(xiàn)的三個(gè)漏洞(CVE-2020-2023、CVE-2020-2025 和 CVE-2020-2026)組成漏洞利用鏈先后進(jìn)行容器逃逸和虛擬機(jī)逃逸,成功從容器內(nèi)部逃逸到宿主機(jī)上。
為緩解甚至消除這些容器運(yùn)行時(shí)的安全隱患,社區(qū)提供了一系列強(qiáng)化配置并且多年來也研發(fā)了相關(guān)的加固工具。CIS 發(fā)布的 Docker 基線已成為 Linux 主機(jī)配置和 Docker 主機(jī)加固的最佳實(shí)踐。同樣,CIS也發(fā)布了 Kubernetes 基線,傳統(tǒng)的漏洞掃描工具、獨(dú)立的容器安全產(chǎn)品(如 Aqua Security 和 NeuVector)和私有維護(hù)人員已經(jīng)在 GitHub 上發(fā)布了腳本,可實(shí)現(xiàn)自動(dòng)化的 Kubernetes 安全檢查。接下來,我們將著重介紹一些行而有效的容器運(yùn)行時(shí)的安全加固技術(shù)以及近年來的一些發(fā)展。
2、容器運(yùn)行時(shí)安全加固
運(yùn)行時(shí)安全是在容器運(yùn)行時(shí)通過檢測和防止惡意行為來提供主動(dòng)保護(hù),可以說是整個(gè)容器生命周期中的最后一道安全屏障。其核心思想就是監(jiān)控并限制容器中高危的行為,縮小容器進(jìn)程的能力和權(quán)限。容器本身是利用了 Namespace 和 Cgroup 技術(shù),將容器和宿主機(jī)之間的資源進(jìn)行了隔離并加以限制。
NamespaceNamespace 即命名空間,也被稱為名稱空間,這是 Linux 提供的一種內(nèi)核級(jí)別的環(huán)境隔離功能,它的主要用途是對(duì)容器提供資源的訪問隔離,這些資源包括文件系統(tǒng)掛載 、主機(jī)名和域名、進(jìn)程間通信 、進(jìn)程訪問、網(wǎng)絡(luò)隔離、用戶和組隔離等。容器充分利用了 Namespace 的技術(shù),使其達(dá)到盡可能地隔離容器之間以及對(duì)宿主機(jī)的影響。
CgroupCgroup全稱為 Control Group,它也是容器的重要特性。如果說 Namespace 是用于隔離,那么 Cgroup 則是限制容器對(duì)于資源的占用,如CPU、內(nèi)存、磁盤 I/O 等。這個(gè)特性可以有效地避免某個(gè)容器因?yàn)楸?DDOS 攻擊或者自身程序的問題導(dǎo)致對(duì)資源的不斷占用,并最終影響到宿主機(jī)及上面運(yùn)行的其他容器,出現(xiàn)“雪崩”的災(zāi)難 。
雖然這種隔離限制從資源層面實(shí)現(xiàn)了對(duì)容器和宿主機(jī)之間的環(huán)境獨(dú)立,宿主機(jī)的資源對(duì)容器不再可見,但是這種方式并沒有達(dá)到真正意義上的安全隔離。由于容器的內(nèi)核與宿主內(nèi)核共享,一旦容器中通過惡意行為進(jìn)行一些高危的操作權(quán)限,或者是利用內(nèi)核漏洞,往往就可以突破這種資源上的隔離,造成容器逃逸,重新危害到宿主機(jī)及上面運(yùn)行的其他容器。
目前 Linux 內(nèi)核提供了一系列的安全能力可以對(duì)這些攻擊行為進(jìn)行有效防護(hù)。結(jié)合內(nèi)核安全技術(shù)的能力,這些技術(shù)的作用范圍可以簡單地分為兩種:一種是限制是限制行為本身,另一種則是限制行為作用的對(duì)象范圍。首先我們介紹如果有效切斷這些造成逃逸的惡意行為,如何去限制發(fā)起行為的能力。
2.1 Capabilities 和 Seccomp
在 Linux 系統(tǒng)中 Root 用戶作為超級(jí)用戶擁有全部的操作權(quán)限,以 Root 身份運(yùn)行容器,相當(dāng)于將打開容器資源限制大門的鑰匙交給了容器自身,這是十分危險(xiǎn)的。但如果以非 Root 身份在后臺(tái)運(yùn)行容器的話,由于缺少權(quán)限容器中的應(yīng)用進(jìn)程容易處處受限。為了適應(yīng)這種復(fù)雜的權(quán)限需求,Linux 細(xì)化了 Root 權(quán)限的管控能力,從 2.2 版本起 Linux 內(nèi)核能夠進(jìn)一步將超級(jí)用戶的權(quán)限分解為細(xì)顆粒度的單元,這些單元稱為 Capabilities。例如,CAP_CHOWN 允許用戶對(duì)文件的 UID 和 GID 進(jìn)行任意修改,即執(zhí)行 chown 命令。
*Capabilities 詳細(xì)信息可通過 Linux Programmer's Manual 進(jìn)行查看:https://man7.org/linux/man-pages/man7/capabilities.7.html
幾乎所有與超級(jí)用戶相關(guān)的特權(quán)都被分解成了單獨(dú)的 Capability,可以分別啟用或禁用。這種系統(tǒng)權(quán)限機(jī)制提供了細(xì)粒度的操作權(quán)限的訪問控制,控制容器運(yùn)行所需的 Capabilities 范圍,可以有效切斷容器中攻擊者的行為操作。即使容器攻擊者取得了 Root 權(quán)限,由于不能獲得主機(jī)的完全的操作權(quán)限,也進(jìn)一步限制了攻擊對(duì)宿主機(jī)的破壞。Docker 在容器管理中默認(rèn)限制了容器的 Capabilities, 其中僅開啟如下部分:
但是基于 Capabilities 的權(quán)限訪問管理,有時(shí)候并不能很好地限制住容器的操作權(quán)限。例如,SYS_ADMIN 管理了 mount,umount,pivot_root,swapon,swapoff,sethostname,setdomainname 等等系統(tǒng)調(diào)用的訪問權(quán)限,一旦應(yīng)用進(jìn)程因?yàn)樾枰M(jìn)行 sethostname 這樣的操作而在容器中開啟了 SYS_ADMIN 組的 Capabilities,那么也就讓容器具有了 mount 這類可以掛載系統(tǒng)資源的操作權(quán)限,導(dǎo)致容器存在逃逸的風(fēng)險(xiǎn)。Seccomp(Secure Computing Mode)同樣也是一種 Linux 內(nèi)核提供的安全特性,它可以以白名單或黑名單的方式限制進(jìn)程進(jìn)行系統(tǒng)調(diào)用。相對(duì)于 Capabilities 將系統(tǒng)調(diào)用以組的形式進(jìn)行分類管理,Seccomp 是對(duì)系統(tǒng)調(diào)用更細(xì)粒度的單點(diǎn)控制。
Seccomp 首次于內(nèi)核 2.6.12 版合入 Linux 主線。早期的 Seccomp 只支持過濾使用四個(gè)系統(tǒng)調(diào)用:read,write,_exit,sigreturn。在這種安全模式下,除了已打開的文件描述符和允許的四種系統(tǒng)調(diào)用,一旦進(jìn)程嘗試訪問其他系統(tǒng)調(diào)用,內(nèi)核就會(huì)使用 SIGKILL 或 SIGSYS 信號(hào)來終止該進(jìn)程。由于這種限制太過于嚴(yán)格,在實(shí)際應(yīng)用中作用并不大。
為了解決此問題,2012 年的內(nèi)核 3.5 版本引入了一種新的 Seccomp 模式,叫做 SECCOMP_MODE_FILTER。這個(gè)功能允許用戶使用可配置的策略過濾系統(tǒng)調(diào)用,該策略使用 Berkeley Packet Filter(BPF)規(guī)則實(shí)現(xiàn),從而使 Seccomp 可以對(duì)任意的系統(tǒng)調(diào)用及其參數(shù)(僅常數(shù),無法指針解引用)進(jìn)行過濾。因此使用這種模式的的 Seccomp 也被稱之為 Seccomp-BPF。而程序在 fork/clone 或 execve 時(shí),BPF 過濾規(guī)則是可以從父進(jìn)程繼承到子進(jìn)程,因此 Seccomp 機(jī)制可以很好地用于限制容器的權(quán)限。
seccomp 設(shè)定的系統(tǒng)調(diào)用過濾規(guī)則能傳遞給子程序的關(guān)鍵在于 prctl 系統(tǒng)調(diào)用:
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
prctl 的 No New Privileges Flag 可以避免類似 execve 的系統(tǒng)調(diào)用授予父進(jìn)程沒有的權(quán)限。詳見:https://man7.org/linux/man-pages/man2/prctl.2.html
目前 docker 在運(yùn)行容器時(shí)會(huì)使用默認(rèn)配置,其中禁止了約 44 個(gè)系統(tǒng)調(diào)用,當(dāng)然也可以使用 --security-opt 選項(xiàng)將默認(rèn)的配置文件替換為自定義的配置文件。
*docker默認(rèn)配置詳見:https://github.com/moby/moby/blob/master/profiles/seccomp/default.json
在 5.0 版本內(nèi)核中又加入了新的 seccomp-unotify 模式。Seccomp-BPF 模式對(duì)系統(tǒng)調(diào)用的判斷過程是由加載到內(nèi)核的 BPF 程序來完成的,而 Seccomp-unotify 機(jī)制可以將這一判斷過程移交給另一個(gè)用戶態(tài)的進(jìn)程來完成。同時(shí),利用該模式 Filter 進(jìn)程不僅可以檢測系統(tǒng)調(diào)用的參數(shù),還可以對(duì)指針參數(shù)進(jìn)行解引用,查看指針?biāo)赶虻膬?nèi)存。這就方便了判斷程序?qū)φ{(diào)用行為的分析判斷,大大擴(kuò)充了 Seccomp 機(jī)制的過濾能力。作為一種新增特性,Seccomp-unotify 模式更為強(qiáng)大的過濾能力相信后續(xù)會(huì)在容器安全加固中擁有比較大的使用空間。
需要注意的是,這種位于 syscall 入口處的檢查判斷是存在 TOCTTOU(Time Of Check To Time Of Use)風(fēng)險(xiǎn)的——風(fēng)險(xiǎn)就在于此時(shí)的一些內(nèi)存數(shù)據(jù)依舊保存在用戶空間,從入口檢測到實(shí)際使用還需要一定的時(shí)間,攻擊者完全可以在這段時(shí)間內(nèi)通過其他并發(fā)線程對(duì)用戶空間上的數(shù)據(jù)進(jìn)行修改。因此 Seccomp 以及 Capabilities 的優(yōu)勢不在于限制容器中的進(jìn)程能否通過 syscall 去訪問一些特定的資源,而在于直接去排除容器中進(jìn)程發(fā)起這類 syscall 行為的能力。接下來我們也將討論如何更有效地限制這些行為的作用對(duì)象,以及阻斷逃逸后的攻擊者對(duì)宿主機(jī)中其他資源的訪問。
2.2 MAC 和 LSM
Namespace 機(jī)制讓容器和宿主機(jī)之間實(shí)現(xiàn)了資源上的隔離,讓宿主機(jī)上的其他資源對(duì)容器不再可見。但是這種虛擬隔離并沒有限制容器中進(jìn)程的訪問權(quán)限,資源訪問權(quán)限的管理卻是由 Linux DAC(Discretionary Access Control,自主訪問控制,以下簡稱 DAC)機(jī)制來完成的,它主要依賴的進(jìn)程的 uid 和 gid 來進(jìn)行管理。因此一旦容器中的攻擊者突破了 Namespace 的界限,往往就可以對(duì)容器外的資源進(jìn)行訪問。而解決這一安全風(fēng)險(xiǎn)的關(guān)鍵就是——強(qiáng)制訪問控制(Mandatory Access Control——MAC,以下簡稱MAC)。其中最為熟知的 MAC 訪問控制安全模塊,就是 SELinux、AppArmor等。
SELinux
早期的操作系統(tǒng)幾乎沒有考慮安全問題,系統(tǒng)中只有一個(gè)用戶并且可以訪問系統(tǒng)任何資源。而隨著多用戶系統(tǒng)的發(fā)展,為了有效限制用戶的訪問權(quán)限,確保用戶只能訪問他們需要的資源,出現(xiàn)了訪問控制機(jī)制來增強(qiáng)安全性。其中主要的訪問控制就是 DAC 機(jī)制。DAC 通常允許授權(quán)用戶自主改變客體的訪問控制屬性,這樣就可指定其他用戶是否有權(quán)訪問該客體。然而,DAC 機(jī)制只約束了用戶、同用戶組內(nèi)的用戶、其他用戶對(duì)文件的可讀、可寫、可執(zhí)行權(quán)限,這對(duì)系統(tǒng)的保護(hù)作用非常有限。
Linux 系統(tǒng)中所有內(nèi)容都是以文件的形式保存和管理的,即一切皆文件。
為了克服這種脆弱性,出現(xiàn)了 MAC 機(jī)制,其基本原理是利用配置的安全策略來控制對(duì)客體的訪問,且這種訪問不被單個(gè)程序和用戶所影響。SELinux(Security-Enhanced Linux)是由美國國家安全局(NSA)聯(lián)合其他安全機(jī)構(gòu)(比如 SCC 公司)共同開發(fā)的一套 MAC 安全認(rèn)證機(jī)制,并在 Linux 2.6 版本后集成在內(nèi)核中。SELinux 規(guī)定了每個(gè)對(duì)象(程序、文件和進(jìn)程等)都有一個(gè)安全上下文(Security Context),它依附于每個(gè)對(duì)象身上,包含了許多重要的信息,包括 SELinux 用戶(不同于Linux系統(tǒng)的用戶)、角色(Role)、類型(Type)和級(jí)別(Security Level)等。
管理員可以通過定制安全策略(Security Policy)來定義這些安全上下文,從而定義哪種對(duì)象具有什么權(quán)限。當(dāng)一個(gè)對(duì)象需要執(zhí)行某個(gè)操作時(shí),系統(tǒng)會(huì)按照該對(duì)象以及該對(duì)象要操作的對(duì)象的安全上下文所定制的安全策略來檢查相對(duì)應(yīng)的權(quán)限。如果全部權(quán)限都符合,系統(tǒng)就會(huì)允許該操作,否則將阻斷這個(gè)操作。
SELinux 與 DAC
在啟用了 SELinux 的 Linux 操作系統(tǒng)中,SELinux 并不是取代傳統(tǒng)的 DAC 機(jī)制。當(dāng)某個(gè)對(duì)象需要執(zhí)行某個(gè)操作時(shí),需要先通過 DAC 機(jī)制的檢測,再由 SELinux 定制的安全策略來檢測。如果 DAC 規(guī)則拒絕訪問,則根本無需使用 SELinux 策略。只有通過 DAC 和 SELinux 的雙重權(quán)限檢查確認(rèn)之后,才能執(zhí)行操作。
SELinux 其中一個(gè)重要概念就是 TE(Type Enforcement,類型強(qiáng)制),其原理是將權(quán)限與程序的上下文結(jié)合在一起,而不是與執(zhí)行程序的用戶,這是目前使用最為廣泛的 MAC 檢測機(jī)制。
SELinux 支持兩種 MAC 檢測機(jī)制
Type Enforcement (TE)
顧名思義,Type Enforcement 是根據(jù)安全上下文中的 type 進(jìn)行權(quán)限審查,審查主體的 type 對(duì)客體的 type 的某種操作是否具有訪問權(quán)限,主要集中于程序訪問控制決策。
Multi-Level Security (MLS)
多層安全機(jī)制,是基于Bell-La Padula (BLP) 模型,將主體和客體定義成多層次的安全等級(jí),不同安全等級(jí)之間有相關(guān)的訪問約束,常見的訪問約束是 "no write down" 和 "no read up"。它是根據(jù)安全上下文中的最后一個(gè)字段 label 進(jìn)行確認(rèn)的。
它允許管理者可以基于程序的功能和安全屬性,加上用戶要完成任務(wù)所需的訪問權(quán)作出訪問決策,將程序限制到功能合適、權(quán)限最小化的程度。并且這個(gè)安全策略采用的是白名單方法,這意味著程序在運(yùn)行過程中只能被授予策略中明確允許的訪問權(quán)限。因此,即使某個(gè)程序出現(xiàn)了故障或被攻擊,但整個(gè)系統(tǒng)的安全并不會(huì)受到威脅。
容器與 SELinux
容器在默認(rèn)配置下是沒有開啟 SELinux 功能的,需要管理者修改 Docker 守護(hù)進(jìn)程中的參數(shù)配置進(jìn)行開啟。
如何為容器啟用 SELinux:
1.在 dockerd 啟動(dòng)時(shí)加上 --selinux-enabled 參數(shù),在 CentOS上 可以修改 systemd 配置文件 docker.service
2.在/etc/docker/daemon.json配置文件中加上:{ "selinux-enabled": true } 然后重啟 docker 服務(wù)
開啟 SELinux 后,依據(jù)自帶的默認(rèn)策略,啟動(dòng)容器中的進(jìn)程一般會(huì)打上 container_t 的標(biāo)簽,容器具備操作權(quán)限的資源則一般會(huì)打上 container_file_t 的標(biāo)簽。(docker 每創(chuàng)建一個(gè)容器,容器中對(duì)象的安全上下文還會(huì)分配一個(gè)額外的信息—— Category,以此來確保容器之間的訪問隔離。簡單點(diǎn)說是說一個(gè)容器A中的進(jìn)程是無法訪問容器B的資源)
這樣容器中的進(jìn)程就無法對(duì)容器中的一些特殊資源進(jìn)行修改,甚至是逃逸后這些進(jìn)程依舊無法對(duì)宿主機(jī)的其他資源進(jìn)行訪問。
需要注意的是,docker 在啟動(dòng)過程中可以通過 -v 參數(shù)額外掛載一些宿主機(jī)上的目錄/文件。如果直接掛載在容器中進(jìn)行訪問時(shí),操作是會(huì)被 SELinux 阻止:
# docker run -it --rm -v /tmp/HostDIR:/host/tmp/HostDIR ubuntu root@f724f5437895:/# ls -lZ /host/tmp/ total 0 drwxr-xr-x. 2 root root unconfined_u:object_r:user_tmp_t:s0 22 Oct 12 10:05 HostDIR root@f724f5437895:/# ls -lZ /host/tmp/HostDIR/ ls: cannot open directory '/host/tmp/HostDIR/': Permission denied
需要通過加上后綴 :z 或者 :Z 來改變掛載資源的上下文的標(biāo)簽。兩者存在區(qū)別,具體可以查看 Docker ,詳見:Docshttps://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container---volumes-from
# docker run -it --rm -v /tmp/HostDIR:/host/tmp/HostDIR:Z ubuntu root@62e115c4771c:/# ls -l /host/tmp/ total 0 drwxr-xr-x. 2 root root 22 Oct 12 10:05 HostDIR root@62e115c4771c:/# ls -lZ /host/tmp/ total 0 drwxr-xr-x. 2 root root system_u:object_r:container_file_t:s0:c132,c528 22 Oct 12 10:05 HostDIR root@62e115c4771c:/# ls -lZ /host/tmp/HostDIR/ total 4 -rw-r--r--. 1 root root system_u:object_r:container_file_t:s0:c132,c528 18 Oct 12 10:05 HostFile root@62e115c4771c:/# cat /host/tmp/HostDIR/HostFile This is a host file
近年來比較突出的利用 procfs/sysfs 中的特殊文件進(jìn)行容器逃逸的方法,在利用 SELinux 對(duì)容器環(huán)境進(jìn)行加固后,是可以進(jìn)行有效阻止。以利用 /proc/sys/kernel/modprobe 進(jìn)行容器逃逸為例,作為宿主機(jī)相關(guān)的文件 modprobe 被配置了 usermodehelper_t 的標(biāo)簽,對(duì)于容器中的進(jìn)程 modprobe 文件是沒有寫權(quán)限的,也就阻止了攻擊者進(jìn)行逃逸的操作。
利用 /proc/sys/kernel/modprobe 進(jìn)行容器逃逸的原理
/proc/sys/kernel/modprobe 用于設(shè)置自動(dòng)加載內(nèi)核模塊相關(guān) usermode helper 的完成路徑,默認(rèn)是 /sbin/modprobe,Linux內(nèi)核安裝或卸載模塊的時(shí)候就會(huì)觸發(fā)這個(gè)被指定的 usermode helper。
在 Documentation for /proc/sys/kernel/ - The Linux Kernel documentation中也提到:“if userspace passes an unknown filesystem type to mount(), then the kernel will automatically request the corresponding filesystem module by executing this usermode helper.”。
也就是說執(zhí)行一個(gè)未知的文件類型,內(nèi)核也會(huì)去調(diào)用這個(gè)指定的程序。
攻擊者就可以替換原有的 modprobe_path 為惡意代碼的地址,之后執(zhí)行一個(gè)未知文件類型,內(nèi)核就會(huì)去調(diào)用惡意文件,執(zhí)行惡意代碼。
但是這個(gè)攻擊的利用需要一定的權(quán)限,在 docker 中默認(rèn) /proc/sys/kernel/modprobe 是不可寫入的,需要對(duì) /proc/sys 以 rw 方式 remount 才可以修改文件內(nèi)容,這就需要被攻擊的容器環(huán)境具有 SYS_ADMIN 的權(quán)限。
*Documentation for /proc/sys/kernel/ - The Linux Kernel documentation 原文詳見:https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#modprobe
AppArmor
另一個(gè)用于此目的的類似的 Linux 內(nèi)核安全模塊是 AppArmor。AppArmor 得到了開發(fā) Linux Ubuntu 發(fā)行版的母公司 Canonical 的支持,其目的是希望開發(fā)一個(gè)比 SELinux 更簡單易用的訪問控制模塊。
RedHat 旗下的所有 Linux 發(fā)行版都預(yù)裝或提供 SELinux 設(shè)置,包括 RHEL、CentOS 和 Fedora,而 AppArmor 安裝在 Debian、Ubuntu、它們的衍生發(fā)行版以及 SUSE Enterprise Server 和 OpenSUSE 發(fā)行版上。
與 SELinux 不同,AppArmor 是作為 DAC 機(jī)制的補(bǔ)充,用于限制指定目標(biāo)程序的資源訪問權(quán)限,例如是否允許讀/寫某個(gè)特定的目錄/文件、打開/讀/寫網(wǎng)絡(luò)端口以及是否具備某類 Linux Capabilities 等。為了簡單易用,Apparmor使用文件名(路徑名)作為安全標(biāo)簽,而SELinux使用文件的 inode 作為安全標(biāo)簽。在文件系統(tǒng)中,只有inode才具有唯一性,因此相比于 SELinux,通過改名等方式,AppArmor 存在被繞過的風(fēng)險(xiǎn)。
Docker 本身也提供了對(duì)于容器環(huán)境的默認(rèn) AppArmor 配置,啟動(dòng)容器時(shí)系統(tǒng)會(huì)自動(dòng)應(yīng)用 docker-default 安全配置文件,配置文件通過 template 模板生成,(Docker 也設(shè)計(jì)了針對(duì) docker 守護(hù)進(jìn)程的配置文件 contrib/apparmor,但是當(dāng)前并沒有包含在 docker 相關(guān)發(fā)行包中),也可以通過 --security-opt apparmor=<profile-name> 命令行選項(xiàng)指定自定義的配置文件。
*template 模板詳見:https://github.com/moby/moby/blob/master/profiles/apparmor/template.go,Docker 守護(hù)進(jìn)程的配置文件 contrib/apparmor詳見:https://github.com/moby/moby/tree/master/contrib/apparmor
管理者可以通過檢查進(jìn)程的 /proc/<pid>/attr/current 文件來查看對(duì)應(yīng)進(jìn)程是否配置了相應(yīng)的 AppArmor 配置文件:
通過配置 AppArmor 同樣可以阻斷之前提到的逃逸攻擊,例如 docker-default 配置中不僅限制了容器進(jìn)程對(duì) procfs/sysfs 等敏感文件/目錄的寫權(quán)限,并且限制容器中進(jìn)程進(jìn)行 mount 操作。(利用 AppArmor 的配置文件同樣可以限制容器 Capabilities 權(quán)限,并配置 Seccomp 功能)
LSM 的現(xiàn)狀
不管是 SELinux 還是 AppArmor 其實(shí)都是 Linux 安全模塊(Linux Security Module,以下簡稱 LSM),都是基于 LSM 框架—— Linux 操作系統(tǒng)內(nèi)核提供的一種安全機(jī)制,來完成對(duì)進(jìn)程對(duì) Linux 資源訪問權(quán)限的判斷(Capabilities 其實(shí)也是一個(gè) LSM 模塊)。LSM 雖然被稱作“模塊”,但不同于 LKM(Loadable Kernel Module),這些擴(kuò)展并不是可加載的內(nèi)核模塊,而是和內(nèi)核代碼一起編譯在內(nèi)核文件(vmlinuz)中,并且只能在系統(tǒng)啟動(dòng)時(shí)就進(jìn)行初始化。
LSM 與 SELinux
在2001年的 Linux Kernel 峰會(huì)上,NSA 代表建議在 Linux Kernel 2.5 中加入 SELinux。然而,這一提議遭到了 Linus Torvalds 的拒絕。一方面,SELinux 并不是惟一用于增強(qiáng) Linux 安全性的安全子系統(tǒng);另一方面,并不是所有的開發(fā)人員都認(rèn)為 SELinux 是最佳解決方案。最終 SELinux 沒能加入到 Linux Kernel 2.5,取而代之的是 Linux Security Module 的開發(fā)被提上日程。
LSM 子系統(tǒng)自提出后開發(fā)了近3年,并終于在 Linux Kernel 2.6正式加入到內(nèi)核中,隨之應(yīng)運(yùn)而生了大量LSM,比如 SELinux、SMACK、AppArmor、TOMOYO、Yama、loadPin、SetSafeID、Lockdown 等。
從上圖可以看出 LSM 框架在Linux安全體系中所處的位置,LSM hook 點(diǎn)一般會(huì)被插入到被訪問的內(nèi)核對(duì)象與 DAC 檢查之間。系統(tǒng)在完成 DAC 檢查通過之后,然后根據(jù) LSM 框架調(diào)用系統(tǒng)中啟用的 LSM 模塊,檢查是否允許訪問,這也是為什么 SELinux 的檢查是在 DAC 之后的原因。同時(shí)我們也可以看到與之前 Seccomp 在系統(tǒng)調(diào)用入口點(diǎn)的檢測判斷不同,LSM Hook 點(diǎn)所在的位置基本上位于實(shí)際資源的訪問之前,在這個(gè)時(shí)候相關(guān)的數(shù)據(jù)信息已經(jīng)從用戶空間復(fù)制到內(nèi)核空間中,也就不會(huì)再有攻擊者在用戶空間進(jìn)行篡改的可能性。
如果系統(tǒng)中有多個(gè) LSM 模塊,就會(huì)根據(jù) LSM 在初始化時(shí)的優(yōu)先順序依次執(zhí)行,所有檢查都被允許才可以繼續(xù)訪問內(nèi)核對(duì)象。通過使用 LSM 框架,就可以進(jìn)行內(nèi)核安全審計(jì)和元數(shù)據(jù)捕獲。安全開發(fā)人員只需要按照既定的調(diào)用規(guī)范編寫 LSM 模塊,并加載進(jìn) Linux 內(nèi)核,不再需要對(duì)系統(tǒng)內(nèi)核代碼進(jìn)行修改。這就方便了安全人員不在受限于已有的 AppArmor、SELinux 等模塊可以基于自身公司容器環(huán)境的實(shí)際需求,定制化的開發(fā)更為輕便的訪問控制模塊,有針對(duì)性地保障容器環(huán)境。而 Linux 5.4中加入的 lockdown 模塊直接禁止了運(yùn)行時(shí)對(duì)內(nèi)核的動(dòng)態(tài)修改,使得 LSM 框架成為 Linux 安全加固工具開發(fā)的最佳途徑之一。
LSM Stacking
當(dāng)前的 Linux 系統(tǒng)雖然支持多個(gè) LSM 模塊的運(yùn)行,但是這種運(yùn)行依然存在著很大的限制,例如 SELinux 和 AppArmor 不能運(yùn)行在同一系統(tǒng)中。其實(shí)基于這種限制,LSM 模塊被劃分為兩種:Major LSM 和 Minor LSM。目前 Linux 系統(tǒng)中提供的 Major LSM 包括 SELinux、SMACK、AppArmor 和 TOMOYO,這四個(gè)模塊都是 MAC 的實(shí)現(xiàn)。LSM 框架在最初設(shè)計(jì)時(shí)只允許啟用一個(gè) LSM 模塊,Major LSM 模塊在設(shè)計(jì)開發(fā)時(shí)都假設(shè)自己擁有對(duì)受保護(hù)內(nèi)核對(duì)象的安全上下文指針和安全標(biāo)識(shí)符的獨(dú)占訪問權(quán)限。例如進(jìn)程相關(guān)的“/proc/[pid]/attr”目錄下的相關(guān)文件,就是用來標(biāo)記進(jìn)程的安全屬性,像“/proc/[pid]/attr/current”文件,被 SELinux 用來標(biāo)識(shí)進(jìn)程的安全上下文,而 AppArmor 模塊則用于標(biāo)識(shí)進(jìn)程對(duì)應(yīng)的配置文件。由于 Major LSM 所具有的排他性,即使四個(gè)安全模塊都編譯進(jìn)了內(nèi)核,內(nèi)核在啟動(dòng)時(shí)只能打開一個(gè) Major LSM 模塊。而 Minor LSM 模塊則沒有這種排他性,可以同時(shí)運(yùn)行在系統(tǒng)中。相比于 Major LSM,他們的作用范圍更小,較少地訪問或者使用內(nèi)核對(duì)象的安全上下文指針,例如 YAMA 模塊主要是對(duì) Ptrace 函數(shù)調(diào)用進(jìn)行訪問控制。其他 Minor LSM 模塊還有 LoadPin、SetSafeID、Lockdown 等。并且他們一般直接硬編碼了大部分安全策略,相對(duì)地 Major LSM 模塊則可以加載用戶可配置的安全策略。在 Linux 5.1 版本之前,通過啟動(dòng)參數(shù) “security=”,內(nèi)核在啟動(dòng)時(shí)確認(rèn)打開哪個(gè) Major LSM 模塊,若未指定則按照 Kconfig 編譯配置中 CONFIG_DEFAULT_SECURITY 的值啟動(dòng)。
為了更便于多個(gè) LSM 模塊的加載使用,LSM 框架在近年來也在逐步逐步消除 Major LSM 模塊之間獨(dú)占性的問題。從 5.1 版本開始,改進(jìn)了模塊的啟動(dòng)方式,啟動(dòng)參數(shù)由 “l(fā)sm=” 替換了原有的 “security=”(參數(shù)被保留,但是存在 “l(fā)sm=” 參數(shù)時(shí),不起作用), Kconfig 編譯配置中 CONFIG_DEFAULT_SECURITY 也被替換為 CONFIG_LSM。內(nèi)核在啟動(dòng)過程中會(huì)按照 “l(fā)sm=” 參數(shù)中的順序啟動(dòng)相應(yīng)的的 LSM 模塊。
為了區(qū)分Major LSM 和 Minor LSM,引入了 LSM_FLAG_LEGACY_MAJOR 和 LSM_FLAG_EXCLUSIVE 標(biāo)志來標(biāo)注對(duì)應(yīng)的 LSM 模塊的排他性。如果啟動(dòng)順序中配置多個(gè) Major LSM 模塊,那么在啟動(dòng)過程中,內(nèi)核會(huì)按照順序只打開第一個(gè)具有 LSM_FLAG_EXCLUSIVE 標(biāo)志的模塊。當(dāng)然這部分只是對(duì)模塊啟動(dòng)的優(yōu)化,改進(jìn)的另一個(gè)重要的目標(biāo)就是可以讓一個(gè)系統(tǒng)中開啟多個(gè) Major LSM 模塊。從 5.1 版本開始 TOMOYO 已經(jīng)被消除了排他性標(biāo)記,而 AppArmor 也很快將可以消除這一標(biāo)記,與其他 MAC 模塊同時(shí)運(yùn)行在同一系統(tǒng)中(參考 LSM: Module stacking for AppArmor)。這種特性的發(fā)展為不同業(yè)務(wù)容器配置不同的 MAC 模塊帶來了可能性。
*LSM: Module stacking for AppArmor,詳見:https://lwn.net/ml/linux-kernel/20220415211801.12667-1-casey@schaufler-ca.com/
2.3 eBPF 觀測與防護(hù)
eBPF,全稱為擴(kuò)展的伯克利數(shù)據(jù)包過濾器(Extended Berkeley Packet Filter),是傳統(tǒng) BPF(以下稱為 cBPF)的后繼者。之前我們介紹過 SECCOMP_MODE_FILTER 模式下的 Seccomp 也是通過 cBPF 來構(gòu)建自定義的系統(tǒng)調(diào)用篩查規(guī)則。cBPF 最初的設(shè)計(jì)目標(biāo)是用于過濾網(wǎng)絡(luò)數(shù)據(jù)包的,受限在內(nèi)核空間使用,只有少數(shù)用戶空間程序(例如:tcpdump和 seccomp)可以編寫這類過濾器。
2014 年,Alexei Starovoitov 對(duì) cBPF 進(jìn)行徹底地改造,實(shí)現(xiàn)了更為高效的 eBPF。時(shí)至今日 cBPF 現(xiàn)在已經(jīng)基本廢棄,Linux 內(nèi)核只運(yùn)行 eBPF,內(nèi)核會(huì)將加載的 cBPF 轉(zhuǎn)換成 eBPF 再執(zhí)行。下面是 CBPF 和 eBPF 的對(duì)比:(參考【19】)
eBPF 的設(shè)計(jì)的最初目標(biāo)是針對(duì)現(xiàn)代硬件進(jìn)行的優(yōu)化,生成指令集更接近硬件的 ISA(Instruction Set Architecture),所以 eBPF 相比于原有的 BPF 解釋器生成的機(jī)器碼執(zhí)行得更快。在這之后更重要的一步改進(jìn)優(yōu)化就是將 eBPF 擴(kuò)展到用戶空間,提供了用戶空間和內(nèi)核空間數(shù)據(jù)交互的能力,這也使得 eBPF 可以適用于更為復(fù)雜的數(shù)據(jù)觀察和分析場景中。隨著越來越多的新特性被合入到 Linux 內(nèi)核社區(qū),eBPF 支持的功能已經(jīng)越來越豐富,擴(kuò)展了內(nèi)核態(tài)函數(shù)、用戶態(tài)函數(shù)、跟蹤點(diǎn)、性能事件(perf_events)以及 LSM 等事件類型。下表列出了目前 eBPF 一些重要的特性(詳細(xì)可參見 BPF Features by Linux Kernel Version:https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md):
隨著這些改進(jìn)的加入,eBPF 的使用場景也不再僅僅是網(wǎng)絡(luò)分析,可以基于 eBPF 開發(fā)性能分析、系統(tǒng)追蹤、網(wǎng)絡(luò)優(yōu)化、安全防護(hù)等多種類型的工具和平臺(tái),許多最新的檢測、監(jiān)控軟件和性能跟蹤工具都是基于 BPF 技術(shù),并且在云原生社區(qū)中,eBPF 被大量項(xiàng)目采用(例如 Cilium、Falco、Tracee)。
*Cilium詳見:https://docs.cilium.io/en/v1.8/intro/、Falco詳見:https://falco.org/、Tracee詳見:https://github.com/aquasecurity/tracee
eBPF 程序本身是一個(gè)標(biāo)準(zhǔn)的 ELF(可執(zhí)行和可鏈接格式,Executable and Linkable Format)文件,一般由 C 語言開發(fā)并使用 LLVM 編譯而成。作為標(biāo)準(zhǔn)的對(duì)象文件,同樣可以用像 readelf 這樣的工具來檢查,其中包含程序字節(jié)碼和所有映射的定義。之后用戶空間程序就可以通過 bpf() 系統(tǒng)調(diào)用將 eBPF 字節(jié)碼加載到內(nèi)核,在加載的過程中,內(nèi)核會(huì)使用驗(yàn)證器組件對(duì)字節(jié)碼的安全性進(jìn)行驗(yàn)證,避免 eBPF 程序不會(huì)對(duì)內(nèi)核造成崩潰影響。在 eBPF 程序運(yùn)行過程中,如果有需要就可以通過 Maps 或者 perf-event 事件將執(zhí)行結(jié)果或者檢測到的數(shù)據(jù)信息回傳至用戶空間程序,并且用戶空間程序也可以通過 Maps 給 eBPF 程序傳遞數(shù)據(jù)。下圖是 eBPF 整個(gè)流程的圖示:
2.4 eBPF 與 LSM 模塊
相較于 LSM 框架,eBPF 提供了一種更加簡便安全的方式在 Linux 內(nèi)核中運(yùn)行自定義的代碼。通過編寫內(nèi)核模塊來改變或擴(kuò)展內(nèi)核行為,往往需要足夠的內(nèi)核編程知識(shí),并且在編寫使用過程中需要十分謹(jǐn)慎,以免因?yàn)橐恍┦韬鰩韮?nèi)核代碼崩潰的問題,甚至留下攻擊者可以利用的漏洞。因此為了保障內(nèi)核安全性,往往內(nèi)核模塊的開發(fā)以及內(nèi)核新版本的發(fā)布,都需要長時(shí)間的分析測試。
而 eBPF 程序的開發(fā)則不需要通過復(fù)雜的內(nèi)核編譯,只需要引入相關(guān)結(jié)構(gòu)體的頭文件申明,這就給 eBPF 程序的開發(fā)降低了難度。同時(shí) eBPF 在安全性保證上提供了一道有效的屏障—— eBPF 驗(yàn)證器:在整個(gè) eBPF 的使用過程中,內(nèi)核會(huì)在加載 eBPF 程序時(shí)對(duì) eBPF 程序進(jìn)行分析驗(yàn)證,保證 eBPF 程序不會(huì)造成內(nèi)核崩潰等問題,當(dāng)然這不意味著 eBPF 程序在開發(fā)后不需要經(jīng)過測試驗(yàn)證,但是在一定程度上保障了 eBPF 的安全性。驗(yàn)證器首先會(huì)確保程序中沒有不可達(dá)的指令,并且沒有無界循環(huán),確保程序在一定數(shù)量的指令數(shù)量后安全地終止,其次通過模擬執(zhí)行,確保所有路徑都是可以運(yùn)行完成的,驗(yàn)證程序沒有越界訪問內(nèi)存。在驗(yàn)證通過后,eBPF 程序才能被解釋執(zhí)行。更具有優(yōu)勢的一點(diǎn)是,eBPF 程序是可以動(dòng)態(tài)地從內(nèi)核中加載或刪除,而不像 LSM 模塊需要重啟系統(tǒng)才能進(jìn)行模塊加載,完全可以做到不打斷任何已經(jīng)存在的進(jìn)程。
下表列舉了一些 LSM 模塊和 eBPF 的差異點(diǎn):(參考【19】)
2.5 eBPF 與容器安全
正如前面提到,作為一個(gè)功能豐富的新特性,eBPF 提供了一種便利的可基于系統(tǒng)或程序事件高效安全執(zhí)行特定代碼的通用能力,并且它可檢測的事件覆蓋了系統(tǒng)的各個(gè)方面(如下圖所示),提供了豐富的可觀察信息,甚至在 Linux 5.7 版本后 eBPF 程序可以插入 LSM hook 點(diǎn)。
對(duì)于容器環(huán)境來說,所有運(yùn)行在一臺(tái)機(jī)器上的容器都和主機(jī)共享內(nèi)核,內(nèi)核了解主機(jī)上運(yùn)行的所有應(yīng)用代碼。eBPF 的 Hook 點(diǎn)可以說是遍布內(nèi)核的各個(gè)角落,這對(duì)于容器安全的檢測和防護(hù)是很大的助力,方便了對(duì)容器中正在進(jìn)行的操作的分析和判斷,近些年來有許多利用這項(xiàng)新技術(shù)來解決一些容器安全問題的工具。當(dāng)前這類安全上的工具主要可以分為兩類:一類是確保網(wǎng)絡(luò)活動(dòng)的安全,eBPF 最初就是用于網(wǎng)絡(luò)數(shù)據(jù)包過濾的技術(shù),可以在網(wǎng)絡(luò)驅(qū)動(dòng)中盡可能早的位置提供最優(yōu)的數(shù)據(jù)包處理能力,過濾并丟棄惡意或非預(yù)期的流量以及防范 DDOS 攻擊等。而另一類則是檢測惡意行為,確保應(yīng)用程序在運(yùn)行時(shí)的行為安全。例如利用 eBPF 同樣可以在系統(tǒng)調(diào)用的入口處插入檢測過濾程序,但是相比于 Seccomp 更強(qiáng)大的地方在于,eBPF 程序可以對(duì)其中的指針參數(shù)進(jìn)行解引用,這也就方便了更進(jìn)一步的行為分析。
早期的 eBPF 程序并沒有直接的阻斷功能,而是作為觀測分析工具將收集到的的信息交給用戶空間程序,這樣用戶空間程序根據(jù)這些信息判斷目標(biāo)進(jìn)程操作的威脅性來殺死目標(biāo)進(jìn)程。目前大部分的成熟的基于 eBPF 開發(fā)的安全工具都將其作為系統(tǒng)觀察和信息收集的手段加以利用,例如 Aqua Security 云原生安全公司開發(fā)的 Tracee 和 Sysdig 開發(fā)的 Falco 都是基于 eBPF 系統(tǒng)觀測能力的異常行為檢測工具。之后在 Linux 5.3 版本中引入了 send_signal() Helper 函數(shù),BPF 程序本身具備了可以直接決斷是否終止目標(biāo)進(jìn)程的能力。
2022年5月,Cilium 的母公司 Isovalent 在歐洲舉行的 KubeCon 技術(shù)峰會(huì)期間發(fā)布了云原生運(yùn)行時(shí)防護(hù)系統(tǒng)——Tetragon,正是利用這一新特性來做到安全防護(hù)的能力。無論是通過用戶空間高權(quán)限進(jìn)程殺死惡意進(jìn)程,或者是 eBPF 程序直接通過 send_signal() 終止進(jìn)程,這兩種加固阻斷的方式或多或少都是存在 TOCTTOU 風(fēng)險(xiǎn)的。直到 Linux 5.7 版本,eBPF 程序可以直接插入 LSM hook 點(diǎn),并影響 LSM Hook 點(diǎn)的判定結(jié)果。需要區(qū)分的是,5.7 版本之前的 eBPF 程序雖然可以利用 kprobe 進(jìn)行動(dòng)態(tài)插入來觀測 LSM 相關(guān)方法的情況,但是只能用于數(shù)據(jù)采集,并不能影響 LSM 方法的返回值。正是這一新特性 Kernel Runtime Security Instrumentation(簡稱 KRSI)的出現(xiàn),使得基于 eBPF 開發(fā)的安全工具才具備真正意義上的加固阻斷能力,也為云原生安全加固相關(guān)的工作帶來了更多可能。
下表列舉了當(dāng)前比較有名的基于 eBPF 開發(fā)的安全工具(當(dāng)前基于KRSI的項(xiàng)目較少,筆者選取了github上比較有特點(diǎn)的一個(gè)開源項(xiàng)目作為對(duì)比):
03容器運(yùn)行時(shí)安全的未來
當(dāng)前云原生的技術(shù)大多數(shù)被服務(wù)于 Web 應(yīng)用的相關(guān)業(yè)務(wù),此類業(yè)務(wù)往往把性能要求放在較為靠前的位置,對(duì)于設(shè)備上選用的安全加固技術(shù)都會(huì)有性能方面的考量。而 eBPF 的出現(xiàn)為容器安全帶來了一種能夠動(dòng)態(tài)、輕量、無感知的提升防御能力的方式。其全面的觀測能力,可以輕松地監(jiān)控到容器安全可觀測性的四個(gè)黃金信號(hào)【18】:進(jìn)程執(zhí)行、網(wǎng)絡(luò)套接字、文件訪問和七層網(wǎng)絡(luò)身份,保證了安全檢測的全面性。同時(shí) KRSI 特性的出現(xiàn)使得 eBPF 程序還具備了等同于 LSM 模塊進(jìn)行訪問控制的決斷能力,而不再只是單純地作為觀測工具。因此在未來的發(fā)展過程中,eBPF 的相關(guān)應(yīng)用將是容器運(yùn)行時(shí)安全最重要的助力。同時(shí),不可忽視的是對(duì)低版本內(nèi)核系統(tǒng)上的安全防護(hù),目前并在未來很長的一段時(shí)間內(nèi),大多數(shù)的主機(jī)服務(wù)器上仍然將運(yùn)行著 Linux 3.* 以及 4.* 的系統(tǒng)。對(duì)于這些系統(tǒng)來說,Seccomp、LSM 模塊等內(nèi)核安全機(jī)制依舊是保障容器安全不可或缺的部分。
?// 文丨支葉盛:美團(tuán)安全研究員,主要從事 Linux 內(nèi)核安全及二進(jìn)制程序安全等方向的研究,當(dāng)前負(fù)責(zé)美團(tuán)內(nèi)部操作系統(tǒng)安全、云原生安全等方向的安全建設(shè)。
1.“Docker Overview”:https://docs.docker.com/get-started/overview/
2.“云原生之容器安全實(shí)踐”:https://tech.meituan.com/2020/03/12/cloud-native-security.html
3.“Exploring container security: An overview”:https://cloud.google.com/blog/products/gcp/exploring-container-security-an-overview
4.“MITRE ATT&CK? Containers Matrix”:https://attack.mitre.org/matrices/enterprise/containers/
5.“Sysdig 2022 Cloud?Native Security and Usage Report”:https://sysdig.com/wp-content/uploads/2022-cloud-native-security-and-usage-report.pdf
6.CIS Docker Benchmark:https://www.cisecurity.org/benchmark/docker
7.CIS Azure Kubernetes Service (AKS) Benchmark:https://www.cisecurity.org/benchmark/kubernetes
8.“New Container Kernel Features” - Christian Brauner, Canonical Ltd.*:https://static.sched.com/hosted_files/ossna19/22/OSS%20NA%202019_%20New%20Container%20Kernel%20Features.pdf
9.“capabilities(7) - Linux man page”:http://man7.org/linux/man-pages/man7/capabilities.7.html
10.“Seccomp BPF (SECure COMPuting with filters)“:https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html
11.“seccomp_unotify(2) — Linux manual page”:https://man7.org/linux/man-pages/man2/seccomp_unotify.2.html
12.“Inside the Linux Security Modules (LSM)” - Vandana Salve, Prasme Systems:https://static.sched.com/hosted_files/ossna2020/3a/ELC_Inside_LSM.pdf
13.“LSM Stacking - What You Can Do Now and What's Next” - Casey Schaufler, Intel:https://static.sched.com/hosted_files/lsseu2019/84/201910-LSS-EU-xxx-Stacking.pdf
14.《What Is eBPF? An Introduction to a New Generation of Networking, Security, and Observability Tools》—— Liz Rice
15.“eBPF Documentation”:https://ebpf.io/what-is-ebpf
16.“eBPF 技術(shù)簡介”:https://cloudnative.to/blog/bpf-intro/
17.《Linux Observability with BPF: Advanced Programming for Performance, Analysis and Networking》(譯名《Linux內(nèi)核觀測技術(shù)BPF》)—— David Calavera and Lorenzo Fontana
18.《Security Observability with eBPF: Measuring Cloud Native Security Through eBPF Observability》—— Jed Salazar and Natalia Reka Ivanko
19.“基于 eBPF 實(shí)現(xiàn)容器運(yùn)行時(shí)安全”:https://www.ebpf.top/post/ebpf_container_security/
20.“Tetragon進(jìn)程阻斷原理”:https://www.cnxct.com/how-tetragon-preventing-attacks/
21.“KRSI — the other BPF security module”:https://lwn.net/Articles/808048/