IPアドレス制限をAWS CloudFrontとNginxの組み合わせでやってみる

リリース直前など、本番環境でテストを行いたいが、一般公開できないということはよくあると思います。
Basic認証だったり、IPアドレスでの制限だったり、方法は色々とあるかと思いますが、個人的によくやるのはIPアドレスでの制限です。IPアドレス制限を行う方法も色々とあります。ApacheやNginxだけで行うこともできますし、AWSだとWAF+CloudFrontという選択肢もあります。今回はなぜかCloudFront+Nginxという、謎の組み合わせを試してみました。

今回のざっくり要件

  1. 対象となるドメインはすでに運用中
  2. CDNとしてCloudFrontを利用している
  3. このドメイン配下にアクセス制限をかけたコンテンツを追加したい(※制限は一時的なもの)

すでに運用しているドメインということと、一時的という理由から、WAFではなくCloudFrontの内側で処理することにしました。

NginxでIP制限

ものすごく簡単な方法は、allow, deny を使った制限だと思います。ほとんどのディレクティブで記載できますし、何よりシンプルですね。以下、公式ドキュメントのサンプルです。

ただ、今回のような一時的な制限だけでなく、恒常的に制限をしたいものが混在する場合も往々にしてあります。その場合、個別にlocationディレクティブへ同じ内容(社内用VPNのIPなど)をコピペしまくるのはさすがに気持ち悪いですよね。そこで、もう少し柔軟かつコンパクトに記述できる制限方法が geo(http_geo_module)になります。

こちらも公式ドキュメントのサンプルだと、以下のようになります。

この場合、アクセスしてきたIPアドレスが 127.0.0.1 の場合 $geo2 がセットされます。その後は、以下のように振り分けを行うことになります。

CloudFrontではまった

オリジンサーバのNginxの設定を終え、CloudFront経由でアクセスしたところ、どこからアクセスしても全て403…。よく引っかかるところですが、リモートIPがCloudFrontのIPにすり替わってしまい、想定した動作にならないというミスです。チェックすべきは、X-Forwarded-Forと言う場合、geoを以下のように記述します。

X-Forwarded-For がカンマ区切りできた場合どういう動作するんだろう…。その辺は、様子を見ながら必要であればrealip_moduleを使ってなんとかすれば良いかな。といったところで今回は終了です。

あと、X-Forwarded-Forをオリジンサーバで受け取るには、CloudFrontで Forward Headers を All にするか、whitelistにX-Forwarded-Forを追加しましょう。