目次

名前空間の操作,その7: ネットワーク名前空間

Linux 名前空間について最後に見てからしばらく時間が経った.このシリーズには最後に埋めなければいけない欠けたピースがあった.それはネットワーク名前空間である.名前が示すように,ネットワーク名前空間はネットワークのデバイス,アドレス,ポート,ルーティング,ファイアウォールのルール等を分割する.本質的に,稼働中の単一のカーネルインスタンス内でネットワークを仮想化する.ネットワーク名前空間は 2.6.24 で導入された.ほとんど丁度 5 年前の事である.それ以来,この機能は多数のデベロッパーからは大部分無視されてきたように見える.

基本的なネットワーク名前空間の管理

他のネットワーク名前空間と同様に,ネットワーク名前空間は clone() システムコールのフラグ CLONE_NEWNET を与えることによって作成する.コマンドラインからは,ip コマンドを使ってセットアップを行い,ネットワーク名前空間を扱うのが便利である.例えば,

    # ip netns add netns1

このコマンドは netns1 という名前のネットワーク名前空間を新たに作る.ip コマンドがネットワーク名前空間を作成した時,その名前空間に対する bind mount を /var/run/netns 以下に作成する.これにより,名前空間内でプロセスが実行されていない場合でもネットワーク名前空間が持続でき,名前空間の操作もそれを通して可能になる.ネットワーク名前空間は,使用可能になるまでにかなりの設定が必要となるので,この機能はシステム管理者にとっては重宝する.

“ip netns exec” コマンドで名前空間内でネットワーク管理コマンドを実行可能である.

    # ip netns exec netns1 ip link list
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT 
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

このコマンドは名前空間内のインターフェースを表示する.

    # ip netns delete netns1

このコマンドは指定したネットワーク名前空間を参照している bind mount を除去する.しかし,名前空間自身は,内部でプロセスが動いている限りは持続する.

ネットワーク名前空間の設定

新しいネットワーク名前空間はループバックデバイスを持っている以外はネットワークデバイスを持っていない.ループバックデバイスは別として,ネットワークデバイス (物理,仮想,ブリッジなど…) はそれぞれ単一のネットワーク名前空間にのみ出現できる.さらに,(実際の物理的なハードウェアに接続されている) 物理デバイスは root 以外は名前空間に割り当てできない.代わりに,仮想ネットワークデバイス (例えば仮想イーサネット,veth) は root 以外でも作成可能で,名前空間に割り当て可能である.これらの仮想デバイスにより,名前空間内のプロセスがネットワークを通じて通信することが可能になる.設定され,ルーティングされ,その他の設定が行われる.

最初に作成された際,新しい名前空間の lo ループバックデバイスはダウンしている.なのでループバックデバイスに対する ping も失敗する.

    # ip netns exec netns1 ping 127.0.0.1
    connect: Network is unreachable

起動させるとループバックデバイスへの ping は成功する.

    # ip netns exec netns1 ip link set dev lo up
    # ip netns exec netns1 ping 127.0.0.1
    PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
    64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.051 ms
    ...

しかし,この時点では netns1 とルート名前空間の間の通信はできない.これをできるようにするために,仮想イーサネットデバイスを作成し,設定する必要がある.

    # ip link add veth0 type veth peer name veth1
    # ip link set veth1 netns netns1

最初のコマンドは相互に接続された仮想イーサネットデバイスのペアを作成している.veth0 へのパケットは veth1 で受信され,逆もそうなる.2 つ目のコマンドは veth1 を netns1 名前空間に割り当てている.

    # ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up
    # ifconfig veth0 10.1.1.2/24 up

それから,この 2 つのコマンドで 2 つのデバイスに IP アドレスを割り当てている.

    # ping 10.1.1.1
    PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
    64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.087 ms
    ...
    
    # ip netns exec netns1 ping 10.1.1.2
    PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
    64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.054 ms
    ...

上に示したように,双方向の ping での通信が可能になっている.

前述のように,route コマンドや iptables -L コマンドを netns1 内で実行すると,名前空間はルーティングテーブルやファイアウォールのルールを共有しないことがわかる.

    # ip netns exec netns1 route
    # ip netns exec netns1 iptables -L

最初に単純に 10.1.1 サブネット (veth1 を使って) へのパケットに対するルートが表示されるだろう.一方,2 つ目は iptables が設定されていない結果が表示されるだろう.これらからわかることは,netns1 からインターネットへ送られたパケットは,恐怖の “Network is unreachable” というメッセージを得ることになるだろう.名前空間からインターネットへ接続したい場合は,いくつか方法が存在する.ルート名前空間にブリッジを作成し,netns1 からの veth デバイスを接続する.別の方法としては,NAT を設定した IP フォワーディングをルート名前空間上に作成することである.これらのいずれも (そして他の設定の可能性も存在する) netns1 からのパケットがインターネットへ到達し,それに対する返事を netns1 内で受信することが可能になる.

(clone(), unshare(), setns() 経由で) 名前空間に割り当てられた root 権限でないプロセスは,その名前空間内でセットアップされたネットワークデバイスと設定にのみアクセス可能である.もちろん root であれば新しいデバイスや設定を追加できる.ip netns サブコマンドを使って,ネットワーク名前空間を指し示す方法が 2 つある.netns1 のように名前を与える方法,その名前空間内のプロセス ID による方法である.通常はルート名前空間では init が起動しているので,以下のようなコマンドが指定可能である.

    # ip link set vethX netns 1

これは (おそらく新たに作られた) veth デバイスをルート名前空間に割り当て,他の名前空間からの root ユーザが使用可能である.ネットワーク名前空間内からの root によるこのような操作が望ましくないシチュエーションでは,PID および mount 名前空間の機能により,他のネットワーク名前空間から到達できないようにすることが可能である.

ネットワーク名前空間の使用

ここで見てきたように,名前空間のネットワーキングは何もない (loopbackのみ) ものから,システムのネットワークのケーパビリティにフルアクセスするものまで幅広い.これは,ネットワーク名前空間のいくつもの異なるユースケースにつながる.

原則,名前空間内のネットワークをオフにすることで,管理者は名前空間内のプロセスが名前空間外と接続できないようにすることができる.プロセスがセキュリティホールを通して侵害されていても,botnet への参加やスパム送信のような行為を行うことができない.

ネットワークトラフィックを扱うようなプロセス (例えば Web Server の Worker プロセスや Web Browser のレンダリングプロセス) でも,制限された名前空間内に置くことが可能である.リモートのエンドポイントとの接続が確立されたら,その接続のファイルディスクリプタは,clone() で作られた新しいネットワーク名前空間内の子プロセスから扱うことが可能である.子プロセスは親のファイルディスクリプタを継承しているので,ファイルディスクリプタにアクセスできる.制限されたネットワーク名前空間内のプロセスに対して Unix ソケット経由で接続済みのファイルディスクリプタを送る親プロセスの可能性が存在する.どちらのケースでも,名前空間内の適切なネットワークデバイスがないことによって,子プロセスや Worker プロセスが,更なるネットワーク接続を行うことを不可能にする.

名前空間は,単一のホスト上での複雑なネットワーク設定のテストに使うことも可能である.慎重に扱うべきサービスを,より隔離したファイアウォールで制限された名前空間で実行するということもできる.明らかに,コンテナの実装もネットワーク名前空間を,それぞれのコンテナに自身のネットワークを与え,コンテナ外のプロセスに制約されないようにするために使用している.などなど…

一般に名前空間はシステムリソースをパーティショニングし,プロセスのグループを他のグループのリソースから隔離するために提供されている.ネットワーク名前空間はそれと同等以上のものである.しかし,ネットワークはセキュリティの不備において影響を与えやすい領域であるので,様々なネットワークの隔離の提供は特に役に立つ.もちろん,複数のタイプの名前空間を同時に使うことはセキュリティや他の要求に対するより一層の隔離を提供できる.