はじめに
Cilium は透過的な暗号化機能として WireGuard を採用していますが、Linux カーネルにおける WireGuard の立ち位置や、Cilium のコア技術である eBPF とどのように連携しているのか気になったので調べてみました。
Linux カーネルへの統合背景
Linux カーネルにおける WireGuard の実装は Linux 5.6(2020 年 3 月リリース) で正式にカーネルのメインラインとして統合されました。
- 登場時期:2020 年 3 月(Linux Kernel 5.6)
以前は、カーネルモジュール(DKMS)として別途インストールするか、Go 言語によるユーザ空間実装である wireguard-go を利用する必要がありました。
統合による技術的メリット
標準搭載
Ubuntu 20.04 以降等の比較的新しい Linux ディストリビューションであれば、追加のインストール作業なしでネイティブに利用することができます。
高速化
従来の wireguard-go はユーザ空間とカーネル空間を行き来する必要があり、少なからずコンテキストスイッチによるオーバヘッドが生じましたが、カーネルネイティブ版はメモリコピーが削減され、処理速度が大幅に向上しています。
コードのシンプルさ
Linus 氏が、既存の VPN プロトコルと比較してコードベースが非常にシンプルであることを高く評価しており、この保守性の高さも普及の要因となっています。
各コンポーネントの役割
Cilium は eBPF を活用したネットワークプラグインですが、暗号化処理そのものを eBPF で行っているわけではありません。
両者の役割分担は明確に定義されています。
- eBPF
- パケットのルーティング、フィルタリング、およびインターフェースへのリダイレクト制御を行う
- WireGuard
- 実際のパケット暗号化および復号処理(ChaCha20-Poly1305 アルゴリズムの実行)を提供する
連携の仕組み
Cilium における暗号化通信は、Control-Plane と Data-Plane が連携して実現されます。
以下は、Pod から送信されたパケットが、対向ノードへ届くまでのフローです。
1. Cilium(Control-Plane)の役割
通常であれば、WireGuard の利用には設定ファイル(wg0.conf 等)への対向 Peer IP や公開鍵の記述が必要ですが、Kubernetes 環境下で頻繁に増減する Pod に対して手動管理を行うことは困難です。
そのため、Cilium Agent がクラスタ内全ノードの公開鍵交換と設定更新を自動的に実行します。
2. eBPF(Data-Plane)の役割
Pod からパケットが送信された直後、eBPF が処理に介入します。
宛先が別ノードの Pod であり、かつポリシで暗号化が有効であると判断した場合、eBPF はパケットを物理インターフェース(eth0)ではなく、WireGuard 用のインターフェース(cilium_wg0)へリダイレクトさせます。
3. WireGuard(暗号化処理)の役割
インターフェースへ渡されたパケットに対し、カーネルモジュールが暗号化処理を行い、UDP パケットへカプセル化して送信します。
eBPF だけで暗号化しない理由
eBPF プログラムには、安全性を担保するためにループ処理や命令数に厳しい制限が設けられています。
AES や ChaCha20 といった計算コストの高い暗号化アルゴリズムを eBPF プログラム内で実装することは、パフォーマンスや Verifier の制限の観点から現実的ではないと思われます。
そのため、高速な暗号化処理はカーネルネイティブの機能である WireGuard に任せ、そこへのパケットフロー制御を eBPF が担当するという構成が、現在の最適解となっているようです。
まとめ
Cilium の高性能な暗号化通信は、以下の要素によって支えられています。
- WireGuard(Kernel):Linux 5.6 以降で標準化された、高速な暗号化モジュール
- Cilium:鍵管理と設定を自動化する Control-Plane としての役割を担う
- eBPF:パケットを適切なインターフェースへ誘導する Data-Plane としての役割を担う
カーネルネイティブな機能と、eBPF によるプログラマブルな制御を組み合わせることで、効率的かつ安全なコンテナ間通信が実現されています。