【さくらのVPS】iptablesでファイアーウォールを構築してみた
この記事の所要時間: 約 25分28秒
【さくらのVPS】初期設定をしてみたからかなり間があいてしまいましたが続きです ^^;
さて、今回はさくらのVPS上にiptablesでファイアーウォール(パケットフィルタリング)を構築します。
ファイアーウォールについてはこちら(小悪魔女子大生のサーバエンジニア日記 ファイアーウォールって何だろう?)を御覧ください。
ポリシー
ファイアーウォールは以下のポリシーで構築します。
- 受信(入力)するパケットは原則破棄
- 送信(出力)するパケットは原則通過
- フォワードするパケットは原則破棄
- 自ホスト(ループバックデバイス)からのパケットは全て許可
- 内部ネットワーク(以降、内部)からのアクセスを全て許可
- 内部から行ったアクセスに対する外部ネットワーク(以降、外部)からの返答アクセスを許可
- SYN Cookiesを有効(TCP SYN Flood攻撃対策)
- ブロードキャストアドレス宛pingへは返答しない(Smurf攻撃対策)
- ICMP Redirectパケットは拒否
- Source Routedパケットは拒否
- フラグメント化されたパケットはログを記録して破棄
- 外部とのNetBIOS関連のアクセスはログを記録せずに破棄(不要ログ記録防止のため)
- 1秒間に4回を超えるpingはログを記録して破棄
- 全ホスト(ブロードキャストアドレス、マルチキャストアドレス)宛パケットはログを記録せずに破棄
- 133番ポート(IDENT)へのアクセスには拒否応答
- 指定された国のIPアドレスからのアクセスを許可、拒否する(許可:日本 拒否:中国、韓国、台湾)
- 公開するサービスだけを許可(SSH, DNS, HTTP, HTTPS, FTP, FTP-DATA, SMTP, SMTPS, POP3, POP3S, IMAP, IMAPS等)
設定する
- 上記のポリシーをそれぞれ書いていたら大変なのでスクリプトにします。
- IPアドレスリストの更新チェックスクリプトを用意します
- rootユーザでiptablesを実行します。
- iptablesを自動起動するように設定します。
iptables.sh(UTF-8のテキストファイル)
このスクリプトを適当な場所に置きます。ボクは /root/script/ に置いてます。
#!/bin/bash #---------------------------------------# # 設定開始 # #---------------------------------------# # インタフェース名定義 LAN=eth0 #---------------------------------------# # 設定終了 # #---------------------------------------# # 内部ネットワークのネットマスク取得 LOCALNET_MASK=ifconfig $LAN|sed -e 's/^.*Mask:\([^ ]*\)$/\1/p' -e d
# 内部ネットワークアドレス取得 LOCALNET_ADDR=netstat -rn|grep $LAN|grep $LOCALNET_MASK|cut -f1 -d' '
LOCALNET=$LOCALNET_ADDR/$LOCALNET_MASK # ファイアウォール停止(すべてのルールをクリア) /etc/rc.d/init.d/iptables stop # デフォルトルール(以降のルールにマッチしなかった場合に適用するルール)設定 iptables -P INPUT DROP # 受信はすべて破棄 iptables -P OUTPUT ACCEPT # 送信はすべて許可 iptables -P FORWARD DROP # 通過はすべて破棄 # 自ホストからのアクセスをすべて許可 iptables -A INPUT -i lo -j ACCEPT # 内部からのアクセスをすべて許可 iptables -A INPUT -s $LOCALNET -j ACCEPT # 内部から行ったアクセスに対する外部からの返答アクセスを許可 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # SYN Cookiesを有効にする # ※TCP SYN Flood攻撃対策 sysctl -w net.ipv4.tcp_syncookies=1 > /dev/null sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf # ブロードキャストアドレス宛pingには応答しない # ※Smurf攻撃対策 sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 > /dev/null sed -i '/net.ipv4.icmp_echo_ignore_broadcasts/d' /etc/sysctl.conf echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf # ICMP Redirectパケットは拒否 sed -i '/net.ipv4.conf.*.accept_redirects/d' /etc/sysctl.conf for dev inls /proc/sys/net/ipv4/conf/
do sysctl -w net.ipv4.conf.$dev.accept_redirects=0 > /dev/null echo "net.ipv4.conf.$dev.accept_redirects=0" >> /etc/sysctl.conf done # Source Routedパケットは拒否 sed -i '/net.ipv4.conf.*.accept_source_route/d' /etc/sysctl.conf for dev inls /proc/sys/net/ipv4/conf/
do sysctl -w net.ipv4.conf.$dev.accept_source_route=0 > /dev/null echo "net.ipv4.conf.$dev.accept_source_route=0" >> /etc/sysctl.conf done # フラグメント化されたパケットはログを記録して破棄 iptables -A INPUT -f -j LOG --log-prefix '[IPTABLES FRAGMENT] : ' iptables -A INPUT -f -j DROP # 外部とのNetBIOS関連のアクセスはログを記録せずに破棄 # ※不要ログ記録防止 iptables -A INPUT -s ! $LOCALNET -p tcp -m multiport --dports 135,137,138,139,445 -j DROP iptables -A INPUT -s ! $LOCALNET -p udp -m multiport --dports 135,137,138,139,445 -j DROP iptables -A OUTPUT -d ! $LOCALNET -p tcp -m multiport --sports 135,137,138,139,445 -j DROP iptables -A OUTPUT -d ! $LOCALNET -p udp -m multiport --sports 135,137,138,139,445 -j DROP # 1秒間に4回を超えるpingはログを記録して破棄 # ※Ping of Death攻撃対策 iptables -N LOG_PINGDEATH iptables -A LOG_PINGDEATH -m limit --limit 1/s --limit-burst 4 -j ACCEPT iptables -A LOG_PINGDEATH -j LOG --log-prefix '[IPTABLES PINGDEATH] : ' iptables -A LOG_PINGDEATH -j DROP iptables -A INPUT -p icmp --icmp-type echo-request -j LOG_PINGDEATH # 全ホスト(ブロードキャストアドレス、マルチキャストアドレス)宛パケットはログを記録せずに破棄 # ※不要ログ記録防止 iptables -A INPUT -d 255.255.255.255 -j DROP iptables -A INPUT -d 224.0.0.1 -j DROP # 113番ポート(IDENT)へのアクセスには拒否応答 # ※メールサーバ等のレスポンス低下防止 iptables -A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset # ACCEPT_COUNTRY_MAKE関数定義 # 指定された国のIPアドレスからのアクセスを許可するユーザ定義チェイン作成 ACCEPT_COUNTRY_MAKE(){ for addr incat /tmp/cidr.txt|grep ^$1|awk '{print $2}'
do iptables -A ACCEPT_COUNTRY -s $addr -j ACCEPT done } # DROP_COUNTRY_MAKE関数定義 # 指定された国のIPアドレスからのアクセスを破棄するユーザ定義チェイン作成 DROP_COUNTRY_MAKE(){ for addr incat /tmp/cidr.txt|grep ^$1|awk '{print $2}'
do iptables -A DROP_COUNTRY -s $addr -m limit --limit 1/s -j LOG --log-prefix '[IPTABLES DENY_COUNTRY] : ' iptables -A DROP_COUNTRY -s $addr -j DROP done } # IPアドレスリスト取得 . /root/script/iptables_functions IPLISTGET # 日本からのアクセスを許可するユーザ定義チェインACCEPT_COUNTRY作成 iptables -N ACCEPT_COUNTRY ACCEPT_COUNTRY_MAKE JP # 以降,日本からのみアクセスを許可したい場合はACCEPTのかわりにACCEPT_COUNTRYを指定する # 中国・韓国・台湾※からのアクセスをログを記録して破棄 # ※全国警察施設への攻撃元上位3カ国(日本・アメリカを除く) # http://www.cyberpolice.go.jp/detect/observation.htmlより iptables -N DROP_COUNTRY DROP_COUNTRY_MAKE CN DROP_COUNTRY_MAKE KR DROP_COUNTRY_MAKE TW iptables -A INPUT -j DROP_COUNTRY #----------------------------------------------------------# # 各種サービスを公開する場合の設定(ここから) # #----------------------------------------------------------# # 外部からのTCP22番ポート(SSH)へのアクセスを日本からのみ許可 # ※SSHサーバーを公開する場合のみ iptables -A INPUT -p tcp --dport 22 -j ACCEPT_COUNTRY # 外部からのTCP/UDP53番ポート(DNS)へのアクセスを許可 # ※外部向けDNSサーバーを運用する場合のみ iptables -A INPUT -p tcp --dport 53 -j ACCEPT iptables -A INPUT -p udp --dport 53 -j ACCEPT # 外部からのTCP80番ポート(HTTP)へのアクセスを許可 # ※Webサーバーを公開する場合のみ iptables -A INPUT -p tcp --dport 80 -j ACCEPT # 外部からのTCP443番ポート(HTTPS)へのアクセスを許可 # ※Webサーバーを公開する場合のみ iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 外部からのTCP21番ポート(FTP)へのアクセスを日本からのみ許可 # ※FTPサーバーを公開する場合のみ iptables -A INPUT -p tcp --dport 21 -j ACCEPT_COUNTRY # 外部からのPASV用ポート(FTP-DATA)へのアクセスを日本からのみ許可 # ※FTPサーバーを公開する場合のみ # ※PASV用ポート60000:60030は当サイトの設定例 iptables -A INPUT -p tcp --dport 60000:60030 -j ACCEPT_COUNTRY # 外部からのTCP25番ポート(SMTP)へのアクセスを許可 # ※SMTPサーバーを公開する場合のみ #iptables -A INPUT -p tcp --dport 25 -j ACCEPT # 外部からのTCP465番ポート(SMTPS)へのアクセスを日本からのみ許可 # ※SMTPSサーバーを公開する場合のみ #iptables -A INPUT -p tcp --dport 465 -j ACCEPT_COUNTRY # 外部からのTCP110番ポート(POP3)へのアクセスを日本からのみ許可 # ※POP3サーバーを公開する場合のみ #iptables -A INPUT -p tcp --dport 110 -j ACCEPT_COUNTRY # 外部からのTCP995番ポート(POP3S)へのアクセスを日本からのみ許可 # ※POP3Sサーバーを公開する場合のみ #iptables -A INPUT -p tcp --dport 995 -j ACCEPT_COUNTRY # 外部からのTCP143番ポート(IMAP)へのアクセスを日本からのみ許可 # ※IMAPサーバーを公開する場合のみ #iptables -A INPUT -p tcp --dport 143 -j ACCEPT_COUNTRY # 外部からのTCP993番ポート(IMAPS)へのアクセスを日本からのみ許可 # ※IMAPSサーバーを公開する場合のみ #iptables -A INPUT -p tcp --dport 993 -j ACCEPT_COUNTRY # 外部からのUDP1194番ポート(OpenVPN)へのアクセスを日本からのみ許可 # ※OpenVPNサーバーを公開する場合のみ # iptables -A INPUT -p udp --dport 1194 -j ACCEPT_COUNTRY # VPNインタフェース用ファイアウォール設定 # ※OpenVPNサーバーを公開する場合のみ # [ -f /etc/openvpn/openvpn-startup ] && /etc/openvpn/openvpn-startup #----------------------------------------------------------# # 各種サービスを公開する場合の設定(ここまで) # #----------------------------------------------------------# # 拒否IPアドレスからのアクセスはログを記録せずに破棄 # ※拒否IPアドレスは/root/script/deny_ipに1行ごとに記述しておくこと # (/root/script/deny_ipがなければなにもしない) if [ -s /root/script/deny_ip ]; then for ip incat /root/script/deny_ip
do iptables -I INPUT -s $ip -j DROP done fi # 上記のルールにマッチしなかったアクセスはログを記録して破棄 iptables -A INPUT -m limit --limit 1/s -j LOG --log-prefix '[IPTABLES INPUT] : ' iptables -A INPUT -j DROP iptables -A FORWARD -m limit --limit 1/s -j LOG --log-prefix '[IPTABLES FORWARD] : ' iptables -A FORWARD -j DROP # サーバー再起動時にも上記設定が有効となるようにルールを保存 /etc/rc.d/init.d/iptables save # ファイアウォール起動 /etc/rc.d/init.d/iptables start
上のiptables.sh内で呼び出している外部関数iptables_functionsです。
iptables_functions
これも上のスクリプトと同じディレクトリに置きます。
# IPアドレスリスト取得関数定義 IPLISTGET(){ # http://nami.jp/ipv4bycc/から最新版IPアドレスリストを取得する wget -q http://nami.jp/ipv4bycc/cidr.txt.gz gunzip cidr.txt.gz # 最新版IPアドレスリストが取得できなかった場合 if [ ! -f cidr.txt ]; then if [ -f /tmp/cidr.txt ]; then # バックアップがある場合はその旨をroot宛にメール通知して処理を打ち切る echo cidr.txt was read from the backup! | mail -s $0 root exit 1 else # バックアップがない場合はその旨をroot宛にメール通知して処理を打ち切る echo cidr.txt not found!|mail -s $0 root exit 1 fi fi # 最新版IPアドレスリストを /tmpへバックアップする /bin/mv cidr.txt /tmp/cidr.txt }
IPアドレスリストは頻繁に更新されるため、毎日cronで更新有無をチェックし、更新がある場合はファイアーウォール設定スクリプトを再起動するようにします。
iplist_check.sh
このファイルはcron.dailyで実行させるので /etc/cron.daily/ に置きます。
#!/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # 新旧IPLIST差分チェック件数(0を指定するとチェックしない) # ※新旧IPLIST差分がSABUN_CHKで指定した件数を越える場合はiptables設定スクリプトを実行しない # ※新旧IPLIST差分チェック理由はhttp://centossrv.com/bbshtml/webpatio/1592.shtmlを参照 SABUN_CHK=10 [ $# -ne 0 ] && SABUN_CHK=${1} # チェック国コード COUNTRY_CODE='JP CN KR TW' # iptables設定スクリプトパス IPTABLES=/root/script/iptables.sh # iptables設定スクリプト外部関数取り込み . /root/script/iptables_functions # IPアドレスリスト最新化 rm -f IPLIST.new IPLISTGET for country in $COUNTRY_CODE do if [ -f /tmp/cidr.txt ]; then grep ^$country /tmp/cidr.txt >> IPLIST.new else grep ^$country /tmp/IPLIST >> IPLIST.new fi done [ ! -f /tmp/IPLIST ] && cp IPLIST.new /tmp/IPLIST # IPアドレスリスト更新チェック diff -q /tmp/IPLIST IPLIST.new > /dev/null 2>&1 if [ $? -ne 0 ]; then if [ ${SABUN_CHK} -ne 0 ]; then if [ $(diff /tmp/IPLIST IPLIST.new | egrep '<|>' | wc -l) -gt ${SABUN_CHK} ]; then ( diff /tmp/IPLIST IPLIST.new echo echo "$IPTABLES not executed." ) | mail -s 'IPLIST UPDATE' root rm -f IPLIST.new exit fi fi /bin/mv IPLIST.new /tmp/IPLIST $IPTABLES > /dev/null else rm -f IPLIST.new fi
$ su - パスワード: # cd script/ # sh iptables.sh ファイアウォールルールを適用中: [ OK ] チェインポリシーを ACCEPT に設定中filter [ OK ] iptables モジュールを取り外し中 [ OK ] ファイアウォールのルールを /etc/sysconfig/iptables に保存中[ OK ] ファイアウォールルールを適用中: [ OK ] チェインポリシーを ACCEPT に設定中filter [ OK ] iptables モジュールを取り外し中 [ OK ] iptables ファイアウォールルールを適用中: [ OK ]
それなりに時間がかかるので気長に待ちましょうw
# chkconfig iptables on
以上でiptablesの設定になります。
今回は、中国、韓国、台湾からアクセスを拒否するようにしましたが、拒否する必要がないと思う場合は、その箇所をコメントアウト等することでオープンになります。しかし、毎日数件変なポートにアクセスが来ますので注意が必要です。
その前に、さくら内部からくるアレをどうにかしてくれw
今日の午前4時のログより
################### Logwatch 7.3 (03/24/06) #################### Processing Initiated: Tue Apr 12 03:59:03 2011 Date Range Processed: yesterday ( 2011-Apr-11 ) Period is day. Detail Level of Output: 0 Type of Output: unformatted Logfiles for Host: vps.iex3.info ################################################################## (中略) --------------------- pam_unix Begin ------------------------ sshd: Authentication Failures: unknown (www19177u.sakura.ne.jp): 1983 Time(s) root (www19177u.sakura.ne.jp): 33 Time(s) mail (www19177u.sakura.ne.jp): 21 Time(s) ftp (www19177u.sakura.ne.jp): 4 Time(s) operator (www19177u.sakura.ne.jp): 3 Time(s) adm (www19177u.sakura.ne.jp): 2 Time(s) mailnull (www19177u.sakura.ne.jp): 2 Time(s) bin (www19177u.sakura.ne.jp): 1 Time(s) daemon (www19177u.sakura.ne.jp): 1 Time(s) games (www19177u.sakura.ne.jp): 1 Time(s) gopher (www19177u.sakura.ne.jp): 1 Time(s) halt (www19177u.sakura.ne.jp): 1 Time(s) lp (www19177u.sakura.ne.jp): 1 Time(s) news (www19177u.sakura.ne.jp): 1 Time(s) nfsnobody (www19177u.sakura.ne.jp): 1 Time(s) nobody (www19177u.sakura.ne.jp): 1 Time(s) rpc (www19177u.sakura.ne.jp): 1 Time(s) rpcuser (www19177u.sakura.ne.jp): 1 Time(s) shutdown (www19177u.sakura.ne.jp): 1 Time(s) smmsp (www19177u.sakura.ne.jp): 1 Time(s) sshd (www19177u.sakura.ne.jp): 1 Time(s) sync (www19177u.sakura.ne.jp): 1 Time(s) uucp (www19177u.sakura.ne.jp): 1 Time(s) xfs (www19177u.sakura.ne.jp): 1 Time(s) Invalid Users: Unknown Account: 1985 Time(s) (中略) ---------------------- pam_unix End ------------------------- (中略) ###################### Logwatch End #########################