Linuxでファイヤーウォール設定

このエントリは2007/11/28の再掲です

Linuxでhosts.allow/hosts.denyファイルでIPアドレス/ポートベースのアクセス制御が有効なのは、

  • inetdを使ったサービスアプリケーション
  • ssh等のhosts.allow/hosta.denyを独自に使うアプリケーション

しかありません。なので、その他のサービスについて、ポートをブロックしたり、許可IPアドレスを制限したりするには、iptablesでIPフィルタリングすることになります。Linuxカーネル2.4以降で、IPフィルタリングはすべて、iptablesで包括的に管理できるようになったそうです。

iptables自体の詳細については、既存の文書を:

http://www.asahi-net.or.jp/~aa4t-nngk/iptables.html

http://iptables-tutorial.frozentux.net/iptables-tutorial.html
http://www.asahi-net.or.jp/~aa4t-nngk/ipttut/output/index.html

以下、RedHat系(FedoraCore/CentOS)でiptablesを使ったプライベートなファイヤーウォール(適用範囲が自クライアントのみ)を設定する方法を説明します。

iptablesサービスが稼動していると、コマンドを実行するたびに、IPフィルタが書き換わります。

service iptables save

とすることで、iptablesサービスのリスタート時(つまりリブート時)に、現在のフィルタ状態を再現することができるようになります。この状態は /etc/sysconfig/iptablesファイルに保存されているので、どうにもならなくなったときは、このファイルを削除して、

service iptables restart

しましょう。また、随時コマンド実行していると、sshもtelnetもできなくなる瞬間ができてしまうので、リモート管理したい場合はかならず、シェルスクリプトに禁止操作と許可操作をまとめて書き、一括実行するようにしましょう。

具体的にどう設定すればよいのかについては、じっさいのところ、「iptables自体が高度すぎるために、記述方法を一般化できない」ようです。なので、一例を書きます。

#! /bin/sh

TRUST_IP='xxx.xxx.xxx.xxx'

iptables -F
iptables -X

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

#loopback
iptables -A INPUT -i lo -j ACCEPT

#pass established
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

#ICMP
iptables -A INPUT -p icmp --icmp-type any -j ACCEPT

#client functions
iptables -A INPUT -p udp --sport 53 -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --sport 25 -j ACCEPT
iptables -A INPUT -p tcp --sport 80 -j ACCEPT
iptables -A INPUT -p tcp --sport 443 -j ACCEPT

#services
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
#iptables -A INPUT -p tcp --dport 80 -j ACCEPT
#iptables -A INPUT -p tcp --dport 443 -j ACCEPT
#iptables -A INPUT -p tcp --dport 21 -j ACCEPT

#for testing phase
iptables -A INPUT -p tcp -s $TRUST_IP --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -s $TRUST_IP --dport 443 -j ACCEPT
iptables -A INPUT -p tcp -s $TRUST_IP --dport 8080 -j ACCEPT

これで、

  • フォワーディング全面的に禁止
  • 自分が自分にアクセスするのは全面的に許可
  • 自分へのアクセスが継続接続であれば無条件に許可(新規のみフィルタ)
  • 自分のbindがDNSとしてちゃんと機能する
  • 自分は他サーバの25,80,443ポート以外へアクセスできない
  • ポート22(ssh)へのアクセスを許可する
  • ポート80,443,8080へのアクセスは、TRUST_IPにしか許可していない

となります。TRUST_IP='xxx.xxx.xxx.xxx'は任意のIPアドレスに設定してください。 sshへのアクセスを限定していないのは、sshがhosts.allow/hosts.denyでIPアドレスベースのアクセス制限を行うことができるためです。

@ITにも同様のサンプルがあるものの、ちょっとやりすぎていて、記述性も可読性も悪く、意味の把握がおろそかになってしまうので、逆に危険な気がします。参考程度にどうぞ。

http://www.atmarkit.co.jp/flinux/index/indexfiles/iptablesindex.html

おまけ:

OS インストール直後、*nixのC標準ライブラリにあるgethostname()は、"localhost.localdomain"を返します。 bindで「外から見た名前」をアサインしても、自分自身の内部で「自分のドメイン名」を取得するときは、DNSをあてにしないのが普通です。デフォルト値として「自分の名前」をサポートするアプリケーションは、gethostname()など、DNSと無関係なAPIを使うのです。

  • /etc/hosts
  • /etc/sysconfig/network

の両方に、自分の名前を書いておきましょう。

/etc/hosts

127.0.0.1 myhost.mydomain localhost.localdomain localhost

/etc/sysconfig/network

HOSTNAME="myhost.mydomain"