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

Accelerating TCP/IP Communications in Rootless Containers by Socket Switching

Accelerating TCP/IP Communications in Rootless Containers by Socket Switching

SWoPP22022 7/27 OS-3

Fe6461a97e4b884c150fa7f0081cef96?s=128

松本直樹

July 27, 2022
Tweet

More Decks by 松本直樹

Other Decks in Research

Transcript

  1. Accelerating TCP/IP Communications in Rootless Containers by Socket Switching SWoPP2022

    7/27 OS-3 松本 直樹(京都大学), 須田 瑛大(NTTソフトウェアイノベーションセンタ) SWoPP2022 7/27 OS-3 1 2022/7/27
  2. 本研究の背景 コンテナランタイム自体の脆弱性→ランタイムを介した不正操作 “Rootless Container” • ランタイム自体をroot権限(特権)なしで動かすことでセキュリティリスク を軽減 • ネットワークはモジュール(slirp4netns, RootlessKit)により非特権化

    → 性能(スループット)が低いという問題 SWoPP2022 7/27 OS-3 2 ホスト コンテナ ブ リ ッ ジ 等 veth デバイス 要特権! ※veth: ペアで構成される仮想的なL2インタフェース 2022/7/27
  3. 本研究の提案 Rootless Container における通信性能を改善するbypass4netnsを提案 • コンテナ内のソケットをホスト上のソケットに差し替え(Socket Switching) • 通信がボトルネックとなるモジュールを経由しないことで改善 SWoPP2022

    7/27 OS-3 3 2022/7/27
  4. 本研究の成果 bypass4netns により、スループットが向上することを確認 • 特に、外部への通信については顕著な改善がみられる SWoPP2022 7/27 OS-3 4 38.6

    39.2 0.452 35.8 41.4 39.8 0 10 20 30 40 50 Container → Host Host → Container Throughput(Gbps) Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 2022/7/27
  5. Rootless Container について コンテナランタイム自体に脆弱性がある場合がある • Docker CVE-2014-9357 悪意のあるコンテナが任意のバイナリを特権で実行可能 • runc

    CVE-2016-3697 悪意のあるコンテナが意図しないUIDで動作可能 → ランタイム自体の脆弱性により、特権で不正な操作が可能になる可能性 ランタイム自体を非特権で動かす→ Rootless Container • ランタイム自体が一般ユーザー権限で動作する • 脆弱性があった場合、被害範囲を小さくできる SWoPP2022 7/27 OS-3 5 2022/7/27
  6. Rootless Container におけるネットワーク処理 UserNS(UserNamespaces) を用いて、非特権化を実現 ※UserNS: NS内の特権ユーザーをNS外の一般ユーザーにマップする • ランタイムのおおよその機能は UserNS

    でカバー ネットワークに関して、vethデバイスはホスト側の特権を要する → veth を利用しない手法でネットワークの非特権化を実現 • slirp4netns: コンテナ内→外部の通信を担当 • RootlessKit port driver: 外部→コンテナ内の通信を担当 SWoPP2022 7/27 OS-3 6 2022/7/27
  7. Rootless Container におけるネットワーク処理 slirp4netns: コンテナ内からホスト外部への通信を中継 • コンテナネットワークを扱う 内部 NetNS に

    TAPデバイスを作成 • TAPデバイスを利用して、内部 NetNS から外部への通信を中継 SWoPP2022 7/27 OS-3 7 ホスト slirp4 netns 内部 NetNS コンテナ コンテナ ブ リ ッ ジ TAP デバイスを作成し、 TAP のファイルディスクリプタ をホスト側の slirp4netns に渡す TAP デバイスから受け取った パケットを取得し送信 TAP パケット veth veth 2022/7/27
  8. Rootless Container におけるネットワーク処理の問題点 Rootless Container のネットワークの問題点 • 性能の劣化(slirp4netns で顕著) SWoPP2022

    7/27 OS-3 8 38.6 39.2 0.452 35.8 0 5 10 15 20 25 30 35 40 45 Container → Host Host → Container Throughput(Gbps) Rootful Rootless w/o bypass4netns 2022/7/27
  9. 2022/7/27 Rootless Container におけるネットワーク処理の問題点 性能劣化の原因 TCPパケットを再構築し、ソケットから送信するオーバーヘッド SWoPP2022 7/27 OS-3 9

    パケットA パケットα パケット1 パケットB パケット2 パケットβ dstIP: 192.168.1.1, dstPort: 443 dstIP: 151.101.66.132, dstPort: 443 dstIP: 133.3.250.189, dstPort: 443 slirp4netns ソケット ソケット ソケット 192.168.1.1:443 に connect slirp TCPパケットを再構築し、 ペイロードを取得する TAP fd 151.101.66.132:443 に connect 133.3.250.189 :443 に connect
  10. 本研究における提案手法 コンテナ内のソケットをホスト上のソケットへ差し替える(Socket Switching) • 外部へ/外部からの通信が対象(コンテナ間の通信はvethで行われるため対象外) • Socket Switching には Seccomp

    を利用 → コンテナランタイムに対する大きな改変なく実現可能 10 2022/7/27
  11. Seccomp について Seccomp(Secure computing mode) プロセスで呼び出される syscall を制御するモジュール 2種類の制御方式が存在する •

    静的なプロファイルに基づく制御 • Docker 等で用いられる手法 • syscall ごとに挙動をプロファイルとして事前に指定しておく • syscall 呼び出し毎に動的に判断する制御 • Seccomp User-space Notification(Seccomp Notify) • bypass4netns で利用 SWoPP2022 7/27 OS-3 11 2022/7/27
  12. Seccomp Notify について Seccompにおいて動的にsyscallを制御する • 監視プロセスで実行される syscall の読み取りや実行判断を行う SWoPP2022 7/27

    OS-3 12 2022/7/27
  13. Seccomp による Socket Switching Seccomp Notify を利用した Socket Switching •

    SECCOMP_IOCTL_NOTIF_ADDFD を利用 SWoPP2022 7/27 OS-3 13 2022/7/27
  14. bypass4netns での挙動 Seccomp Notify を利用し接続先に応じて Socket Switching • コンテナ内のソケットと同じ設定のソケットをホスト上に作成する必要 SWoPP2022

    7/27 OS-3 14 socket setsockopt connect socket setsockopt bypass4netns send ソケットの作成 設定の反映 Socket Switching 設定を記録 コンテナ ホスト Seccomp Notify 2022/7/27
  15. Socket Switching の流れ bypass4netns では以下の手順に従い Socket Switching を行う ソケットに関係がある syscall

    をSeccomp Notify fd 経由でハンドル 1. syscall の引数を読み出す 2. syscall が接続先を指定している a. 接続先が外部のエンドポイント → Socket Switching を行う b. 接続先が外部のエンドポイントでない → 何もしない 3. syscall がポートをバインドしている a. ポートが公開対象のポート → Socket Switching を行う b. ポートが公開対象のポートでない → 何もしない 4. syscall がソケットの設定を行っている → 設定を記録 SWoPP2022 7/27 OS-3 15 slirp4netns を代替 RootlessKit port driver を代替 2022/7/27
  16. 既存アプリケーションにおけるソケット syscall の調査 Socket Switching に必要な情報 1. ソケットに関係する syscall 2.

    接続先/元が外部であると分かる syscall 3. Socket Switching 前にソケットに対して実行される syscall トレーサーを用いてアプリケーションが利用する syscall を調査 • socket(2) で作成された fd に対して実行される syscall を調査 SWoPP2022 7/27 OS-3 16 socket bind listen accept clone recv send accept accept PID=x PID=y fd=α fd=β 2022/7/27
  17. 調査結果 以下のアプリケーションを対象に調査 • ping, wget, apache, nginx, iperf3 • 対象となるソケットは

    SOCK_STREAM, SOCK_DGRAM • トレースのログを解析し、対象の syscall を抽出 接続先/元が外部であると分かる syscall • connect, sendto(アドレス付き),bind Socket Switching 前にソケットに対して実行される syscall • ソケット作成後から接続先/元が外部であると分かるまでに実行される syscall を抽出 • 設定を行うsyscall: setsockopt, ioctl SWoPP2022 7/27 OS-3 17 2022/7/27
  18. bypass4netns での挙動 Seccomp Notify で 以下の syscall をフック connect, sendto,

    bind, setsockopt, ioctl 以下の手順で処理を行う 1. Syscall の引数を読み出す 2. Syscall が connect, sendto(アドレス付き)である a. 接続先が外部のエンドポイント → Socket Switching を行う b. 接続先が外部のエンドポイントでない → 何もしない 3. Syscall が bind である a. ポートが公開対象のポート → Socket Switching を行う b. ポートが公開対象のポートでない → 何もしない 4. Syscall が setsockopt, ioctl である → 引数を設定として記録 SWoPP2022 7/27 OS-3 18 2022/7/27
  19. bypass4netns での挙動 Seccomp Notify を利用し接続先に応じて Socket Switching → コンテナ内のソケットと同じ設定のソケットをホスト上に作成する SWoPP2022

    7/27 OS-3 19 socket setsockopt connect socket setsockopt bypass4netns send ソケットの作成 設定の反映 Socket Switching 設定を記録 コンテナ ホスト Seccomp Notify 2022/7/27
  20. 実装 3つのコンポーネントを実装 • bypass4netns: Seccomp Notify や Socket Switching の処理を担う

    • bypass4netnsd: nerdctl と連携し、bypass4netns の管理を担う • nerdctl(改修): bypass4netnsd との連携機能を追加 実験的要素として nerdctl v0.17.0 にマージ済み ※nerdctl: 高レベルランタイムであるcontainerd用CLI. コンテナ関連の新機能の実験場として開発 nerdctl run --label nerdctl/bypass4netns=true alpine で容易に利用可能 SWoPP2022 7/27 OS-3 20 2022/7/27
  21. 性能評価及び評価環境 以下の観点で性能を評価 • スループット • CPU使用率 • syscall 実行のオーバーヘッド •

    アプリケーション(wget, nginx) 評価には以下のHyper-V 上の VM 環境を利用 • Host CPU: Ryzen 7 PRO 5850U • Host メモリ 32GB • Host OS: Windows 11 Pro (build 22000.739) • VM CPU: 4 コア • VM Memory: 8GB • VM OS: Ubuntu 21.10 (kernel 5.13.0-1025-azure) SWoPP2022 7/27 OS-3 21 2022/7/27
  22. 性能評価(スループット) 2つの場合についてスループットを iperf3 で計測 Case A. コンテナと接続先/元ホストが同一VM Case B. コンテナと接続先/元ホストが別のVM

    → いずれの場合についても、従来より性能が向上したことを確認 38.6 39.2 0.452 35.8 41.4 39.8 0 10 20 30 40 50 Container → Host Host → Container Throughput(Gbps) Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 16.8 16.0 1.11 13.6 21.0 16.1 0 5 10 15 20 25 Container → Other host Other host → Container Throughput(Gbps) Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 2022/7/27 22 A. コンテナと接続先/元ホストが同一VM B. コンテナと接続先/元ホストが別のVM
  23. 性能評価(CPU使用率) iperf3(1Gbps制限,120秒間)動作中のCPU使用率(sys + user)を計測 → いずれの場合でも、従来よりCPU使用率が減少したことを確認 23 2022/7/27 0 5

    10 15 20 25 30 35 40 0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 CPU使用率(user + sys) % 経過時間(秒) w/ bypass4netns(case A) w/o bypass4netns(case A) w/ bypass4netns(case B) w/o bypass4netns(case B)
  24. 性能評価(syscall 実行のオーバーヘッド) 単純なプログラムで syscall 実行のオーバーヘッドを計測 • socket(SOCK_DGRAM), connect, close を繰り返す

    • 10万回実行し、平均値で比較 →従来より実行に30倍の時間を要することを確認 Seccomp Notify では特定の syscall のみ処理するため、 実アプリケーションならば影響は小さくなると考えられる SWoPP2022 7/27 OS-3 24 w/o bypass4netns w/bypass4netns 1回あたりの実行時間(us) 3.22 100.05 2022/7/27
  25. 性能評価(wget) コンテナ内で外部へ wget を実行したときにかかる時間を計測 • 環境は B. 別VM で、Nginx をサーバーとして利用

    → 小さいファイルは Socket Switching のオーバーヘッドの影響が出ている ファイルサイズが一定以上でRootfulな場合と同等の性能 SWoPP2022 7/27 OS-3 25 0 1 2 3 4 5 6 1KiB 32KiB 128KiB 512KiB 1MiB ダウンロード時間(ミリ秒) ファイルサイズ Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 0 0.5 1 1.5 2 2.5 32MiB 128MiB 512MiB 1GiB ダウンロード時間(秒) ファイルサイズ Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 2022/7/27
  26. 性能評価(nginx) コンテナ内の nginx を公開した場合でダウンロード時間を計測 • 環境は B. 別VM で、wget をクライアントとして利用

    → bypass4netns を用いない場合に比べて用いる場合のほうが高速 Rootful なコンテナとほぼ同等の性能 SWoPP2022 7/27 OS-3 26 0 1 2 3 4 5 6 1KiB 32KiB 128KiB 512KiB 1MiB ダウンロード時間(ミリ秒) ファイルサイズ Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 32MiB 128MiB 512MiB 1GiB ダウンロード時間(秒) ファイルサイズ Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 2022/7/27
  27. 考察 1. 他のネットワークコンポーネントとの組み合わせ コンテナのNetNSや内部NetNSをバイパスすることによる弊害 • 外部エンドポイントへの通信の制御をホスト側でする必要がある(要特権) 2. セキュリティ • NetNSによるネットワークの分離を壊している

    • Seccomp Notify で time-of-check to time-of-use(TOCTOU)攻撃が 成立する可能性がある 3. slirp4netns, RootlessKit との関係(bypass4netns の制約) • VXLAN をサポートしない→ Usernetes 等では利用できない ※ Usernetes: 特権なしで動く Kubernetes • 全ての通信について bypass4netns で高速化できるわけではない SWoPP2022 7/27 OS-3 27 2022/7/27
  28. まとめ 目的: Rootless Container における外部へ/からの通信の高速化 • Rootless 化による通信性能の劣化の改善 提案: Socket

    Switching による高速化手法 bypass4netns • コンテナ内のソケットをホスト上のソケットに差し替える 実装, 評価: 既存のモジュールに比べて高速化を達成 • コンテナ内→外部の通信については 約20倍の高速化を達成 考察: セキュリティ上の課題や bypass4netns 自体の制約が存在 • 従来のネットワークモジュールと組み合わせた利用が必要 SWoPP2022 7/27 OS-3 28 2022/7/27
  29. 補足資料: 性能評価(スループット) -r オプション(server → client に流す)場合についても同様の傾向 SWoPP2022 7/27 OS-3

    29 53.5 43.0 4.25 26.1 55.2 45.2 0 10 20 30 40 50 60 Container → Host Host → Container Throughput(Gbps) Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns 13.5 20.9 3.56 11.8 13.6 21.2 0 5 10 15 20 25 Container → Host Host → Container Throughput(Gbps) Rootful Rootless w/o bypass4netns Rootless w/ bypass4netns A. コンテナと接続先/元ホストが同一VM B. コンテナと接続先/元ホストが別のVM 2022/7/27
  30. 補足資料: 性能評価(スループット) bypass4netns を使うとRootful なコンテナより速い場合がある → iptables や veth, bridge

    のオーバーヘッドによる可能性 curl のパケット処理に関係したカーネル関数数を ipftrace2 で集計 Rootful な場合に比べて、bypass4netns の場合は関数数が少ないことを確認 → bypass4netns を利用する場合が速い原因の一つとして考えられる SWoPP2022 7/27 OS-3 30 Rootful w/o bypass4netns w/ bypass4netns 処理カーネル関数数 673 922 198 2022/7/27
  31. 補足資料: トレース結果(wget) • DNS 名前解決 → 仮接続 → TCP 接続で取得

    • connect(2) で差し替えた直後に ioctl(2) や fnctl(2) を実行 • ハンドルする必要は特にない • connect(2) 前に実行される場合はありそう? 31 2022/7/27
  32. 補足資料: トレース結果(Nginx) • Nginx 特有のイベント多重な処理が行われていることが分かる • 複数プロセスでの epoll_wait による待ち受け •

    bind(2) → listen(2) → 別プロセスで accept(2) • bind(2) 以降は特にハンドルする必要はない 32 2022/7/27 SWoPP2022 7/27 OS-3