Share
Embed
eBPFによるProcess Lifecycle Monitoring -Tetragonの実装紹介-
eBPFによるProcess Lifecycle Monitoring -Tetragonの実装紹介-
Yuki Nakamura
March 15, 2025
Transcript
34 slides
-
eBPFによる Process Lifecycle Monitoring - Tetragonの実装紹介 - Yuki Nakamura March
15, 2025 @Cloud Native Community Japan - eBPF Japan Meetup #3 -
Whoami: Yuki Nakamura 👨💻 Platform Engineer ex-IBM Group, Mapbox Tech
Blog Container・Kubernetes関連のツール(ArgoCD, Buildkit, etc.) eBPF(Tetragon, Aya) 🐝 eBPFとの関わり Documentary: Unlocking the Kernelを見て、eBPFを活用したツール開発を志す eBPF関連のコードがLinux Kernelのコードベースにマージされていく経緯 eBPFが人気を集めていく経緯 名言: "This is like putting Javascript into the kernel." - Brendan Gregg Tetragon Tetragon ProjectにContribution Tetragon-mini: RustでTetragonをRewriteしながらeBPFを学習 -
Agenda 1. Tetragonの概要とユースケース Runtime Enforcement Security Observability 収集したProcess Lifecycleの分析 2.
Process Lifecycle Monitoringの仕組み Linuxの前提知識 Tetragonのコード解説 -
Tetragon:概要 CNCFプロジェクト, Ciliumのサブプロジェクト Ciliumと同様にC(eBPF)とGo(UserSpace)で書かれている 2023年11月にv1.0がリリース 2023-11-01: v1.0 2024-04-29: v1.1 2024-09-05:
v1.2 2024-12-13: v1.3 (本日紹介するコードはv1.3を参照) Tetragonを一言で言うと… eBPFベースのSecurity Observability & Runtime Enforcement Tool -
Tetragon:Runtime Enforcement(実装紹介対象外) あるルールに合致するSyscallが発生した際に、それをカーネル空間内で即座に制御する仕組み Tracing Policy(ルール): Traceするカーネル内のイベントや条件に一致した場合のアクションを定義 例1: /etc/passwdへの書き込みを試みる、PIDが1または0でないすべてのsys_writeをkillする 例2: 特定のbinaryファイルの実行を禁止する
eBPFを活用することでユーザースペースにイベントを伝達することなく処理を完了するのが特徴。 このアプローチにより、低レイテンシかつ確実なセキュリティポリシーの適用が可能。 Kernel Event eBPF Map Syscall Event eBPF Program eBPF Program eBPF Program Kill / Override eBPF Program Set up eBPF Programs/Maps Tetragon Agent Tetra CLI Tracing Policy Process eBPF Map eBPF Map -
Tetragon:Security Observability セキュリティ関連のKernel内のEventをリアルタイムに観測・分析できるようにすること Eventの例: File Access, TCP Connection Event, ProcessのLifeCycle(実行終了)
etc. eBPF ProgramでEventを検知し、eBPF Mapを介してユーザースペースのTetragon Agentに伝達する。任意 のCollector, Storage/Analytics Toolを活用し、蓄積・分析が可能になる。 Storage/AnalyticsTool Kernel Event eBPF Map Syscall Event eBPF Program eBPF Program eBPF Program eBPF Program Set up eBPF Programs/Maps Tetragon Agent Tetra CLI Tracing Policy Process eBPF Map eBPF Map Grafana loki S3 Collector fluentd optl Athena tetragon.log -
Agenda 1. Tetragonの概要とユースケース Runtime Enforcement Security Observability 収集したProcess Lifecycleの分析 2.
Process Lifecycle Monitoringの仕組み Linuxの前提知識 プロセスのデータ構造 TGIDとPID Process Management Syscall Tetragonのコード解説 -
Linux基礎: task_struct task_struct とは、Linuxカーネルにおいて各プロセス(またはスレッド)を管理するデータ構造 Linux: include/linux/sched.h Tetragonはこのtask_structからプロセスの情報を収集している eBPF helper関数 bpf_get_current_task()
: 現在のプロセス(スレッド)に対応する task_struct のポ インタを取得 struct task_struct { pid_t pid; pid_t tgid; char comm[TASK_COMM_LEN]; // プロセスのコマンド名 struct nsproxy *nsproxy; // Namespace struct mm_struct *mm; // プロセスが使用するユーザ空間のメモリ管理情報へのポインタ ... struct task_struct *task = bpf_get_current_task(); get_namespaces(&event->ns, task); // task_struct からnamespace の情報を取得。get_namespace はTetragon 内で定義された関数。 -
Linux: TGIDとPID TGIDはプロセスの識別子。PIDはスレッドの識別子。 Multi Thread task_struct tgid 200 pid 200
comm binary_2 task_struct tgid 200 pid 201 comm binary_2 task_struct tgid 200 pid 202 comm binary_2 Single Thread task_struct tgid 100 pid 100 comm binary_1 ⚠️PIDはプロセスの識別子ではない⚠️ Tetragonはプロセス単位でイベントを監視。プロセス内のThread(Multithreading)の作成・削除は対象外。 eBPF helper関数 bpf_get_current_pid_tgid() : pidとtgidを取得 u64 pid_tgid = bpf_get_current_pid_tgid(); u32 tgid = pid_tgid >> 32; // 上位32 ビットからTGID を取得 u32 pid = pid_tgid & 0xFFFFFFFF; // 下位32 ビットからPID を取得 -
Linux: Process Management Syscall プロセスは以下の手順で、作成・実行・終了される。 1. 親プロセスが fork() やclone() や類似のSyscallなどを呼び出して、子プロセスを作成する。
2. 子プロセスは execve() や類似のSyscallを呼び出して、プログラムを実行する。 3. 子プロセスは実行が終了すると、 exit() や類似のSyscallを呼び出して、プロセスを終了する。 Parent Child fork() execve() exit() wait() -
具体例: lsコマンド実行時のSyscall bashがlsコマンドを実行するときのSyscallをTraceした結果は以下の通りである。 Terminal1 (bash, PID=23167) Terminal2 以下のSyscallが呼ばれていた。 1. 作成:
clone() 2. 実行: execve() 3. 終了: exit_group() ls -la strace -fp 23167 2>&1 | grep -e clone -e execve -e exit clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLDstrace: Process 23895 attached [pid 23895] execve("/usr/bin/ls", ["ls", "--color=auto", "-la"], 0xbb5be6b20cc0 * 24 vars /) = 0 [pid 23895] exit_group(0) = ? [pid 23895] +++ exited with 0 +++ -
Agenda 1. Tetragonの概要とユースケース Runtime Enforcement Security Observability 収集したProcess Lifecycleの分析 2.
Process Lifecycle Monitoringの仕組み Linuxの前提知識 プロセスのデータ構造 TGIDとPID Process Management Syscall Tetragonの実装紹介 Fork Execve Exit -
Tetragon: Process Lifecycle Monitoring - Overview 各Process Management SyscallのHookにProcess Lifecycle
Eventを作成するeBPF Programをアタッチする。 eBPF Programが作成したEventをeBPF Mapを介してユーザースペースに伝達する。 User Space Kernel Space Exit-related Syscall eBPF Map Fork-related Syscall eBPF Program for creating Clone Event Execve-related Syscall eBPF Program for creating Exit Event eBPF Program for creating Execve Event Tetragon Agent -
Fork: eBPF ProgramとHook Point section名: kprobe/wake_up_new_task のeBPF Programを kprobe の
wake_up_new_task にアタッチ Tetragon UserSpace: base.go User Space Kernel Space Tetragon Agent fork-related syscalls event_wake_up_new_task kprobe wake_up_new_task perf_event_array tcpmon_map 47 Fork = program.Builder( 48 "bpf_fork.o", // the name of the BPF object file 49 "wake_up_new_task", // the hook point 50 "kprobe/wake_up_new_task", // the program section name 51 "kprobe_pid_clear", // the name of pin 52 "kprobe", // the type of BPF program 53 ).SetPolicy(basePolicy) -
Fork: Hook Point (wake_up_new_task) wake_up_new_task はforkのmain routineである kernel_clone() の中で呼ばれる関数 Linux:
kernel/fork.c -> kernel_clone() kernel_clone()はmainのfork-routine。 pid_t kernel_clone(struct kernel_clone_args *args) { struct task_struct *p; wake_up_new_task(p); ... -
Fork: eBPF Program 主な処理: Clone Eventを組み立て、eBPF Map: tcpmon_mapに書き込む Tetragon eBPF:
bpf_fork.c プロセス内でのThreadの作成を無視する仕組み: wake_up_new_taskはThread作成時にも呼ばれるため、同じTGIDでCloneEventがすでに作成されてい るかを確認し、作成されていない場合のみ新たに作成する。 curr = execve_map_get(tgid); if (curr->key.ktime != 0) // Check whether the event for the tgid has already been created. return 0; ``` --> 23 __attribute__((section("kprobe/wake_up_new_task"), used)) int 24 BPF_KPROBE(event_wake_up_new_task, struct task_struct *task) 25 { 26 struct msg_clone_event msg; 27 ... 28 perf_event_output_metric(ctx, MSG_OP_CLONE, &tcpmon_map, 29 BPF_F_CURRENT_CPU, &msg, msg_size); // Write msg_clone_event to tcpmon_map -
Execve User Space Kernel Space Exit-related Syscall eBPF Map Fork-related
Syscall eBPF Program for creating Clone Event Execve-related Syscall eBPF Program for creating Exit Event eBPF Program for creating Execve Event Tetragon Agent -
Execve: eBPF ProgramとHook Point section名: tracepoint/sys_execve のeBPF Programを tracepoint の
sched/sched_process_exec にアタ ッチ Tetragon UserSpace: base.go Kernel Space Tail Call event_execve execve_send Tail Call execve_rate execve-related syscalls trecepoint sched_process_exec User Space Tetragon Agent perf_event_array tcpmon_map 23 Exit = program.Builder( 24 config.ExecObj(), // the name of the BPF object file 25 "sched/sched_process_exec", // the hook point 26 "tracepoint/sys_execve", // the program section name 27 "event_execve", // the name of pin 28 "execve", // the type of BPF program 29 ).SetPolicy(basePolicy) -
Execve: Hook Point (sched/sched_process_exec) tracepoint: sched/sched_process_exec は新しいプロセスが実行される際にTriggerされる プロセス内でのThreadの作成を無視する仕組み: プロセス内でのThread作成時には、 sched/sched_process_exec
はトリガーされない。 <参考>TracepointのeBPF Programを書く際は、そのTracepointで利用可能なデータのフォーマットを確認 することが大切。以下のコマンドで確認可能。 cat /sys/kernel/debug/tracing/events/sched/sched_process_exec/format name: sched_process_exec ID: 267 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1; field:__data_loc char[] filename; offset:8; size:4; signed:0; field:pid_t pid; offset:12; size:4; signed:1; field:pid_t old_pid; offset:16; size:4; signed:1; print fmt: "filename=%s pid=%d old_pid=%d", __get_str(filename), REC->pid, REC->old_pid -
Execve: eBPF Program 主な処理: Execve Event (msg_exit)を組み立て、eBPF Map: tcpmon_mapに書き込む Tetragon
eBPF: bpf_execve_event.c event_execve execve_send __attribute__((section("tracepoint/sys_execve"), used)) int event_execve(struct trace_event_raw_sched_process_exec *ctx) { struct task_struct *task = (struct task_struct *)get_current_task(); char *filename = (char *)ctx + (_(ctx->__data_loc_filename) & 0xFFFF); // Use __data_loc_filename in ctx struct msg_execve_event *event; __attribute__((section("tracepoint"), used)) int execve_send(void *ctx __arg_ctx) { // Write msg_execve_event to tcpmon_map perf_event_output_metric(ctx, MSG_OP_EXECVE, &tcpmon_map, BPF_F_CURRENT_CPU, event, size); -
Execve: Tail Call Execve Eventの処理は3つのeBPF Programに分かれており、Tail Callによって順に実行される 1. event_execve: Execve
Eventの組み立て 2. execve_rate: cgroup単位で大量のEventが発生した際の監視を抑制(Event throttling) 3. execve_send: Execve EventをeBPF Mapへの書き込み Kernel Space Tail Call event_execve execve_send Tail Call execve_rate execve-related syscalls trecepoint sched_process_exec User Space Tetragon Agent perf_event_array tcpmon_map Tail Call導入のメリット: ロジックの分離 eBPF Verifierのプログラムサイズ制限到達の回避 スタック使用量の削減(最大512バイト) 1. v5.2までは、命令数の上限が4k、複雑さの上限が128k。その後、これらの上限は1Mに引き上げられた。↩︎ [1] -
Tips: Tail Call間でのデータ共有 Tail Callの呼び出し時にデータを渡すことはできない。 その解決策として、eBPF Mapを利用して、eBPF Program間でEventデータを共有している。 Tetragon eBPF:
process.h Kernel Space Tail Call read/write event_execve read/write execve_send Tail Call read/write execve_rate execve-related syscalls trecepoint sched_process_exec User Space Tetragon Agent perf_event_array tcpmon_map Storage for sharing states PerCpuArray CPU:1 CPU:n PerCpuArray ... 360 struct { 361 __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 362 __uint(max_entries, 1); 363 __type(key, __u32); 364 __type(value, struct msg_execve_event); 365 } execve_msg_heap_map SEC(".maps"); -
Exit User Space Kernel Space Exit-related Syscall eBPF Map Fork-related
Syscall eBPF Program for creating Clone Event Execve-related Syscall eBPF Program for creating Exit Event eBPF Program for creating Execve Event Tetragon Agent -
Exit: eBPF ProgramとHook Point section名: kprobe/acct_process のeBPF Programを kprobe の
acct_process にアタッチ Tetragon UserSpace: base.go User Space Kernel Space Tetragon Agent exit-related syscalls event_exit_acct_process kprobe acct_process perf_event_array tcpmon_map 39 Exit = program.Builder( 40 "bpf_exit.o", // the name of the BPF object file 41 "acct_process", // the hook point 42 "kprobe/acct_process", // the program section name 43 "event_exit", // the name of pin 44 "kprobe", // the type of BPF program 45 ).SetPolicy(basePolicy) -
Exit: Hook Point (acct_process) acct_process はdo_exit()の中でThread Groupがなくなるときに呼ばれる関数 Linux: kernel/exit.c ->
do_exit() プロセス内でのThreadの削除を無視する仕組み: acct_processはThread Groupがなくなるときに呼ばれるため、プロセス終了時に1回のみ呼ばれる。 なお、acct_processがないKernelの場合は、 disassociate_ctty が利用される。 <参考>以前はtracepointの sched/sched_process_exit やkprobeの kprobe/__put_task_struct を利用 していたが、Thread Groupの終了を簡単に検知できるacct_processに変更された。 tetragon: Switch exit tracepoint to __put_task_struct kprobe #558 tetragon: Hook exit sensor on acct_process #1509 void __noreturn do_exit(long code) { if (group_dead) acct_process(); -
Exit: eBPF Program 主な処理: Exit Event (msg_exit)を組み立て、eBPF Map: tcpmon_mapに書き込む Tetragon
eBPF: bpf_exit.cの kprobe/acct_process section Tetragon eBPF: bpf_exit.h 47 __attribute__((section("kprobe/acct_process"), used)) int 48 event_exit_acct_process(struct pt_regs *ctx) 49 { 50 __u64 pid_tgid = get_current_pid_tgid(); 51 52 event_exit_send(ctx, pid_tgid >> 32); 53 return 0; 54 } FUNC_INLINE void event_exit_send(void *ctx, __u32 tgid) { struct msg_exit *exit; exit->info.tid = tgid; ... perf_event_output_metric(ctx, MSG_OP_EXIT, &tcpmon_map, BPF_F_CURRENT_CPU, exit, size); // Write msg_exit to tcpmon_map -
Process Lifecycle Monitoring - 詳細 3つのHook Point、5つのeBPF Program、複数のeBPF Mapを利用して、Process Lifecycle
Monitoringを実現 User Space Kernel Space exit-related syscalls Tail Call event_execve perf_event_array tcpmon_map Tetragon Agent Tetra CLI fork-related syscalls event_exit_acct_process execve_send Tail Call execve_rate event_wake_up_new_task execve-related syscalls kprobe wake_up_new_task trecepoint sched_process_exec kprobe acct_process -
まとめ 1. TetragonのRuntime Enforcement、Security Observabilityについて説明した 2. Linuxの基礎知識(task_struct、TGIDとPID、Process関連のSyscall)について説明した 3. Tetragon/Kernelのコードを一部紹介した(Fork/Execve/ExitのHook PointとeBPF
Program) 4. eBPFのTips(TracepointのData Format、Tail Call、Per-CPU Mapを利用したデータ共有)を紹介した