VPN クライアントプールごとに宛先レンジを一つ遮断する
nftables のルール一つで、許可済み VPN プールに対して宛先プレフィックスを拒否できます。ゲートウェイ自身の通信には触れません。フックと位置を合わせてください。
ルール一つで、許可済みの VPN プールを宛先レンジから遠ざけられます。ゲートウェイが行う他のことには影響しません。ルール自体は短いものです。機能するかどうかを決めるのは、そのルールが住むフックと、チェーン内の位置です。この二つを誤ると、正しく見えるのに挙動が不安定なファイアウォールになります。ルールがパケットを見る時点でパケットが何をしているかから始めてください。
ルールが実際に照合するもの
このルールは同時に三つを照合します。入力インターフェース、送信元プレフィックス、宛先プレフィックスです。ドロップが適用されるには三つすべてが真である必要があり、それがこのルールを狭く保ちます。三つの別々のポリシーとして読むより、一つの式として読むほうが簡単です。
インターフェースの照合は、転送されるクライアント通信をゲートウェイ自身の接続から区別するものです。これがなければ、送信元プールだけを指定したルールは、ゲートウェイ自身がそのアドレスから生成するパケットにも影響します(そういうことが起きれば)。送信元プレフィックスはポリシーを許可済みクライアントに限定し、宛先プレフィックスは一つのレンジに限定します。ルールはリストではなく交差として読んでください。
編集する前に三つの値を書き留めてください。トンネルインターフェース名、サーバーが配布するプール、拒否する予定のプレフィックスです。どれか一つに誤字があると、きれいに解析されるのに何も守らないルールになります。その三つの値はルールのそばの変更記録に残してください。
フックがルールの適用対象を決める
netfilter チェーンはフックに接続され、どのパケットをチェーンが見るかを決めるのはフックです。forward フックはゲートウェイ経由でルーティングされる通信を見ます。これがクライアントから宛先への通信です。チェーン内の他のすべては別の対象に向いています。
input フックはゲートウェイ自身宛ての通信を見るため、そこに置いたルールは通過通信ではなく自身のサービスへのアクセスを制御します。output フックはゲートウェイが生成する通信を見ますが、これはクライアントプールのポリシーが必要とするものの逆です。チェーンの名前はルールセットを書いた人が選んだ任意のラベルなので、名前からフックを推測してはいけません。チェーンがどこに接続されているかを確認してから、何を照合できるかを想定してください。
| Hook | Traffic it sees | Right for this policy |
|---|---|---|
| input | Addressed to the gateway | No, that is the host's own services |
| forward | Routed through the gateway | Yes, for client-to-destination traffic |
| output | Generated by the gateway | No, that is the opposite direction |
接続先を読むことは一行の確認であり、パケットを決して見ないチェーンにルールが落ちるのを防ぎます。
広い accept より前にルールを置く
ルールは順に評価され、最初の判定が勝ちます。チェーンの前方にある広い accept は、それに一致するパケットの評価を終わらせるので、後から追加したドロップはそれらのパケットには決して実行されません。この順序の規則こそが、正しく見えるルールが効果を持たない理由のすべてです。
末尾に追加するのではなく、accept の前に挿入してください。チェーンにトンネルインターフェース用の一般的な accept が既にあるなら、新しいルールはその前になければ飾りです。編集したファイルではなく結果の順序を確認してください。複数のファイルから組み立てたルールセットは、どれとも一致しないことがあります。そのうえでプールからのテストパケットで確認してください。
sudo nft list chain inet filter forward
sudo nft insert rule inet filter forward iifname "tun0" ip saddr 10.90.0.0/24 ip daddr 198.51.100.0/24 drop
sudo nft -c -f /etc/nftables.conf
三つ目のコマンドはファイルを適用せずに解析するので、構文エラーが障害になる前に捕まえられます。ロールバック計画を用意して適用してください。forward チェーンの誤ったルールは、作業に使っているトンネルを切断しうるからです。
既存のフローは新しいルールを気にしない
ルールが存在する前に作られた conntrack エントリは、以前の accept に一致し続けます。だから新しいドロップが、新しい接続には効いているように見えて、テスト中の接続には何もしないことがあります。
チェーンの先頭にあるステート照合を読んでください。あなたのルールより前に established と related の通信を accept しているなら、すでに進行中のフローは閉じるまで流れ続けます。緊急ルールでは通常それが望む挙動であり、即時の切断を期待していると混乱します。展開する前にどちらの効果が欲しいかを決めてください。開いた接続を使い回すテストは、間違った話をあなたに伝えます。
sudo conntrack -L -s 10.90.0.14 -d 198.51.100.20
sudo nft list ruleset | grep -n -A3 'ct state'
一つ目のコマンドはフローが存在するかを示し、二つ目は早期のステートルールがそれを accept し続けているかを示します。どちらも読み取り専用で、インシデント中に実行しても安全です。
このルールが意味しないもの
このルールはドメインのブラックリストではなく、IPv6 のポリシーでも、個々のアプリケーションアカウントに対する制限でもありません。
それぞれに独自の仕組みが必要です。ドメインのブロックは名前を解決する必要があり、パケットフィルタはそれをしません。IPv6 の通信には独自の照合が必要で、ip 式は ip6 パケットについて何も語りません。アプリケーション層の制限は接頭辞の照合ではなく、サービスまたは認証済みプロキシに属します。これらの要件を分けておくことが、一つの狭いルールに四つの仕事を求めるのを防ぎます。
このルールが果たす契約は正確です。許可済みプールから一つの宛先プレフィックスへの通信は拒否され、無関係なゲートウェイ通信は既存のポリシーを保ちます。その一文をルールのそばに書いておけば、次の人が何のためのものか分かります。