iptables: VPN クライアントを一つのホストだけに届かせる
必要なルールは FORWARD にあり、INPUT ではありません。VPN プールに一つの宛先だけを許可し、残りは拒否し、カウンタとロールバック手順で証明します。
無関係に見える二件のサポートチケットが、実は同じ原因を共有しています。第一の件では管理者はサーバーがトンネルからの接続だけを受け入れることを望み、第二の件では VPN ユーザーは内部ホスト一台だけに到達できてそれ以上は何も届かないべきです。どちらのポリシーも FORWARD に属しますが、どちらもたいてい INPUT で試されます。結果はファイアウォールのように見えて、実際にはプレースホルダーのように振る舞います。
どちらのチェーンが問いに答えるか
VPN クライアントが LAN のホストへ、あるいはインターネットへ向けて送るパケットは、カーネルによって転送され FORWARD で評価されます。INPUT と OUTPUT が見るのは、サーバー自身で終わるか、サーバーから始まる通信だけです。したがって tun0 以外から来るものをすべて拒否しても、守れるのはサーバー自身のリスナーだけであり、既存のフローを先に許可しない限り SSH セッションも切れてしまいます。クライアントがどこへ行けるかは何も変わりません。
まず問いを言葉にします——誰がサーバーに到達できるのか、それともクライアントはどこへ行けるのか。多くのネットワークは両方の答えを必要とし、それぞれ別のチェーンに置きます。
まず状態、次に許可、最後に拒否
許可リストが機能するのは、個別の許可が一般的な拒否より上にあり、戻りの通信がその両方より上で許可されている場合だけです。ルールは明示的な位置に挿入し、そのあと iptables -S FORWARD でチェーンを出力して、順序を推測ではなく目で確認できるようにします。
POOL=10.99.0.0/24
iptables -I FORWARD 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD 2 -s "$POOL" -d 172.31.20.15 -p tcp -m multiport --dports 443,3389 -j ACCEPT
iptables -I FORWARD 3 -s "$POOL" -j REJECT実際の通信に耐えられるかは二つの点で決まります。状態のルールがないと、いま許可した接続への戻りパケットも拒否の対象として評価され、破棄されます。制限のない LOG ルールは、スキャンが一度当たっただけで小さなパーティションを埋め尽くすことがあるため、記録を続ける前に -m limit --limit 10/min を追加します。REJECT は即座にエラーを返すのでリストを調整している間は扱いやすく、DROP は黙って捨てるため誤りはすべてタイムアウトとして現れます。どちらかを意図的に選び、その選択を変更記録に書きます。
転送と NAT が先に動いている必要がある
フィルタリングは経路の存在を証明できません。まずカーネルがそもそも転送するのかを確認し、その設定をシェルの一度きりのコマンドではなく永続化します。フィルターは最後の層であり、最初の層ではありません。
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s "$POOL" -o eth0 -j MASQUERADEマスカレードをどこに置くかは、クライアントがどこから出るかで決まります。トンネルを通って遠隔ネットワークへ出るなら、NAT ルールは WAN インターフェースではなくそのインターフェースに置きます。そのうえでカウンタを見て、POSTROUTING のカウンタがまったく動かないのに FORWARD の許可数が増えているなら、戻り経路が壊れていてフィルターは正常です。この読み方で、問題ではなかったルールを書き直す半日が節約できます。
メールのブロックは隣のチェーンの話
INPUT でポート 25 を塞いでも止まるのは VPN サーバー宛てのメールだけです。トンネル経由でメールを送る侵害されたクライアントは転送されるため、ブロックは FORWARD の 465 と 587 の隣に置く必要があります。あるアプリケーションが正当にメールを中継するなら、その宛先とポートをそのルールより上に置きます。
iptables -I FORWARD 2 -s "$POOL" -p tcp -m multiport --dports 25,465,587 -j REJECTほかを厳しくする前に、拒否カウンタを一週間動かしておきます。増えなくなった数が、いま壊した正当なフローです。
読み返してから、クライアントから証明する
ルールセットはスクリプトが書いたとおりではなく、カーネルが報告するとおりに読みます。まず iptables -S FORWARD、次に iptables -t nat -L POSTROUTING -n -v で NAT テーブル、そのあと調べているフローの conntrack エントリを見ます。作業が続く間は、ロールバック手順か予定されたフラッシュを用意しておきます。どの呼び出しにも -w が必要で、なければ二人の管理者が xtables のロックで衝突します。変更作業の間、これらはどれも任意ではありません。
プール内のクライアントと、その外のクライアントから試して締めます。打ち込んだマシンからしか動かないルールはポリシーではありません。