pfを使い外部からのアクセスを内部ネットワークへ転送する
FreeBSDではファイアウォールとしてpf
を使えます。くわえてFreeBSDではbhyve
やjail
のようなハイパーバイザやコンテナも利用できます。FreeBSD特有の連携というわけではありませんが、これらの機能を連携させることで、仮想マシンやコンテナ上のデータをそのホストで提供しているかのように振る舞えます。
ネットワーク構成
今回例に挙げるネットワーク構成は図1のとおりです。
あるLAN(ここでは172.16.0.0/24のネットワーク)にはおもにデスクトップPCやノートPC、スマートフォンが接続されます。物理マシンは基本的にこのネットワークに所属するわけです。
一方「PC A」では内部ネットワーク192.168.1.0/24をつくり、そのネットワークにゲストの仮想マシンやコンテナを接続させるようにしています。ようはNATです。「PC A」がゲートウェイの役割も果たすため「仮想マシン A」や「仮想マシン B」からインターネットに出ることはできます。しかし172.16.0.0/24内の「PC B」から「仮想マシン A」には直接アクセスできません。
リダイレクトのためのpf.conf
ここで「PC B」から「仮想マシン A」「仮想マシン B」へアクセスするには、「PC A」でpf
を動かしリダイレクトの設定をします。具体的には、/etc/pf.conf
を書き、service pf start
するだけです。まずはpf.conf
を書きましょう。
ext_if = "re0" # 「PC A」のネットワークインタフェース
bhyve_internal_network = "192.168.1.0/24" # 仮想マシンの内部NW
vm_A = "192.168.1.20" # 「仮想マシン A」のIPアドレス
vm_B = "192.168.1.50" # 「仮想マシン B」のIPアドレス
# 192.168.1.0/24と「PC A」のネットワークインタフェースとでNATします
nat on $ext_if from { $bhyve_internal_network } to any -> $ext_if
# リダイレクトの設定
# re0へのTCP通信が特定のポートへ来たのであれば内部NWのVMへそれぞれ
# 転送します
rdr on $ext_if proto tcp from any to $ext_if port 80 -> $vm_A port 80
rdr on $ext_if proto tcp from any to $ext_if port 443 -> $vm_A port 443
rdr on $ext_if proto tcp from any to $ext_if port 22 -> $vm_B port 22
# はじめにre0への通信はすべてブロックします
block in on $ext_if all
# 外向きのパケットはすべて許可します
pass out all
# 許可する通信を宣言します
# 192.168.1.20の80番・443番へのアクセスと、
# 192.168.1.50の22番へのアクセスは許可します
pass in on $ext_if inet proto tcp from any to $vm_A port 80
pass in on $ext_if inet proto tcp from any to $vm_A port 443
pass in on $ext_if inet proto tcp from any to $vm_B port 22
リダイレクトの設定をrdr
ルールで記述しても、pass
ルールで通信を許可することを忘れないでください。
またnat
やrdr
、pass
といった各ルールは一定の順序にしたがって書くよう標準で強制されています。詳細はオンラインマニュアルpf.conf(5)
に譲りますが、ここではTranslationのルールnat
・rdr
はPacket Filteringのルールblock
・pass
よりも先に書かなければいけません。
pfを動かす
/etc/pf.conf
に不備がなければpfデーモンを動かしルーティングを開始してください。文法エラーなどなにかしらの不備がある場合、pfは動かずエラーメッセージを出力して終了します。
service pf start
おわりに
上記のように通信を別ホストに転送する設定によって、ホストPCで直接なにかしらのデータやコンテンツを管理することなく、比較的安全なVMの上で任意のサーバを運用できます。今回はホストOSがFreeBSDという前提で話を進めましたが、仮想マシンのOSは自由に選択できます。「NATでネットワークを隔離したいけれど、LAN内から外部アクセスを受け付けたい」要求をうまく満たせられるでしょう。