Linux/Ubuntuでファイアウォールを実現するための iptables の設定に関する覚え書きです。
Contents
iptables とは
iptables は Linux に実装されているパケットフィルタリング機能でこの iptables によって不要なパケットを拒否することでファイアウォールを実現します。
環境
Desktop (Ubuntu 16.04)
Raspberry Pi (Raspbian)
初期設定
iptables の Lオプションで iptables に設定されている規則の一覧が確認できます。
初期設定では何も設定されていません。
# ルールの確認 $ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
設定
1つずつコマンドとして実行して設定していくこともできますが、見やすさを優先してシェルスクリプトにまとめて記述します。
基本方針として受信するパケットを全て拒否し、後ろに個別で受信するパケットの規則を設定します。
ここではWebサーバ用のHTTP(80)とリモートログイン用のSSH、リモートデスクトップのvncを通すようにしています。
vncに関しては許可するIPアドレスを制限しています。
その他の通信を許可したい場合はHTTPなどと同じような書式でポートを指定して設定することができます。
$ vim ~/Documents/iptables.sh #! /bin/sh # 設定をクリア iptables -F # 基本方針[1] # サーバーが受信するパケットを拒否 iptables -P INPUT DROP # サーバーが経由させるパケットを拒否 iptables -P FORWARD DROP # サーバーが送信するパケットを許可 iptables -P OUTPUT ACCEPT # サーバ攻撃対策関連 # データを持たないパケットの接続を破棄 iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP # SYNflood攻撃と追われる接続を破棄 iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP # ステルススキャンと思われる接続を破棄 iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP # 許可するパケットを個別に追加 # SSHを許可 (OpenSSHでポート変更済み 22 => xxxx)[2] iptables -A INPUT -p tcp -m tcp --dport xxxx -j ACCEPT # HTTPを許可 iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT # HTTPS(SSL)を許可 iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT # PINGを許可 iptables -A INPUT -p icmp -j ACCEPT # vnc (ポート変更済み=yyyy) iptables -A INPUT -p tcp -m tcp --dport yyyy -s 192.168.3.3 -j ACCEPT # その他 # ローカルループバックの接続を許可 iptables -A INPUT -i lo -j ACCEPT # 確率済みの通信を許可 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # ログを出力 iptables -A INPUT -j LOG --log-prefix "drop_packet:"
このスクリプトファイルを実行すればファイアウォールの設定が反映されます。
iptables -L で確認するとスクリプトファイルで記述した設定が確認できます。
# スクリプトの実行 $ sudo sh ~/Documents/iptables.sh # ルールの確認 (xxx=ssh, yyy=vnc) $ sudo iptables -L Chain INPUT (policy DROP) target prot opt source destination DROP tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,PSH,ACK,URG/NONE DROP tcp -- anywhere anywhere tcp flags:!FIN,SYN,RST,ACK/SYN state NEW DROP tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,PSH,ACK,URG/FIN,SYN,RST,PSH,ACK,URG ACCEPT tcp -- anywhere anywhere tcp dpt:xxx ACCEPT tcp -- anywhere anywhere tcp dpt:http ACCEPT tcp -- anywhere anywhere tcp dpt:https ACCEPT icmp -- anywhere anywhere ACCEPT tcp -- 192.168.3.3 anywhere tcp dpt:yyy ACCEPT all -- anywhere anywhere ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED LOG all -- anywhere anywhere LOG level warning prefix "drop_packet:" Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
設定の自動読み込み
直打ちしたやスクリプトで指定した iptables の設定が有効なのはシャットダウンするまでの間でマシンを再起動すると設定は全て消えてしまいます。
毎回起動後にスクリプトファイルを手動で実行するのは大変なので、マシン起動時に自動で iptables の設定を読み込むように準備します。
設定のエクスポート
上で作成したスクリプトファイルを実行しルールの設定を行って、 iptables-save で現在の設定を書き出します。
sudo でリダイレクトをすると Permission denied のエラーメッセージが表示されるので sudo sh -c を使ってリダイレクトしています。
# フィルタリングルールの設定 $ sudo sh ~./iptables.sh # 現在のルールの書き出し $ sudo sh -c "iptables-save -c > /etc/iptables.rules"
起動時に設定を読み込むスクリプト
書きだした設定ファイル /etc/iptables.rules を読み込むシェルスクリプトを作成します。
このスクリプトファイルを /etc/network/if-pre-up.d/ 下に保存しておくとマシン起動時に自動でスクリプトを処理して iptables の設定を反映してくれます。
# マシン起動時に iptables の設定を読み込むスクリプトを作成 $ sudo vim /etc/network/if-pre-up.d/iptables_start #!/bin/sh /sbin/iptables-restore < /etc/iptables.rules exit 0 # 実行権限付与 $ sudo chmod +x /etc/iptables.rules
確認
設定が完了したらマシンを再起動して iptables のルールが適用されているか確認します。
# 再起動 $ sudo reboot # iptables の確認 $ sudo iptables -L
iptables -L の出力を確認して、実際に設定したとおりに通信が許可・拒否されているか確認します。
終わりに
iptables-save と iptables-restore を使って設定を読み込むようにしましたが、はじめに設定用のスクリプトファイルを自前で作成しているのでそのファイルを /etc/network/if-pre-up.d/ に配置するのでもいいと思います。
参考
知らなきゃ損するiptablesのTips:iptablesテンプレート集 改訂版(8) – @IT