1 前言
隨著容器技術(shù)的發(fā)展,越來越多業(yè)務(wù)甚至核心業(yè)務(wù)開始采用這一輕量級虛擬化方案。作為一項依然處于發(fā)展階段的新技術(shù),容器的安全性在不斷提高,也在不斷地受到挑戰(zhàn)。天翼云云容器引擎于去年 11 月底上線,目前已經(jīng)在 22 個自研資源池部署上線。天翼云云容器引擎使用 ebpf 技術(shù)實現(xiàn)了細(xì)粒度容器安全,對主機和容器異常行為進行檢測,對有問題的節(jié)點和容器進行自動隔離,保證了多租戶容器平臺容器運行時安全。
BPF 是一項革命性的技術(shù),可在無需編譯內(nèi)核或加載內(nèi)核模塊的情況下,安全地高效地附加到內(nèi)核的各種事件上,對內(nèi)核事件進行監(jiān)控、跟蹤和可觀測性。BPF 可用于多種用途,如:開發(fā)性能分析工具、軟件定義網(wǎng)絡(luò)和安全等。我很榮幸獲得今年 openEuler Summit 大會的演講資格,做 BPF 技術(shù)知識和實踐經(jīng)驗的分享。本文將作為技術(shù)分享,從 BPF 技術(shù)由來、架構(gòu)演變、BPF 跟蹤、以及容器安全面對新挑戰(zhàn),如何基于 BPF 技術(shù)實現(xiàn)容器運行時安全等方面進行介紹。
2 初出茅廬:BPF 只是一種數(shù)據(jù)包過濾技術(shù)
BPF 全稱是「Berkeley Packet Filter」,中文翻譯為「伯克利包過濾器」。它源于 1992 年伯克利實驗室,Steven McCanne 和 Van Jacobson 寫得一篇名為《The BSD Packet Filter: A New Architecture for User-level Packet Capture》的論文。該論文描述是在 BSD 系統(tǒng)上設(shè)計了一種新的用戶級的數(shù)據(jù)包過濾架構(gòu)。在性能上,新的架構(gòu)比當(dāng)時基于棧過濾器的 CSPF 快 20 倍,比之前 Unix 的數(shù)據(jù)包過濾器,例如:SunOS 的 NIT(The Network Interface Tap )快 100 倍。
BPF 在數(shù)據(jù)包過濾上引入了兩大革新來提高性能:
BPF 是基于寄存器的過濾器,可以有效地工作在基于寄存器結(jié)構(gòu)的 CPU 之上。
BPF 使用簡單無共享的緩存模型。數(shù)據(jù)包會先經(jīng)過 BPF 過濾再拷貝到緩存,緩存不會拷貝所有數(shù)據(jù)包數(shù)據(jù),這樣可以最大程度地減少了處理的數(shù)據(jù)量從而提高性能。
3 Linux 超能力終于到來了:eBPF 架構(gòu)演變
3.1 eBPF 介紹
2013 年 BPF 技術(shù)沉默了 20 年之后,Alexei Starovoitov 提出了對 BPF 進行重大改寫。2013 年 9 月 Alexei 發(fā)布了補丁,名為「extended BPF」。eBPF 實現(xiàn)的最初目標(biāo)是針對現(xiàn)代硬件進行優(yōu)化。eBPF 增加了寄存器數(shù)量,將原有的 2 個 32 位寄存器增加到 10 個 64 位寄存器。由于寄存器數(shù)量和寬度的增加,函數(shù)參數(shù)可以交換更多的信息,編寫更復(fù)雜的程序。eBPF 生成的指令集比舊的 BPF 解釋器生成的機器碼執(zhí)行速度提高了 4 倍。
當(dāng)時 BPF 程序仍然限于內(nèi)核空間使用,只有少數(shù)用戶空間程序可以編寫內(nèi)核的 BPF 過濾器,例如:tcpdump 和 seccomp 。2014 年 3 月, 經(jīng)過 Alexei Starovoitov 和 Daniel Borkmann 的進一步開發(fā), Daniel 將 eBPF 提交到 Linux 內(nèi)核中。2014 年 6 月 BPF JIT 組件提交到 Linux 3.15 中。2014 年 12 月 系統(tǒng)調(diào)用 bpf 提交到 Linux 3.18 中。隨后,Linux 4.x 加入了 BPF 對 kprobes、uprobe、tracepoints 和 perf_evnets 支持。至此,eBPF 完成了架構(gòu)演變,eBPF 擴展到用戶空間成為了 BPF 技術(shù)的轉(zhuǎn)折點。正如 Alexei 在提交補丁的注釋中寫到:“這個補丁展示了 eBPF 的潛力”。當(dāng)前 eBPF 不再局限于網(wǎng)絡(luò)棧,成為內(nèi)核頂級的子系統(tǒng)。
后來,Alexei 將 eBPF 改為 BPF。原來的 BPF 就被稱為 cBPF「classic BPF」?,F(xiàn)在 cBPF 已經(jīng)基本廢棄,Linux 內(nèi)核只運行 eBPF,內(nèi)核會將加載的 cBPF 字節(jié)碼透明地轉(zhuǎn)換成 eBPF 再執(zhí)行。
下面是 cBPF 和 eBPF 的對比:
緯度 | cBPF | eBPF |
---|---|---|
內(nèi)核版本 | Linux 2.1.75(1997 年) | Linux 3.18(2014 年)[4.x for kprobe/uprobe/tracepoint/perf-event](注:雖然 eBPF 在 Linux 3.18 版本以后引入,并不代表只能在內(nèi)核 3.18+ 版本上運行,低版本的內(nèi)核升級到最新也可以使用 eBPF 能力,只是可能部分功能受限。) |
寄存器數(shù)目 | 2 個:A, X | 10 個:R0–R9, 另外 R10 是一個只讀的幀指針* R0 - eBPF 中內(nèi)核函數(shù)的返回值和退出值* R1 - R5 - eBF 程序在內(nèi)核中的參數(shù)值* R6 - R9 - 內(nèi)核函數(shù)將保存的被調(diào)用者 callee 保存的寄存器* R10 -一個只讀的堆棧幀指針 |
寄存器寬度 | 32 位 | 64 位 |
存儲 | 16 個內(nèi)存位: M[0–15] | 512 字節(jié)堆棧,無限制大小的 “map” 存儲 |
限制的內(nèi)核調(diào)用 | 非常有限,僅限于 JIT 特定 | 有限,通過 bpf_call 指令調(diào)用 |
目標(biāo)事件 | 數(shù)據(jù)包、 seccomp-BPF | 數(shù)據(jù)包、內(nèi)核函數(shù)、用戶函數(shù)、跟蹤點 PMCs 等 |
接下來,讓我們來看看演變后的 BPF 架構(gòu)。
3.2 eBPF 架構(gòu)演變
BPF 是一個通用執(zhí)行引擎,能夠高效地安全地執(zhí)行基于系統(tǒng)事件的特定代碼。BPF 內(nèi)部由字節(jié)碼指令,存儲對象和幫助函數(shù)組成。從某種意義上看,BPF 和 Java 虛擬機功能類似。對于 Java 開發(fā)人員而言,可以使用 javac 將高級編程語言編譯成機器代碼,Java 虛擬機是運行該機器代碼的專用程序。相應(yīng)地,BPF 開發(fā)人員可以使用編譯器 LLVM 將 C 代碼編譯成 BPF 字節(jié)碼,字節(jié)碼指令在內(nèi)核執(zhí)行前必須通過 BPF 驗證器進行驗證,同時使用內(nèi)核中的 BPF JIT 模塊,將字節(jié)碼指令直接轉(zhuǎn)成內(nèi)核可執(zhí)行的本地指令。編譯后的程序附加到內(nèi)核的各種事件上,以便在 Linux 內(nèi)核中運行該 BPF 程序。下圖是 BPF 架構(gòu)圖:
BPF 使內(nèi)核具有可編程性。BPF 程序是運行在各種內(nèi)核事件上的小型程序。這與 JavaScript 程序有一些相似之處:JavaScript 是允許在瀏覽器事件,例如:鼠標(biāo)單擊上運行的微型 Web 程序。BPF 是允許內(nèi)核在系統(tǒng)和應(yīng)用程序事件,例如:磁盤 I/O 上運行的微型程序。內(nèi)核運行 BPF 程序之前,需要知道程序附加的執(zhí)行點。程序執(zhí)行點是由 BPF 程序類型確定。通過查看/kernel-src/sample/bpf/bpf_load.c 可以查看 BPF 程序類型。下面是定義在 bpf 頭文件中的 bpf 程序類型:
BPF 映射提供了內(nèi)核和用戶空間雙向數(shù)據(jù)共享,允許用戶從內(nèi)核和用戶空間讀取和寫入數(shù)據(jù)。BPF 映射的數(shù)據(jù)結(jié)構(gòu)類型可以從簡單數(shù)組、哈希映射到自定義類型映射。下面是定義在 bpf 頭文件中的 bpf 映射類型:
3.3.BPF 與傳統(tǒng) Linux 內(nèi)核模塊的對比
BPF 看上去更像內(nèi)核模塊,所以總是會拿來與 Linux 內(nèi)核模塊方式進行對比,但 BPF 與內(nèi)核模塊不同。BPF 在安全性、入門門檻上及高性能上比內(nèi)核模塊都有優(yōu)勢。
傳統(tǒng) Linux 內(nèi)核模塊開發(fā),內(nèi)核開發(fā)工程師通過直接修改內(nèi)核代碼,每次功能的更新都需要重新編譯打包內(nèi)核代碼。內(nèi)核工程師可以開發(fā)即時加載的內(nèi)核模塊,在運行時加載到 Linux 內(nèi)核中,從而實現(xiàn)擴展內(nèi)核功能的目的。然而每次內(nèi)核版本的官方更新,可能會引起內(nèi)核 API 的變化,因此你編寫的內(nèi)核模塊可能會隨著每一個內(nèi)核版本的發(fā)布而不可用,這樣就必須得為每次的內(nèi)核版本更新調(diào)整你的模塊代碼,并且,錯誤的代碼會造成內(nèi)核直接崩潰。
BPF 具有強安全性。BPF 程序不需要重新編譯內(nèi)核,并且 BPF 驗證器會保證每個程序能夠安全運行,確保內(nèi)核本身不會崩潰。BPF 虛擬機會使用 BPF JIT 編譯器將 BPF 字節(jié)碼生成本地機器字節(jié)碼,從而能獲得本地編譯后的程序運行速度。
下面是 BPF 與 Linux 內(nèi)核模塊的對比:
維度 | Linux 內(nèi)核模塊 | BPF |
---|---|---|
kprobes、tracepoints | 支持 | 支持 |
安全性 | 可能引入安全漏洞或?qū)е聝?nèi)核 Panic | 通過驗證器進行檢查,可以保障內(nèi)核安全 |
內(nèi)核函數(shù) | 可以調(diào)用內(nèi)核函數(shù) | 只能通過 BPF Helper 函數(shù)調(diào)用 |
編譯性 | 需要編譯內(nèi)核 | 不需要編譯內(nèi)核,引入頭文件即可 |
運行 | 基于相同內(nèi)核運行 | 基于穩(wěn)定 ABI 的 BPF 程序可以編譯一次,各處運行 |
與應(yīng)用程序交互 | 打印日志或文件 | 通過 perf_event 或 map 結(jié)構(gòu) |
數(shù)據(jù)結(jié)構(gòu)豐富性 | 一般 | 豐富 |
入門門檻 | 高 | 低 |
升級 | 需要卸載和加載,可能導(dǎo)致處理流程中斷 | 原子替換升級,不會造成處理流程中斷 |
內(nèi)核內(nèi)置 | 視情況而定 | 內(nèi)核內(nèi)置支持 |
4 BPF 實踐中的第一公民:BPF 跟蹤
BPF 跟蹤是 Linux 可觀測性的新方法。在 BPF 技術(shù)的眾多應(yīng)用場景中,BPF 跟蹤是應(yīng)用最廣泛的。2013 年 12 月 Alexei 已將 eBPF 用于跟蹤。BPF 跟蹤支持的各種內(nèi)核事件包括:kprobes、uprobes、tracepoint 、USDT 和 perf_events:
kprobes:實現(xiàn)內(nèi)核動態(tài)跟蹤。kprobes 可以跟蹤到 Linux 內(nèi)核中的函數(shù)入口或返回點,但是不是穩(wěn)定 ABI 接口,可能會因為內(nèi)核版本變化導(dǎo)致,導(dǎo)致跟蹤失效。
uprobes:用戶級別的動態(tài)跟蹤。與 kprobes 類似,只是跟蹤的函數(shù)為用戶程序中的函數(shù)。
tracepoints:內(nèi)核靜態(tài)跟蹤。tracepoints 是內(nèi)核開發(fā)人員維護的跟蹤點,能夠提供穩(wěn)定的 ABI 接口,但是由于是研發(fā)人員維護,數(shù)量和場景可能受限。
USDT:為用戶空間的應(yīng)用程序提供了靜態(tài)跟蹤點。
perf_events:定時采樣和 PMC。
5 容器安全
5.1 容器生態(tài)鏈帶來新挑戰(zhàn)
虛擬機(VM)是一個物理硬件層抽象,用于將一臺服務(wù)器變成多臺服務(wù)器。管理程序允許多個 VM 在一臺機器上運行。每個 VM 都包含一整套操作系統(tǒng)、一個或多個應(yīng)用、必要的二進制文件和庫資源,因此占用大量空間。VM 啟動也較慢。
容器是一種應(yīng)用層抽象,用于將代碼和依賴資源打包在一起。多個容器可以在同一臺機器上運行,共享操作系統(tǒng)內(nèi)核,但各自作為獨立的進程在用戶空間中運行。與虛擬機相比,容器占用的空間比較少(容器鏡像大小通常只有幾十兆),瞬間就能完成啟動。
容器技術(shù)面臨的新挑戰(zhàn):
容器共享宿主機內(nèi)核,隔離性相對較弱!
有 root 權(quán)限的用戶可以訪問所有容器資源!某容器提權(quán)后可能影響全局!
容器在主機網(wǎng)絡(luò)之上構(gòu)建了一層 Overlay 網(wǎng)絡(luò),使容器間的互訪避開了傳統(tǒng)網(wǎng)絡(luò)安全的防護!
容器的彈性伸縮性,使有些容器只是短暫運行,短暫運行的容器行為異常不容易被發(fā)現(xiàn)!
容器和容器編排給系統(tǒng)增加了新的元素,帶來新的風(fēng)險!
5.2 容器安全事故:容器逃逸
在容器安全問題中,容器逃逸是最為嚴(yán)重,它直接影響到了承載容器的底層基礎(chǔ)設(shè)施的保密性、完整性和可用性。下面的情況會導(dǎo)致容器逃逸:
? 危險配置導(dǎo)致容器逃逸。在這些年的迭代中,容器社區(qū)一直在努力將「縱深防御」、「最小權(quán)限」等理念和原則落地。例如,Docker 已經(jīng)將容器運行時的 Capabilities 黑名單機制改為如今的默認(rèn)禁止所有 Capabilities,再以白名單方式賦予容器運行所需的最小權(quán)限。如果容器啟動,配置危險能力,或特權(quán)模式容器,或容器以 root 用戶權(quán)限運行都會導(dǎo)致容器逃逸。下面是容器運行時默認(rèn)的最小權(quán)限。
? 危險掛載導(dǎo)致容器逃逸。Docker Socket 是 Docker 守護進程監(jiān)聽的 Unix 域套接字,用來與守護進程通信——查詢信息或下發(fā)命令。如果在攻擊者可控的容器內(nèi)掛載了該套接字文件(/var/run/docker.sock),容器逃逸就相當(dāng)容易了,除非有進一步的權(quán)限限制。
下面通過一個小實驗來展示這種逃逸可能性:
1.準(zhǔn)備 dockertest 鏡像,該鏡像是基于 ubuntu 鏡像安裝 docker,通過 docker commit 生成
2.創(chuàng)建一個容器并掛載/var/run/docker.sock
[root@bpftest~]#dockerrun-itd--namewith_docker_sock-v/var/run/docker.sock:/var/run/docker.sockdockertest
3.接著使用該客戶端通過 Docker Socket 與 Docker 守護進程通信,發(fā)送命令創(chuàng)建并運行一個新的容器,將宿主機的根目錄掛載到新創(chuàng)建的容器內(nèi)部;
[root@bpftest~]#dockerexec-it/bin/bash [root@bpftest~]#dockerps [root@bpftest~]#dockerrun-it-v/:/hostdockertest/bin/bash
? 相關(guān)程序漏洞導(dǎo)致容器逃逸,例如:runc 漏洞 CVE-2019-5736 導(dǎo)致容器逃逸。
? 內(nèi)核漏洞導(dǎo)致容器逃逸,例如:Copy_on_Write 臟牛漏洞,向 vDSO 內(nèi)寫入 shellcode 并劫持正常函數(shù)的調(diào)用過程,導(dǎo)致容器逃逸。
下面是 2019 年排名最高的容器安全事故列表:
6 容器安全主控引擎
6.1 主機和容器異?;顒拥臋z測
確保容器運行時安全的關(guān)鍵點:
? 降低容器的攻擊面,每個容器以最小權(quán)限運行,包括容器掛載的文件系統(tǒng)、網(wǎng)絡(luò)控制、運行命令等。
? 確保每個用戶對不同的容器擁有合適的權(quán)限。
? 使用安全容器控制容器之間的訪問。當(dāng)前,Linux 的 Docker 容器技術(shù)隔離技術(shù)采用 Namespace 和 Cgroups 無法阻止提權(quán)攻擊或打破沙箱的攻擊。
? 使用 ebpf 跟蹤技術(shù)自動生成容器訪問控制權(quán)限。包括:容器對文件的可疑訪問,容器對系統(tǒng)的可疑調(diào)用,容器之間的可疑互訪,檢測容器的異常進程,對可疑行為進行取證。例如:
? 檢測容器運行時是否創(chuàng)建其他進程。
? 檢測容器運行時是否存在文件系統(tǒng)讀取和寫入的異常行為,例如在運行的容器中安裝了新軟件包或者更新配置。
? 檢測容器運行時是否打開了新的監(jiān)聽端口或者建立意外連接的異常網(wǎng)絡(luò)活動。
? 檢測容器中用戶操作及可疑的 shell 腳本的執(zhí)行。
6.2 隔離有問題的容器和節(jié)點
如果檢測到有問題的容器或節(jié)點,可以將節(jié)點設(shè)置為維護狀態(tài),或使用網(wǎng)絡(luò)策略隔離有問題的容器,或?qū)?deployment 的副本數(shù)設(shè)置為 0,刪除有問題的容器。同時,使用 sidecar WAF,進行虛擬補丁等進行容器應(yīng)用安全防范。
6.3 大型公有云容器平臺安全主控引擎
下面是天翼云云容器引擎產(chǎn)品為了保證容器運行時安全實現(xiàn)的安全主控引擎:
? Pod 通過 sidecar 注入 WAF 組件對容器進行深度攻擊防御。
? 容器安全代理 Sage 組件以 Daemonset 形式部署在各個節(jié)點上,用來收集容器和主機異常行為,并通過自己的 sidecar 推送到消息隊列中。
? 安全主控引擎組件 jasmine 從消息隊列中拉取事件,對數(shù)據(jù)進行分析,對有故障的容器和主機進行隔離。并將事件推送給 SIEM 安全信息事件管理平臺進行管理。
-
編譯
+關(guān)注
關(guān)注
0文章
646瀏覽量
32664 -
BPF
+關(guān)注
關(guān)注
0文章
24瀏覽量
3926 -
容器技術(shù)
+關(guān)注
關(guān)注
1文章
21瀏覽量
5571
原文標(biāo)題:基于 eBPF 實現(xiàn)容器運行時安全
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論