Upgrade to Pro — share decks privately, control downloads, hide ads and more …

eBPFによるProcess Lifecycle Monitoring -Tetragonの実...

eBPFによるProcess Lifecycle Monitoring -Tetragonの実装紹介-

eBPFによるProcess Lifecycle Monitoring -Tetragonの実装紹介-

Yuki Nakamura

March 15, 2025
Tweet

More Decks by Yuki Nakamura

Other Decks in Technology

Transcript

  1. eBPFによる Process Lifecycle Monitoring - Tetragonの実装紹介 - Yuki Nakamura March

    15, 2025 @Cloud Native Community Japan - eBPF Japan Meetup #3
  2. 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を学習
  3. Agenda 1. Tetragonの概要とユースケース Runtime Enforcement Security Observability 収集したProcess Lifecycleの分析 2.

    Process Lifecycle Monitoringの仕組み Linuxの前提知識 Tetragonのコード解説
  4. 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
  5. 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
  6. 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
  7. Agenda 1. Tetragonの概要とユースケース Runtime Enforcement Security Observability 収集したProcess Lifecycleの分析 2.

    Process Lifecycle Monitoringの仕組み Linuxの前提知識 プロセスのデータ構造 TGIDとPID Process Management Syscall Tetragonのコード解説
  8. 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 内で定義された関数。
  9. 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 を取得
  10. Linux: Process Management Syscall プロセスは以下の手順で、作成・実行・終了される。 1. 親プロセスが fork() やclone() や類似のSyscallなどを呼び出して、子プロセスを作成する。

    2. 子プロセスは execve() や類似のSyscallを呼び出して、プログラムを実行する。 3. 子プロセスは実行が終了すると、 exit() や類似のSyscallを呼び出して、プロセスを終了する。 Parent Child fork() execve() exit() wait()
  11. 具体例: 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 +++
  12. Agenda 1. Tetragonの概要とユースケース Runtime Enforcement Security Observability 収集したProcess Lifecycleの分析 2.

    Process Lifecycle Monitoringの仕組み Linuxの前提知識 プロセスのデータ構造 TGIDとPID Process Management Syscall Tetragonの実装紹介 Fork Execve Exit
  13. 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
  14. 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)
  15. 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); ...
  16. 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
  17. 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
  18. 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)
  19. 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
  20. 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);
  21. 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]
  22. 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");
  23. 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
  24. 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)
  25. 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();
  26. 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
  27. 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