Raspberry Pi の VPN ゲートウェイ:NIC 一枚か、専用クライアントポートか
Pi のポート一つでも選んだクライアントを収容できるが、二つ目のポートがあれば機器を内側に囲い込める。囲い込み、フォールバックの方針、DNS の所有者で構成を選ぶ。
Pi が一台、動作する外向き VPN プロファイルが一つ、そしてそれを経由してインターネットに出るべき機器が二台ある。構成全体を決める問いは、どの手順書に従うかではなく、どれだけ囲い込む必要があるかだ。ポート一つなら Pi はそれらの機器の隣でルーターの LAN に置かれて追加のゲートウェイとして働き、二つ目のポートがあれば Pi が唯一の出口となるセグメントに機器を置ける。この選択のあとのすべて — DHCP、ファイアウォールの範囲、DNS、切断時の挙動 — はそこから決まる。
二つの構成は実際に何が違うのか
どちらの設計もルーティングを行う。違いは、ほかに誰が配線につながっているかと、方針が誤っていたときに何が起きるかにある。
| Layout A: Pi on the ISP LAN | Layout B: dedicated client port | |
|---|---|---|
| Cabling | One Ethernet port, existing switch port | Two interfaces: uplink plus a separate LAN port |
| Can a client bypass the Pi? | Yes, by using the ISP router as its gateway | No, unless the device has another radio or link |
| Who hands out addresses | The ISP router, with a per-client setting or a DHCP option | The Pi, on its own LAN interface only |
| Blast radius of a mistake | Any LAN host, if a rule is too broad | The attached segment |
| Good fit for | One laptop, a console, a temporary test client | Appliances, always-on boxes, untrusted devices |
本当の軸は囲い込みだ。構成 A は助言にすぎず、DHCP が渡したゲートウェイを無視してルーターを選ぶ機器は暗号化されないまま動き続ける。構成 B は、選べる次のホップがほかにないという理由でトポロジーによって強制される。
構成 A:既存 LAN 上の追加ゲートウェイとしての Pi
ISP のルーターが 192.168.50.1、Pi が 192.168.50.2 で、選んだクライアントが Pi を指すとしよう。重要なのは、二つの異なるパケットの流れが一本のケーブルを共有することだ。クライアントの内側のパケットは Pi に届いてトンネルから出なければならず、Pi 自身の暗号化されたパケットは VPN の相手に向けて同じケーブルからルーターへ出なければならない。両者は同じインターフェースを逆向きに流れ、別の扱いを必要とする。
Pi のアドレスは、機器を奪い合う古いインターフェースファイルのレシピではなく、インストール済みのネットワークマネージャーで与える。次にクライアントを設定し、一台に静的ゲートウェイを置くか、192.168.50.2 をルーターとして配る DHCP 予約を使う。二台のためにルーターの DHCP 全体を変えてはいけないし、クライアントがその設定に従うと決めつけてもいけないので、必ず確認する。
弱さは構造的で、直せない。そのセグメントのどのクライアントも 192.168.50.1 を指して平文のまま外に出られるし、二つ目のインターフェースや携帯回線を持つ機器は強制の経路から完全に外れる。その一文が問題の機器にとって受け入れられないなら、答えはすでに出ているので構成 B を使う。
構成 B:専用ポートで機器を内側に囲い込む
ここでは Pi は上流側で 192.168.50.2 をゲートウェイ 192.168.50.1 とともに保ち、二つ目のインターフェースで接続機器のために 10.20.0.1/24 を取る。Pi は二つのネットワークを持つルーターになり、接続されたセグメントの出口はちょうど一つになる。
決める前に、トンネル自身のサブネット、他の拠点間プレフィックス、VPN 経由で届くものすべてと範囲を突き合わせる。遠隔の LAN と衝突する 10.20.0.0/24 は、診断に一晩かかる半端な結果を生む。二つ目のポートが USB アダプターなら、対応していることを確認し、再起動後の並び替えで LAN のアドレスが動かないよう名前をネットワークマネージャーに固定する。
DHCP のリスナーはそのインターフェースだけで動かす。上流側で応答するサーバーは ISP のルーターと競合し、あなたのセグメントのアドレスを家のほかの機器に配ってしまう。LAN インターフェースに結びつけ、宣言した範囲に限定し、Pi 自身のアドレスはプールの外に置く。
転送、変換、そして障害時に閉じる規則
四つのものはよく一つとして説明されるが、一つではない。転送を有効にすること(net.ipv4.ip_forward=1)は、カーネルがインターフェース間でパケットを動かしてよいと伝えるだけで、それ自体は何も許可せず、どの経路も保証しない。出口を選ぶのはルーティングの決定だ。パケットを許可するのは forward チェーンの方針の決定だ。その送信元を書き換えるのは postrouting の決定だ。最初の一つだけを行う構成は、クライアントの通信を上流側から喜んで転送する Pi を生む。
許可を、意図した送信元と通信が使うべきインターフェースに限定し、戻りの経路と Pi 自身に必要な宛先も含める。次に、プロバイダーが LAN のプレフィックスをこちらへ戻さない場合は、トンネルの出口で変換する。ここで、nftables のマニュアルは、転送、ローカル出力、送信元変換を別々の操作として扱っており、ここではそれが正しい考え方だ。
よくある失敗は、物理インターフェースに広い masquerade 規則を置くことだ。すると通信は ISP の経路でインターネットに出るのに、クライアント側からは動作している VPN とまったく同じに見える。それでは何も証明できない。変換は宣言した出口に結びつけたままにし、規則はホストがすでに使っているファイアウォールに置いて、共有の postrouting チェーンを空にする競合する規則セットを足してはいけない。
次にトンネルがない場合を扱う。広いデフォルトルートを入れるクライアントプロファイルは、トンネルが落ちたときに通常のデフォルトが戻り、クライアントの通信が静かに上流側へ戻ることも意味する。平文へのフォールバックを受け入れられない場合、forward の方針は、VPN の経路が消えた状態でクライアントから上流側への通信を明示的に拒否しなければならない。それは想定ではなく拒否規則として書く。Pi 自身の VPN 相手への暗号化された転送は別の local-output の流れであり、許可されたままにしなければならない、そうでなければトンネルは二度と戻らない。
DNS と IPv6 にはそれぞれの答えが要る
クライアントが Pi をリゾルバーとして使うと、ローカルのリスナーに当たり、Pi が新しい問い合わせを始める。その上流の問い合わせは、クライアント用に書いた forward 規則ではなく Pi 自身の経路に従うので、トンネル経由だけのクライアント経路と直接出ていくリゾルバーの組み合わせは、エラーメッセージも出ない漏洩になる。トンネル経由で届くリゾルバーにするか、直接と認めるローカルのリゾルバーにするかを意図して決め、Pi 自身の出力方針をその決定に合わせる。
IPv6 はまた別の話だ。IPv4 の forward 規則は IPv6 について何も制限しないし、上流側のルーター広告は、Pi と、それを通じて接続セグメントに、あなたの方針を迂回する二つ目のデフォルトを渡しうる。同じ原則で IPv6 にも独自の保護経路を与えるか、クライアントセグメントで明示的に制限してそう明言するかだ。
信頼する前に境界を試す
設計を受け入れるのは、一台のクライアントでブラウザーを開くという魅力的な単一のテストがいくつもの壊れた状態で通ってしまうため、四つの別々の確認のあとだけにすること。
本物のクライアントがトンネル経由でインターネットに届くことを確認し、次に同じクライアントがトンネルを落とした状態では届かないことを確認する。DNS の解決が働き、問い合わせが意図した場所から出ていくことを確認する。トンネルの再起動後も Pi 自身の転送が働き、復旧にマシンの再起動が要らないことを確認する。最後に、選んでいない機器を確認し、構成 A では通常どおり動き続けるはずで、構成 B ではそのセグメントに存在してはいけない。
- ポート二つと拒否規則が強制を与え、ポート一つと DHCP の設定が助言を与える。
- 間違ったインターフェースでの変換は成功に見えて、成功ではない。
- Pi 自身の通信、DNS、IPv6 は、どれも推測ではなく決定を要する。