Tech Sketch Bucket of Technical Chips by TIS Inc.

nginxでS3へリバースプロキシ

Pocket

一般的に利用されるブラウザではJavaScriptによるクロスドメイン制約などセキュリティのための読み込みドメインの制約があります。
そのためクラウド上のファイルなどを利用するときに上記の制約を受けて何らかの対策が必要になる場合があります。
この対策の一つとしてリバースプロキシによって対応する方法があります。


リバースプロキシを立ててすべてを解決するんだ

リバースプロキシで解決を試みると言うのは以下の図のような構成にすることです。

reverse.png

このようにリバースプロキシを使うことでユーザのブラウザから見るとすべてのデータが同じドメインからのデータ取得になります。
このような構成にするために次に具体的な設定をしてみます。

リバースプロキシを立てよう

リバースプロキシを立てるにはApache、Squidなどの有名なWebサーバやProxyサーバを利用したり、最近ではnode.jsでスクリプトを書いてリバースプロキシを作成したりなどあるようですが、今回はnginxを用いることとします。

ゴール

以下の絵のようになるようにします。
goal.png
このとき以下の状態です。

  • nginxはport80でListen
  • ApplicationServerはport8000でListen(pythonのSimpleHTTPServer)
  • AWS S3はport443でListen(80でもListenしてます)
  • nginxへのアクセスをurlで振り分ける

nginxのインストールと起動

毎度のようにAmazon Linuxを使います。
以下のようにnginxをインストールします。

sudo yum update
sudo yum install nginx
sudo service nginx start

AWSのセキュリティグループが正しく設定されていれば
ブラウザにEC2のホスト名を入れるだけで以下の画面が出ます。

nginx_started.png

アプリケーションサーバとS3を準備

アプリケーションサーバとS3を準備していきます。

アプリケーションサーバ(SimpleHTTPServer)を準備

8000番ポートでpythonのSimpleHTTPServerを動かします。
その前に単純なindex.htmlファイルを配置します。

S3にファイルを配置

以下のように"testimage.png"を"tech-sketch"バケットに配置します。

s3_data.png

この後、ファイルに対する権限をPublicにすることで以下のURLからファイルが取得できるようになります。S3のバケット名をディレクトリ名にするか、S3のバケット名をサブドメインにするかどちらでもアクセス可能なようです。

https://tech-sketch.s3-ap-northeast-1.amazonaws.com/testimage.png
https://s3-ap-northeast-1.amazonaws.com/tech-sketch/testimage.png

※上記は例なのでファイルは実際には配置しておりません。

/etc/nginx/nginx.confを設定

nginxの設定を変更するために/etc/nginx/nginx.confを以下のように修正します。

上記設定後、nginx再起動

sudo service nginx restart

設定完了

これだけで一応リバースプロキシができます。
今回EC2に割り当てられたドメインでページを開いてみたりしました。

index.png

ここで80番ポートにアクセスしていますが、8000番ポートで待ち受けてるSimpleHTTPServerからindex.htmlが取得できています。
またリンク先は./s3/testimage.pngになっているので開いてみます。

image.png

S3に配置した画像がindex.htmlと同じドメインで開かれています。
無事リバースプロキシが出来ていることが確認できました。

この設定のままだと問題もある

実運用をする場合はプロキシ先のログなどのためにnginx.confに対して、X-Forwarded-ForをHTTPヘッダに追加する記述をしたり、プロキシ利用のログの取得をする記述が必要でしょう。
また、プロキシサーバが単一障害点になるのでそのあたりも意識しておく必要があります。

S3に置いたデータがPublicなのはダメじゃないの?

S3においたら何処からでも見られるからセキュリティ的に困る、リバースプロキシにだけS3のデータ見せられないの?と思ったのでやってみます。

S3はアクセスコントロールの機能があるのでそれを使ってみます。

S3のバケットポリシーによるアクセス制限

設定例のドキュメントがあるのでざっくり目を通してみます

(Example Cases for Amazon S3 Bucket Policies)

IPアドレスやリファラなどによるアクセス制限が可能なようですが手っ取り早くプロキシサーバのIPアドレスでやって見ます。

Amazon S3 の設定画面を開くと以下のような画面がでます。
S3_policy.PNG
画像内で赤く囲んだ部分のリンクをクリックして開くダイアログ内で以下のような設定をしました。

設定内容は以下の内容。

IPアドレス1.2.3.4はリバースプロキシの外部IPアドレスに置き換えてください。

この設定の後、バケット内のファイルtestimage.pngについてEveryoneのレコードを削除しAuthenticatedUserが追加されていることを確認します。

これでリバースプロキシを通したアクセス以外は遮断され、遮断された場合はAccessDeniedが表示されます。

リバースプロキシ以外の他の手段は?

取得元ドメインを同じにすればいいわけなので他にも手段はあると思われます。
AWS Cloud Frontは解のひとつになるはずです。

おわり

と、いうわけで今回は

  • EC2上にnginxでリバースプロキシを配置
  • S3上のデータをリバースプロキシ越しでアクセスすることでデータを同一ドメインから取得
  • S3に置いたファイルへのIPアドレスによるアクセス制限

といった内容を行いました。

同一ドメインからS3のデータを取得することでS3に格納した画像をCanvasに読み込んで自由に出力できたり、JavaScriptのクロスドメイン制約を受けずに済みます。

参考

(Example Cases for Amazon S3 Bucket Policies)

http://ja.wikipedia.org/wiki/X-Forwarded-For

エンジニア採用中!私たちと一緒に働いてみませんか?