技術メモなど

ほぼ自分用の技術メモです。

Squidの多段プロキシ構成で特定ドメインまたはURLで上位プロキシを振り分ける設定

Squidで多段プロキシ構成で複数の上位プロキシが存在している時に、特定のドメインの場合は指定した上位プロキシ経由でアクセスするようにする設定です。また、アクセス方法がHTTPSでなく平文のHTTPである場合のみ、特定のURLで振り分けることも可能です。

クラウドの業務システム向け通信はAプロキシ、それ以外のインターネット向け通信は全てBプロキシ、といったことが実現できます。

検証はSquidのバージョン3.5で行っています。

概要

/etc/squid/squid.confに次の通り記載。

  • cache_peerに上位プロキシを定義。この時デフォルトのプロキシは必ず他の上位プロキシを定義する行より下に記載しないとならない。
  • aclに振り分けたい特定ドメインを定義。
  • cache_peer_accessに振り分けたい特定ドメインを定義したaclと経由したい上位プロキシを定義したcache_peerを紐付け。
  • never_direct allow allを記載すると、aclに当てはまらない通信は全てデフォルトの上位プロキシを経由するようになる。

設定例

構成

多段プロキシ構成は以下の通りとします。上位プロキシには振り分けに関する設定は不要で、全て下位プロキシ側に設定することになります。

プロキシサーバ ホストと待受けポート
Aプロキシ(特定ドメインまたはURLの場合経由させたい上位プロキシ) system-proxy.example.com:3128
Bプロキシ(それ以外の場合経由させたいデフォルトの上位プロキシ) internet-proxy.example.com:3128
Cプロキシ(クライアント側に設定しているプロキシ〔下位プロキシ〕) client-proxy.example.com:8080

下位プロキシ側(Cプロキシ)の設定

コンフィグ例

/etc/squid/squid.confに以下の通り追記(または変更)します。

# 上位プロキシの定義
# Aプロキシ(特定ドメインまたはURLの場合経由させたい上位プロキシ)
cache_peer system-proxy.example.com parent 3128 0 no-query
# Bプロキシ(それ以外の場合経由させたいデフォルトの上位プロキシ)
# デフォルトのプロキシは必ず他の上位プロキシより下の行に書くこと!
cache_peer internet-proxy.example.com parent 3128 0 default no-query

# 振り分けたい特定ドメイン・URLの定義
# 振分け対象ドメイン
acl system-domain dstdomain "/etc/squid/system-domain.acl"
# 振り分け対象URL(ただしHTTPSだとURLで振り分けることはできないのでドメインで振り分けるしかない)
acl system-url url_regex "/etc/squid/system-url.acl"

# 振分け対象特定ドメイン・URLとAプロキシの紐付け
cache_peer_access system-proxy.example.com allow system-domain
cache_peer_access system-proxy.example.com allow system-url

# 振分け対象特定ドメイン・URL以外は全てBプロキシ経由にする
never_direct allow all

解説

上位プロキシの設定

ここで重要なのが、デフォルトの上位プロキシを指定する記載は必ず他の上位プロキシを指定する行より後にする必要があることです。defaultというキーワードを指定していてもなぜか関係ありません。他の上位プロキシの記載が後にあるとそちらがデフォルトになってしまい、意図した通りになりません。

cache_peer system-proxy.example.com parent 3128 0 no-query
cache_peer internet-proxy.example.com parent 3128 0 default no-query # こちらがデフォルトの上位プロキシ

Squidのドキュメントを読んでも、複数のdefaultを指定した上位プロキシがある場合は最初のものが使われる、との記述があるも、実際にコンフィグに投入しても意図した通りにはなりませんでした。また、cache_peer自体の順序についても記述はありません。ですが実際には一番最後に指定したcache_peerがデフォルトになってしまうので、cache_peerの記述順序は要注意です。

==== PEER SELECTION METHODS ====

The default peer selection method is ICP, with the first responding peer being used as source. These options can be used for better load balancing.

default This is a parent cache which can be used as a "last-resort" if a peer cannot be located by any of the peer-selection methods. If specified more than once, only the first is used.

http://www.squid-cache.org/Versions/v3/3.5/cfgman/cache_peer.html

振分け対象ドメインの指定

振り分けたい特定ドメインをここではsystem-domainという名前(名前は任意で大丈夫)のaclに定義しています。

acl system-domain dstdomain "/etc/squid/system-domain.acl"

dstdomainの後に対象ドメインをベタ書きしてもいいのですが、メンテしやすいよう/etc/squid/system-domain.aclというテキストファイルを作成し、対象ドメインを列記するようにします。

/etc/squid/system-domain.aclの内容は次の通りです。振り分けたい特定ドメインがsystem01.example.comというドメインと、system02.example.comサブドメインという想定です。

system01.example.com
.system02.example.com

振分け対象URLの指定

同様に、振り分けたい特定URLをsystem-urlという名前のaclに定義しています。/etc/squid/system-url.aclというテキストファイルを作成し、対象URLを列記するようにします。

acl system-url url_regex "/etc/squid/system-url.acl"

ポイントは、aclのurl_regex対象URLを正規表現で記載できることです。dstdomainの方は正規表現は使えないので注意です。

ただし、HTTPSの場合はURLでの振分けは使えません。後で検証の際にSquidaccess.logを見れば分かるのですが、HTTPSの場合、クライアントと通信先サーバとの間で暗号化されているので参照先URLがSquidからは見えないためだと思われます。(SquidHTTPSを終端するようなman in the middle的設定ができるなら可能なのかも。)

そのため、HTTPSの場合はURLでの振分けは諦めて、ドメインで振り分けるしかなさそうです。

/etc/squid/system-url.aclの内容は次の通りです。振り分けたい特定URLがhttp://system03.example.com/maintener/以下という想定です。

^http://system03\.example\.com/maintener/.*$

ちなみにHTTPS(標準ポート)でドメインの振分けで正規表現が使いたい場合は、dstdomainでは正規表現が使えないためurl_regexを使って次のような書き方ができると思います。

# HTTPSで正規表現を使ったドメイン振り分け例(dstdomainではできないことに注意)
^branch[0-9]+\.system03\.example\.com:443$
# HTTPもある場合を想定した書き方
^(http://)*branch[0-9]+\.system03\.example\.com(:443)*(/.*)*$

指定以外の通信は全てデフォルトの上位プロキシに向ける設定

最後に以下の記述がないと下位プロキシが上位プロキシを経由せず直接通信してしまいます。

never_direct allow all

設定の反映

コンフィグに誤りがないことが確認できたら、Cプロキシのsquidサービスをリロード(または再起動)します。

# systemctl reload squid

振分けができているか確認

期待した通りに振分け設定ができていれば、Cプロキシのaccess.logには次のようなログが出力されます。

651285320.368 1663 198.51.100.123 TCP_TUNNEL/200 3878 CONNECT system01.example.com:443 - FIRSTUP_PARENT/192.0.2.1 -

上位プロキシ側は次のようなログが出力されます。

651285320.370  1441 192.0.2.1 TCP_TUNNEL/200 3139 CONNECT system01.example.com:443 - HIER_DIRECT/203.0.113.200 -