経緯
- EC2上にSquidを導入してフォワードプロキシサーバとして運用しているのですが、可用性向上/運用負担軽減を目的にAppRunner上でSquidのDockerイメージが動作可能か試してみました。
結論
- AppRuuner上でフォワードプロキシは動作不可。(Fargateでは動作可)
リバースプロキシとフォワードプロキシの違い
-
リバースプロキシとフォワードプロキシはhttp(s)通信を中継する点では役割同じですが、リバースプロキシをフォワードプロキシとして使ってしまうと、
-
外部送信を避けたい組織内の情報(X-Forwarded-forに個別端末のIPアドレスが付与される等)が転送される。
-
送信先のURLとリバースプロキシのURLが分離されない。
-
というとわかりやすくなるかもしれません。
送信先URLの指定方法のイメージ(yahooにアクセスする場合を想定)
# フォワードプロキシの場合(プロキシサーバのURLと送信先URLは分離されている)
curl https://www.yahoo.co.jp -x forward-proxy-url:3128
# リバースプロキシの場合(プロキシサーバのURLと送信先URLは分離されていない)
# 構築方法でURL(含むクエリストリング)の組み方は変えられる
curl https://reverse-proxy-url?dest_url=www.yahoo.co.jp
curl https://reverse-proxy-url/www.yahoo.co.jp
- 比較表を作ると以下のような感じですが、双方http(s)通信を中継する役割は同じなので少しわかりにくいかもしれず、上記解説にて補足したものです。
特徴 | リバースプロキシ | フォワードプロキシ |
---|---|---|
役割 | クライアントからのリクエストを受け取り、適切なサーバーに転送する。 | クライアントの代理として外部のリソースにアクセスする。 |
主な目的 | 負荷分散、キャッシング、セキュリティ | インターネットアクセスの制御、匿名化、キャッシング |
主な用途 | - ウェブサーバーの負荷分散 - SSL終端 - キャッシング |
- 社内ネットワークのインターネットアクセス制御 - 匿名ブラウジング - コンテンツフィルタリング |
設置場所 | サーバーの前面 | クライアントの前面 |
接続の方向 | インバウンドトラフィック(クライアント→サーバー) | アウトバウンドトラフィック(クライアント→インターネット) |
IPアドレス | クライアントにはリバースプロキシのIPアドレスが見える | 外部サイトにはフォワードプロキシのIPアドレスが見える |
セキュリティ機能 | Webアプリケーションファイアウォール(WAF)、DoS攻撃の緩和 | フィルタリング、アクセス制御、匿名化 |
クライアントからサーバに送信するデータの取り扱い | 極力サーバに転送しようとする | 必要最小限にとどめる |
有名なソフトウェア | Squid | Apache、Nginx |
ざっくり手順
- squidのコンテナイメージを作成するDockerfile
Dockerfile-squid
# 使用するベースイメージ
FROM ubuntu/squid:latest
# デフォルトのSquid設定ファイルをバックアップ
RUN mv /etc/squid/squid.conf /etc/squid/squid.conf.original
# Squid設定を直接書き込み
RUN echo "\
# Allow local machine to access\n\
http_access allow localhost\n\
\n\
# IPアドレスによるアクセス制限の設定\n\
acl allowed_ips src xxx.xxx.xxx.xxx \n\
http_access allow allowed_ips\n\
\n\
# Squid の設定\n\
acl Safe_ports port 1-65535 # all ports\n\
acl SSL_ports port 443\n\
acl CONNECT method CONNECT\n\
\n\
http_access allow Safe_ports\n\
http_access allow CONNECT SSL_ports\n\
http_access deny all\n\
\n\
# デフォルトのポート\n\
http_port 3128\n\
\n\
# キャッシュを無効にする設定\n\
cache deny all\n\
cache_mem 0 MB\n\
maximum_object_size_in_memory 0 KB\n\
cache_dir null /tmp\n\
\n\
# ログファイルの場所\n\
access_log /var/log/squid/access.log\n\
cache_log /var/log/squid/cache.log\n\
\n\
# その他のオプション\n\
coredump_dir /var/spool/squid" > /etc/squid/squid.conf
# 必要なログファイルとキャッシュディレクトリの作成
RUN mkdir -p /var/spool/squid \
&& chown -R proxy:proxy /var/spool/squid \
&& mkdir -p /var/log/squid \
&& chown -R proxy:proxy /var/log/squid \
&& squid -z
# Squidサーバーを起動
CMD ["squid", "-N", "-d", "1"]
squidのDockerイメージをECRにプッシュ( your-account-id を適宜変更)
# Dockerfile-squidを使ってSquidのDockerイメージをビルドし、イメージ名をhogehoge-squidにタグ付けする
docker build -f Dockerfile-squid -t hogehoge-squid .
# AWS ECRにログインするためのパスワードを取得し、Dockerにログインする
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <your-account-id>.dkr.ecr.ap-northeast-1.amazonaws.com
# hogehoge-squidイメージに最新タグを付け、AWS ECRリポジトリのsquid:latestとしてタグ付けする
docker tag hogehoge-squid:latest your-id.dkr.ecr.ap-northeast-1.amazonaws.com/squid:latest
# 最新タグが付いたSquidイメージをAWS ECRリポジトリにプッシュする
docker push <your-account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/squid:latest
- AWSマネジメントコンソールからAppRunnerを選択して、プッシュしたイメージを元にサービスを起動。(実際の手順は公式に委ねますが、体感して簡単に設定可能でした。)
検証結果
- 上記コンテナをAppRunnerにデプロイすると標準出力にログ出力されることになるが、端末からデプロイしたサービス経由で接続してもタイムアウトになり、サービス上のログもヘルスチェック用のログしか記録されない。
通信シーケンスまで確認できていないですが、フォワードプロキシの場合、通信開始する際にHTTPのCONNECTメソッド(送信元がプロキシサーバーに送信先とTCP接続を確立するよう要求する役割)を使うのですが、AppRunnerの目的からして当然ではありますがAppRunnerはこのメソッドをサポートしていないからだと思われます。
07-15-2024 12:15:45 AM 1720970144.822 0 169.254.175.249 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- -
07-15-2024 12:15:55 AM 1720970154.823 0 169.254.175.249 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- -
07-15-2024 12:16:05 AM 1720970164.823 0 169.254.175.249 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- -
- AppRunner上にデプロイしても、以下のようなSquidのエラーページは表示されました。(以下は検証時と全く同じものではないです)
補足
-
AWS上でフォワードプロキシを構築する際は、踏み台にならないように必ず送信元制限はかけましょう。(AWSの規約違反になります)
-
上記は厳密に検証/整理したわけではありませんので、その点割り引いてお読みください。