[前に戻る: authpf: 認証ゲートウェイ用 ユーザシェル] [目次]
[ COMP1 ] [ COMP3 ] | | ADSL ---+------+-----+------- fxp0 [ OpenBSD ] ep0 -------- ( インターネット ) | [ COMP2 ]
内部ネットワークには多数のコンピュータが接続されています。上図では 3 台になっていますが、これは実際の台数とは無関係です。これらのコンピュータは、 web サーフィン、電子メール、チャットなどの用途で使用されるワークステーションです。 内部ネットワークは 192.168.0.0 を使用しており、ネットワークブロックは 255.255.255.0 となっています。
この OpenBSD ルータは 2 枚のネットワークカード 3Com 3c509B (ep0) ならびに Intel EtherExpress Pro/100 (fxp0) を持つ Pentium 100 のマシンです。この ルータはインターネットへの ADSL 接続を持っており、この接続を内部ネットワークで 共有するために NAT を使用しています。外部インターフェイスの IP アドレスは、 インターネットサービスプロバイダ (ISP) から動的に割り当てられています。
int_if = "fxp0"
ext_if = "ep0"
tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"
priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"
最初の 2 行は、実際にフィルタリングが行われるネットワークインターフェイスを 定義しています。3 行目と 4 行目とは、インターネットに対して開かれた TCP ポート番号 (SSH と ident/auth) および、ファイアウォールに届くことが許される ICMP のパケットタイプを定義しています。 最後の行はループバックと RFC 1918 のプライベートアドレスのブロックを定義しています。
注: もし、ADSL によるインターネット接続が PPPoE を必要とする場合、フィルタリングや NAT は ep0 に対してでは なく、tun0 インターフェイスに対して定義する必要があります。
set block-policy return
set loginterface $ext_if
scrub in all
nat on $ext_if from $int_if:network to any -> ($ext_if)
外部インターフェイスの IP アドレスは動的に割り当てられますので、 アドレスが変化した場合に PF がこれに注意を払うことができるよう、 変換するインターフェイスに対して括弧を付与しておきます。
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
このルールは、ポート 21 番への FTP 接続だけを捕えることができます。もし、 ユーザが FTP サーバの他のポートに対して、いつも接続しているのでしたら、 たとえば from any to any port { 21, 2121 } のように、 リストは送信先ポートを指定するために使用されるべきです。
block all
この時点では、内部ネットワークからのものも含めて、ファイアウォールを 通過するパケットは何もありません。以下のルールによって、上記の目的ごとに ファイアウォールを開いていき、同様に、すべての必要な仮想インターフェイス も開いていきます。
どの Unix システムも、「ループバック」インターフェイスを持ちます。これは、システム内の アプリケーションが互いに他と通信するのに使用される仮想的なネットワークインターフェイスです。 一般的に、すべてのトラフィックは、このループバックインターフェイスにわたされるべきです。 OpenBSD では、ループバックインターフェイスは lo(4) です。
pass quick on lo0 all
次に、 RFC 1918 のプライベートアドレスは、公のインターネットに出現してはいけないので、 外部インターフェイスに入って来たり、出て行ったりするのをブロックします。 これらをフィルタリングすることは、ルータがこれらのアドレスが内部ネットワークから 「漏れて」出て行かないことと、同じくこれらのネットワークのひとつを 送信元アドレスとする着信パケットをブロックすることを確実にします。
block drop in quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets
block drop は、TCP RST や ICMP Unreachable パケットに応答する必要がないことを PF に指示するために使用されるということに注意してください。RFC 1918 のプライベートアドレスは インターネットに存在しないので、これらのアドレスに送信先されるパケットはすべて、何があろうと 何もしてはいけません。また、quick オプションは、そこから上のルールにパケットが マッチした場合に、PF に残りのフィルタルールを評価する手間をかける必要がないことを指示するために 使用されます。$priv_nets ネットワークへの、あるいは、そこからのパケットは、 直ちに廃棄されます。
ここで、インターネットに対して公開しているネットワークサービスが使用する ポートを開きます。
pass in on $ext_if inet proto tcp from any to ($ext_if) \
port $tcp_services flags S/SA keep state
$tcp_services マクロの中にネットワークポートを指定することにより、 単にマクロを編集し、ルールセットを再ロードすることで、インターネットに対して 付加的なサービスを開くことが簡単にできるようになります。同様に、UDP のサービスも $udp_services マクロを生成し、上記のように、proto udp を指定したフィルタルールを追加しておくことで、開くことができるようになります。
この時点で、ICMP のトラフィックは以下のように通過させておくべきでしょう。
pass in inet proto icmp all icmp-type $icmp_types keep state
$tcp_services マクロと同じように、$icmp_types マクロも、 ファイアウォールに到達することができる ICMP パケットのタイプの変更するため、 簡単に編集することができます。このルールはすべてのネットワークインターフェイスに 適用されるということに注意してください。
この時点で、内部ネットワークからのトラフィックは通過できるようにすべきです。ここで、 私たちは、内部ネットワークのユーザは、自分たちが何をしようとしているのかを知っていて、 トラブルを引き起こすつもりなどはないものと仮定しましょう。 これは必ずしも正当な仮定ではなく、いくつかの環境では、より限定的なルールセットが 適切であるかも知れません。
pass in on $int_if from $int_if:network to any keep state
上記のルールは、すべての内部のマシンに、ファイアウォールを通過するパケットの送信を 許可していますが、ファイアウォールから内部のマシンに対して接続しようとすることは 許可していません。しかし、本当にこれで良いのでしょうか ? もちろん、その答は ネットワーク構成のより詳細な部分に依存することです。たとえば、ファイアウォールが DHCP サーバを兼ねている場合には、IP の割り当て前にクライアントが生きているかどうかを確認するのに "ping" を行う必要があるかも知れません。ファイアウォールが内部ネットワークに接続するのを 許可することはまた、インターネットからファイアウォールに SSH で接続してきた誰かに 内部ネットワークへのアクセスを許可することでもあります。 ファイアウォールが直接内部ネットワークに通信を行うことを許可しないことが セキュリティ上の大きな利点になるわけではないということに留意しておいてください。 もし、誰かがファイアウォールへのアクセスを手に入れたとすると、どのみちフィルタルールも たいていは変更されてしまうかも知れないからです。以下のフィルタルールを追加することによって、 ファイアウォールから内部ネットワークに接続しようとすることができるようになります。
pass out on $int_if from any to $int_if:network keep state
もし、これらの両方の行が記述されている場合には、keep state オプションは 不要であることに注意してください。つまり、双方向にパケットを通過させるための ルールが記述されているのですから、すべてのパケットは内部インターフェイスを 通過することができるわけです。しかし、pass out の行が含まれていない場合には、 pass in の行には keep state オプションが含まれている必要があります。 また、この状態の保持 (keep state) には、いくつかの性能上の利点もあります。 たとえば、状態テーブルはルールの評価前にチェックされ、 状態のマッチがあった場合には、パケットはルールセットの評価を受けることなく ファイアウォールを通過します。これによって、負荷の重いファイアウォールに対して 性能上の利点を提供することができますが、この単純なことによって、 システム内部で非常に大きな負荷を発生してしまうようなことは考えにくいでしょう。
最終的に、外部インターフェイスから出て行くトラフィックを通過させます。
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
これで TCP、UDP および ICMP のトラフィックはファイアウォールからインターネットに向かって 出て行くことができます。また、応答パケットがファイアウォールを通過して内部ネットワークに 入れるよう、状態情報が保持されます。
# macros int_if = "fxp0" ext_if = "ep0" tcp_services = "{ 22, 113 }" icmp_types = "echoreq" priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }" # options set block-policy return set loginterface $ext_if # scrub scrub in all # nat/rdr nat on $ext_if from $int_if:network to any -> ($ext_if) rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 \ port 8021 # filter rules block all pass quick on lo0 all block drop in quick on $ext_if from $priv_nets to any block drop out quick on $ext_if from any to $priv_nets pass in on $ext_if inet proto tcp from any to ($ext_if) \ port $tcp_services flags S/SA keep state pass in inet proto icmp all icmp-type $icmp_types keep state pass in on $int_if from $int_if:network to any keep state pass out on $int_if from any to $int_if:network keep state pass out on $ext_if proto tcp all modulate state flags S/SA pass out on $ext_if proto { udp, icmp } all keep state |
[前に戻る: authpf: 認証ゲートウェイ用 ユーザシェル] [目次]