2011/03/20 CentOS5.5





プロキシーサーバを構築する(解説)

Linuxのプロキシーサーバーと言えばSquidです。
ですがこのSquid、長らく大きな進化をしていません。
Webサーバやメールサーバとは違い比較的早い段階でソフトウェアとして完成の域に達したこと、インターネットの高速化によりキャッシュサーバの有用性が低くなったこと、セキュリティ的に攻撃される理由が少ないこと、です。

システム連携複雑化、セキュリティ強化の昨今プロキシーサーバは組織において重要な位置を占めます。
特にコンテンツフィルタ、ウィルスフィルターとしてプロキシー導入が必須になる組織ではプロキシールーティングを必要とする場面が増え、プロキシールーティングの柔軟性のためSquidを導入する必要に迫られます。

しかし組織内で乱立させるタイプのサーバでもはないため、他システムに比べると情報源が少ない(古い)事が悩みです。


Squidの運用形態別
 1.単純なプロキシーとして動作させる
 2.多段プロキシーを組む
 3.宛先により別のプロキシーへルーティングする
 4.二つ以上のプロキシールーティングをする(直接取得)
 5.二つ以上のプロキシールーティングをする(多段プロキシ)

 ACLの書き方
  ・ACLの注意点
  ・似ているが異なる動作のポリシー
  ・ACLの記述順序
1.単純なプロキシーとして動作させる
クライアントが独自にインターネットアクセスするのを制限したいときに使用します。
もちろんファイアーウォール等で外部へアクセスできるIPを制限しなくては意味がありません。

見づらいですがウェブのアクセスログを収集することができます。
アクセス制限もかけられるので、なにもないよりはだいぶましです。

2.多段プロキシーを組む
プロキシー導入で一番最初に浮かぶ疑問が「多段プロキシー」です。
多少組織が大きくなると必要になってきます。



3.宛先により別のプロキシーへルーティングする
組織が大きくなってくると、社内システムや連携会社など特定のドメイン宛の接続はインターネットではなく別のプロキシーへ任せる仕組みが必要になってきます。

例えば通常のインターネット接続はプロキシーを使って出ていくが、会社間の共同体によるシステムを使う場合は別のプロキシーへ任せる、といった運用です。


4.二つ以上のプロキシルーティングをする(直接取得)
宛先により別のプロキシーへルーティングするのと変わりませんが、想定したように動かないことがあります。
ちょっとしたテクニックが必要です。



5.二つ以上のプロキシルーティングをする(多段プロキシ)
宛先により別のプロキシーへルーティングするのと変わりませんが、想定したように動かないことがあります。
ちょっとしたテクニックが必要です。この場合も少しコンフィグがトリッキーになります。

例えば通常のインターネット接続はプロキシーを使って出ていくが、会社間の共同体によるシステムを使う場合は別のプロキシーへ任せる、といった運用です。

ACLの書き方
acl aclname src 192.168.1.0/255.255.255.0
ACL宣言、ACL名の定義、ACLタイプ、範囲

ACLはタイプ・範囲を「宣言」してから後で利用する、という手順をとります。
acl aclname src 192.168.1.0/255.255.255.0
http_access deny aclname

ACLのタイプはたくさんあり、柔軟に設定できます。
src 送信元アドレス
dst 送信先アドレス
dstdomain 送信先ドメイン
port 接続先ポート

コンフィグが複雑化しないように気を付けましょう。

ACLの注意点
Squidのコンフィグには各種ACLの設定が重要になってきます。
しかし昨今のセキュリティ重視のポリシー慣れている、SquidのACLは驚愕と憤りを感じる仕組みとなっております。
というより設計思想が異なっており、ルータやファイアウォールのACLのような「禁止を少しずつ許可していく」という考えに慣れている人にとっては思い込みによる設定ミスが多発します。

例えば「あるプロキシーサーバAは、インターネット接続には上位プロキシーBを使用し、社内システムへは直接アクセスする」というポリシーがあるとします。
それはこのように記述します。

cache_peer proxysrvB  parent 8080 0 no-query
ACL companyDomain dstdomain .example.co.jp
always_direct allow companyDomain

一見問題がないように見えます。事実、クライアントのブラウジングは期待した通りに画面に表示されます。
しかし見かけにすぎません。

tailコマンドによって子プロキシーA親プロキシーBのアクセスログの推移を見ればわかることですが、社内システム以外の通常のインターネット接続も、親プロキシーを使用せず直接インターネットを閲覧してたりします。
とりあえず親プロキシがダウンした場合でも、直接取得でインターネット閲覧が可能です。

この動作が都合良いかは別として、ちょっとわかりにくいです。

このACLの解釈は「インターネット閲覧に親プロキシーAを使っても良い」「example.co.jp宛のアクセスは直接アクセスしても良い」と記述されているだけです。
つまり「インターネット接続は必ず上位プロキシーを使わなくてはいけない」とは書いてないからです。
Squidは上位プロキシーがダウンした場合、あるいはアクセスが遅い場合のことも考え、自分でも積極的にアクセスに行きます。
自分で取りに行ったほうが早いことを学習するとそれ以降は上位プロキシーに頼らず、自分で取りに行くことを覚えます。
そして大抵ウェブアクセスは上位プロキシーを経由せず、自分でアクセスしたほうが速いことが多いです。
結果、最初は上位プロキシーを使っていたのに、しばらくすると直接アクセスばかりしている、という事態になります。

このようにSquidのACLは「いかにウェブとの接続性を保つか」という仕様になっています。
経路のプロキシーがダウンしても次善の方法として、ACLで明示的に禁止されていないこと(別のプロキシーは利用可能か? 自分自身で取得可能か?)を次々模索して抜け穴を発見しようとします。
「遮断」を主眼にしているファイアウォールやルータとは違った思想となっています。

従って、ルータのように厳密にプロキシールーティングを制御したい場合は、一つずつ明示的に許可と拒否を記述することが重要です。

似ているが異なる動作をするポリシー
明記が重要、という意味では以下のような記述も注意が必要です。

acl LAN1 src 192.168.1.0/255.255.255.0
acl LAN2 src 192.168.2.0/255.255.255.0

Aパターン
http_access allow LAN1

Bパターン
http_access allow LAN1
http_access deny LAN2

一見同様のACLに見えますが、動作がまったく異なります。
AパターンではLAN1が許可されます。それ以外のセグメントのクライアントは禁止されます。
BパターンではLAN2が禁止されます。それ以外のセグメントのクライアントは許可されます。

Aパターンのようにallowで終わっていると、その後は暗黙のdenyとなります。
Bパターンのようにdenyで終わっていると、その後は暗黙のallowとなります。
これは暗黙の「allow/deny」は、最後に指定した「allow/deny」の反対となるというSquidのルールによるものです。
ルータなどのACLに慣れている人にとってはハマりです。

これらは意図しない事故につながるため、通常は

Aパターン
http_access allow LAN1
http_access deny all

Bパターン
http_access allow LAN1
http_access deny LAN2
http_access deny all

と最後に、明確な拒否を記述しておけば思い違いによる事故は防げます。
一見同じようなようにACLを増やしてセキュリティを強化したつもりが、逆効果となるため注意が必要です。

似たパターンでは以下のものもあります。

Aパターン
acl proxy-clients src 192.168.1.0/255.255.255.0
http_access allow proxy-clients

Bパターン
acl proxy-clients src 192.168.1.0/255.255.255.0
http_access deny !proxy-clients

ABともに似ていますが、やはり動作は異なります。

Aパターンの場合、192.168.1.10のクライアントからアクセスがあった場合、「192.168.1.0はallow」と明示されていますので、その時点で許可とみなされ、以降のACL判断は受けません。
指定された範囲外の192.168.2.10からアクセスであれば、許可はされず次以降のACL判断に流れます。
もしACLがなにもなければ、allowの範囲外なのでdenyとみなされます。

Bパターンの場合、192.168.2.10のクライアントからアクセスがあった場合、「192.168.1.0以外はdeny」と明示されていますので、192.168.2.10は即座に拒否されます。
指定された範囲の192.168.1.10からアクセスがあった場合でも、拒否はされませんが次以降のACL判断に流れます。
もしACLがなにもなければ、denyの範囲外なのでallowとみなされます。
ただし、デフォルトで最終位置に「http_access deny all」が記述してあるので拒否扱いとなります。

ACLの記述順序
あまり突飛なところに書くと視認性が悪く、ACLでトラブルを招くおそれがあります。
似たような記述が集まっているところへ記述しましょう。
各セクションに記述するのが正攻法ですが、ミスのない設計とするため一旦は一か所に見やすく書くことも重要です。

なお順番が重要です。
設定情報は必ず使用する場所よりも前で宣言します。
たとえば

cache_peer ProxyA.example.local
cache_peer_access ProxyA.example.local parent 8080 0 no-query

このように使用するProxyA.example.localが先に宣言されていなければ、cache_peer_accessが使用できません。
ACLの場合も同様です。ACLの宣言は、使用する場合より先に宣言しなくてはいけません。

エラーになる例
http_access deny YAHOO
ACL YAHOO dstdomain .yahoo.co.jp

他にも、エラーにはならないが意味として違ってしまうACLもあります。
以下の構文ではSUBEXMAPLEは直接取得、EXAPLEはプロキシー接続を意図しているつもりが誤っている例です。

ACL SUBEXAMPLE dstdomain .sub.example.local
ACL EXAMPLE dstdomain .example.local
cache_peer_access ProxyA.example.local allow EXAMPLE (.example.local)
always_direct allow SUBEXAMPLE (.sub.example.local)

この場合、www.sub.example.localは「.example.local」と条件が一致してしまうため、プロキシを使用します。
正しくは限られた範囲である、SUBEXAMPLEを先に設定します。

ACL SUBEXAMPLE dstdomain .sub.example.local
ACL EXAMPLE dstdomain .example.local
always_direct allow SUBEXAMPLE (.sub.example.local)
cache_peer_access ProxyA.example.local allow EXAMPLE (.example.local)

これで正しく動作します。





prev.gif