#seccon ワークショップ@福岡でeBPF/XDPベースのファイアウォールとロードバランサーに入門してきた
クラウドネイティブ界隈でよく耳にするCNI(Container Network Interface)・L4ロードバランサーのCilium、そしてランタイムセキュリティツールのFalcoでは、eBPF(Extended Berkeley Packet Filter)およびeBPFを活用したXDP(eXpress Data Path)の技術が非常に重要な役割を果たしています。
みんな大好き、『詳解 システム・パフォーマンス』や "BPF Performance Tools" の著者である現IntelのBrendan Gregg ニキは、eBPFとLinuxカーネルの関係はJavaScriptとウェブサイトの関係と同じだと発言しています。
近年、重要度が高まっているeBPF/XDPをワークショップ形式で学べるSECCONのイベントが地元福岡の九州大学で開催されましたので、レポートします。
ワークショップで利用したスライド、及び、サンプルコードは公開されているため、ワークショップに参加できなかった方も自分のペースで進めることが可能です。
#seccon ワークショップご参加いただきありがとうございました.
本日の資料です.https://t.co/Uum3Ancghf
ロードバランサーの実装にぜひチャレンジしてみてください!
— terassyi (@terassyi_) October 29, 2023
ワークショップ概要
ワークショップ案内
「XDP で作って学ぶファイアウォールとロードバランサー」ワークショップ@福岡
概要
現在、ロードバランサーやファイアウォールはサービスを提供する上で欠かせないネットワークコンポーネントとなっており、ファイアウォールは機密性や堅牢性、ロードバランサーは可用性に非常に重要な役割を果たしています。ファイアウォールやロードバランサーは使ったことのある方は多いかもしれませんが、それらが実際にどのようにパケットを処理しているのかを知っている方はあまり多くないのではないでしょうか。普段なにげなく利用しているソフトウェアの仕組みを知ることは利用する上でもかなり役に立ちます。
また、XDP とは、近年流行している eBPF の一種で、高速なパケット処理に特化した機能を提供します。eBPF とは Linux カーネルの機能のひとつで、Linux カーネルの挙動を安全かつ動的に変更することのできる機能です。XDPはすでに様々なプロダクションで活用されていて非常にホットな技術です。本ワークショップでは XDP を利用して実際に簡単 なファイアウォールやロードバランサーを実装して動作させることで、それらの仕組みや、XDP によるパケット処理プログラムの書き方を学びます。本ワークショップを通して、パケット処理の面白さや普段利用しているネットワークコンポーネントの仕組みに興味を持って貰えれば幸いです。
講師
寺嶋友哉 (サイボウズ株式会社)
日時
2023年10月29日(日) 13:00 ~ 17:20(途中休憩あり)
会場
〒819-0395 福岡県福岡市西区元岡744 九州大学 伊都キャンパス 情報基盤研究開発センター 2階
ワークショップ検証環境
ワークショップでは、参加者ごとにUbuntuのAmazon EC2 t2.microインスタンスが割り当てられました。
ワークショップ後、個人用AWSアカウントのUbuntu 22.04/t2.microでも動作することを確認しています。
XDP で作って学ぶファイアウォールとロードバランサー
それでは、当日のワークショップについて簡単にレポートします。
eBPF/XDP の概要
BPFはもともとBSD系OS向けのパケットフィルターとして開発され、1993年のUSENIXでも発表されているほどの歴史があります。
その後、Linuxに移植され、拡張されてより汎用的になったのが、eBPF(Extended Berkeley Packet Filter)です。eBPFは2014年リリースのカーネル4.4から導入されています。 BPF技術を利用すると、Linuxカーネルを変更したりカーネルモジュールをロードすることなく、安全かつ効率的にカーネルの機能を拡張できます。
eBPF以前の旧BPFはclassic BPF(cBPF)と呼ばれており、tcpdumpのフィルタールールなどでも利用されています。
※ 引用元 https://ebpf.io/what-is-ebpf/
XDP(eXpress Data Path)はeBPFプログラムをネットワークドライバ(NIC)などにアタッチして動作し、高速なパケット処理を実現します。
eBPF/XDPは以下のプロダクトなどで使われています。
- Meta社のKatranやCloudflare社のUnimogのようなL4ロードバランサー
- CiliumのようなKubernetes等をターゲットとしたCloud Native Networking(CNI)
- Google Kubernetes Engine;GKEやAmazon EKS Anywhere等も利用
- Falcoのようなランタイムセキュリティツール
hello worldプログラムでeBPFのお作法を学ぶ
パケットを受信するたびに hello from xdp!
を出力するだけのCで書かれたeBPFプログラムが次のものです。
#include "vmlinux.h" #include <bpf/bpf_helpers.h> SEC("xdp") int hello(struct xdp_md *ctx) { bpf_printk("hello from xdp!"); return XDP_PASS; } char LICENSE[] SEC("license") = "Dual BSD/GPL";
eBPFはカーネルスペースでサンドボックス化された仮想マシン上で実行されます。具体的な流れは以下の通りです。
- C言語でeBPFプログラムを記述
- ClangやGCCでeBPFバイトコードにコンパイル
- bpfシステムコールでカーネル空間にロード
- Verifierが安全性を検証
- アーキテクチャに合わせてネイティブコードにJITコンパイル
- フックポイントで実行
安全性を検証する重要な機構がeBPF Verifierです。 DAG(Directed Acyclic Graph)を作成し、到達不可能な命令がないかなどをチェックします。
それでは、実際にeBPFをターゲット(-target bpf
)にしてコンパイルし、カーネル空間にロードしてみましょう。
$ clang \ -I./include \ -target bpf \ -Wall \ -O2 \ -g \ -o hello.bpf.o -c hello.bpf.c $ sudo bpftool prog load hello.bpf.o /sys/fs/bpf/hello
次にロードしたプログラムのIDを bpftool
で確認し、デバイス(NIC)にアタッチします。
$ sudo bpftool prog list 3: cgroup_device tag e3dbd137be8d6168 gpl loaded_at 2023-11-11T11:11:38+0000 uid 0 xlated 504B jited 310B memlock 4096B pids systemd(1) ... 30: xdp name hello tag 744c65b05702d8c0 gpl loaded_at 2023-11-11T03:25:30+0000 uid 0 xlated 96B jited 71B memlock 4096B map_ids 3 btf_id 40 $ sudo ip netns exec host0 bpftool net attach xdp id 30 dev h0 $ sudo ip netns exec host0 ip link show dev h0 3: h0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether b6:94:06:0f:86:db brd ff:ff:ff:ff:ff:ff link-netns host1 prog/xdp id 30 tag 744c65b05702d8c0 jited
手順は省略しますがが、本ワークショップでは、Network Namespaceを使ってテスト用ネットワークを作成します。
eBPFのライセンスに注意
eBPF プログラムのライセンスにも注意が必要です。BSD系OS経由のclassic BPF(cBPF)はBSDライセンスですが、extend された eBPFプログラムのライセンスはLinuxカーネルライセンスのGPLv2と互換性が必要です。
試しに、eBPFプログラムのライセンス行をコメントアウトしてビルドし、先程と同じ手順でデバイスにアタッチしてみましょう。
$ sudo bpftool prog load hello.bpf.o /sys/fs/bpf/hello libbpf: prog 'hello': BPF program load failed: Invalid argument libbpf: prog 'hello': -- BEGIN PROG LOAD LOG -- 0: R1=ctx(off=0,imm=0) R10=fp0 ; int hello(struct xdp_md *ctx) { 0: (18) r1 = 0x21706478206d6f ; R1_w=9412251045883247 ; bpf_printk("hello from xdp!"); 2: (7b) *(u64 *)(r10 -8) = r1 ; R1_w=9412251045883247 R10=fp0 fp-8_w=9412251045883247 3: (18) r1 = 0x7266206f6c6c6568 ; R1_w=8243311830880773480 5: (7b) *(u64 *)(r10 -16) = r1 ; R1_w=8243311830880773480 R10=fp0 fp-16_w=8243311830880773480 6: (bf) r1 = r10 ; R1_w=fp0 R10=fp0 ; 7: (07) r1 += -16 ; R1_w=fp-16 ; bpf_printk("hello from xdp!"); 8: (b7) r2 = 16 ; R2_w=16 9: (85) call bpf_trace_printk#6 cannot call GPL-restricted function from non-GPL compatible program processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 -- END PROG LOAD LOG -- libbpf: prog 'hello': failed to load: -22 libbpf: failed to load object 'hello.bpf.o' Error: failed to load object file
コンパイルは成功しますが、ロード時に cannot call GPL-restricted function from non-GPL compatible program というライセンス起因のエラーが発生しました。
Verifierはライセンス情報もチェックしていることがわかります。
Verifierのエラーログはわかりにくいので、めげないようにしましょう。
より複雑なコードを拡張していく
Step 1のHello World
プログラムは最初から完成形が提示されていますが、後続のパケットカウンタやロードバランシングなど機能では、ボイラープレートを元に参加者がメインロジックをコンパイラ・ Verifierに怒られながら実装していきます。
main
ブランチで目指す動作を確認したあと、ワークショップ用の handson
ブランチに切り替えてマイペースに作業を進めることも可能です。
ワークショップ用スライドとGitHubのサンプルコードレポジトリを参考にしてください。
講義のベースになっているスライドは約170ページもあリ、4時間のワークショップでは一部をとばしても100ページ程度まで進みました。
すべてをこなす場合、8時間程度は覚悟しましょう。
eBPF本の待望の邦訳が2023年12月に出版!
2023年4月に、Ciliumの開発を主導するIsovalent社のchief open source officerをつとめるLiz Riceが"Learning eBPF"を出版しました。
本書の邦訳である『入門 eBPF Linuxカーネルの可視化と機能拡張』は、同年12月に刊行されます。
Learning eBPFの邦訳版、「入門eBPF」が12/19発売予定です。 .@udzura さんと二人で翻訳しました。Linuxカーネルの最新のトレース、拡張技術の概念から使い方、マニアックな仕組みまで一気に紹介していますhttps://t.co/DcskGAEV60
— sat (@satoru_takeuchi) October 24, 2023
書影きたああああああああああああああhttps://t.co/3mKnK1KFEr
> Liz Rice (著), 武内 覚 (翻訳), 近藤 宇智朗 (翻訳)
— Uchio Kondo🐝 (@udzura) October 24, 2023
翻訳はLinux低レイヤーに強い武内 覚さんと近藤 宇智朗さんという強力なペアによって行われています。年末・年始の必読書と言えるでしょう。
最後に
普段はパブリッククラウドのマネージドサービスにおんぶにだっこなゆるふわ勢にとって、今回のワークショップはクラウドの裏側で動いているであろう仕組みをパケットの気持ちになって体感するいい機会となりました。
講師のテラシマさん、タジマさん、誘ってくれた同僚のべこみんに感謝します。