iptables

iptablesで正しくポートマッピング

More than 3 years have passed since last update.


iptablesでポートマッピング

ConoHaを使い始めました.ConoHaは,インスタンスの前段に仮想ルータがないので,iptablesなどでセキュリティを確保する必要があります.iptablesは,設定に抜けが出てしまいそうで,結構苦手です.

さて,ConoHaに限らず,クラウド上のインスタンスは,不正な接続をなされないように,適切にファイアウォールを設定する必要があります.特にSSHなどは,意図しない接続を排除するよう,注意深く設定する必要があります.私は,22番ポートを2222番ポート1にポートマッピングして,SSH接続をできるようにしています.完全に手抜きなので,よくないですね.

ConoHaでポートマッピングを行うためには,iptablesのNAT機能を使用することが,最も確実な方法だと思います2.本記事では,同一ホスト内で,2222ポートに着信した通信を,22番ポートで待ち受けているsshdにリダイレクトすることを考えます.80番ポートへ届いたパケットをiptablesでローカルの上位ポートに転送するを参照すると,natテーブル上にREDIRECTターゲットへジャンプするルールを作成すれば,所望のポートマッピングを実現できます.しかし,このルールのみだと,22番ポートへの直接アクセスを許してしまします.

iptablesでポートマッピングを行いながら,マッピング先への直接アクセスを禁止する方法は,実はあまり知られていないようです.iptables redirect 80 to 8080 but block public 8080 accessiptables: how to allow traffic from redirected portでは,マッピング先へのアクセスを禁止する方法がいくつか提示されていますが,mangleテーブルを利用したり,存在しないサービスにマップしたりと,まあ,その,やりたくない方法を使っています.なので,ここに,納得できる設定法を示します.


設定例

マッピング先への直接アクセスを禁止し,リダイレクトされたアクセスの場合は許可するルールは,次のようなコマンドで作成することができます.

iptables -t nat -A PREROUTING -p tcp --dport 2222 -j REDIRECT --to-ports 22

iptables -A INPUT -p tcp --dport 22 -m conntrack --ctorigdstport 2222 -j ACCEPT

1行目は,ポートマッピングの設定です.この設定により,2222番ポートに着信したパケットは,宛先ポート番号のみ22番に書き換えられます.ポート番号が書き換えられた後,パケットフィルタリングが行われますが,宛先ポート番号しか書き換えられないため,通常の記法だと直接22番ポートに着信したパケットと区別がつきません.2行目は,ポート番号が2222番から22番に書き換えられたパケットを許可するルールです.ポート番号が書き換えられたパケットに限定するために,conntrackモジュールのctorigdstportオプションを使用しています.iptablesのドキュメントによると,ctorigdstportは,書き換え前のポート番号を指定するオプションです.次に,iptablesによる処理の流れを示します.

iptables_portmapping.png


まとめ

ctorigdstportは,ぐぐってもまともな資料がでできませんが,ポートフォワーディングするときには非常に有用なオプションです.


失敗設定

次の設定だと,22番でも2222番でも接続できません.

iptables -t nat -A PREROUTING -p tcp --dport 2222 -j REDIRECT --to-ports 22

iptables -A INPUT -p tcp --dport 2222 -j ACCEPT

次の設定だと,22番でも2222番でも接続できてしまいます.

iptables -t nat -A PREROUTING -p tcp --dport 2222 -j REDIRECT --to-ports 22

iptables -A INPUT -p tcp --dport 22 -j ACCEPT





  1. この番号はフィクションです.実際,2222番ポートは,Vagrantなどの有名なツールで,22番ポートの代替として使用されています.したがって,22番の大体ポートとして広く認知されているので,2222番ポートを使用しても,隠していることになりません. 



  2. ssh localhost -L 22:localhost:2222とかやだなあ...inetdを使う方法もあるらしいけど...