Amazon S3をWebサーバとして利用できる、静的ウェブサイトホスティングの機能を利用してみました。
また、今回はCloudFrontを経由させることで、ELBとS3へそれぞれリクエストを振り分ける、ということも合わせて試しました。
(CloudFrontのキャッシュ機能の話については今回の対象外となります。今回はリクエストの振り分け用途として利用しています)
イメージとしては以下のようになります。
-
http://example.com/
CloudFront => ELB => EC2 -
http://example.com/test/
CloudFront => S3
また、S3へのファイルアップロードは、EC2から行う想定です。
ELB
事前に作成して設定しておきます。
作成方法は公式ドキュメント (http://docs.aws.amazon.com/ja_jp/ElasticLoadBalancing/latest/DeveloperGuide/elb-getting-started.html) を参照してください。
また、CloudFront経由でのアクセスになるため、セキュリティグループでInboundへの任意の場所からのHTTP 80番ポートを許可しておきます。
EC2
事前にEC2を作成しておき、Apache httpdをインストールした後、コンテンツを配置します。
作成方法については割愛します。
今回はデフォルトのテストページをそのまま利用します。
また、このコンテンツをインターネットに公開したくない場合、ELB=>EC2の場合はセキュリティグループでIPアドレス制限を設定することが多いと思いますが、CloudFrontは今日時点ではアクセス制限を掛けることが出来ません。
そのため、EC2のWebサーバ側でアクセス制限を設定します。(S3へのアクセスはこの方法だと制限出来ませんが)
以下はApache httpd2.4での最低限の設定例になります。CloudFront, ELBを経由するため、X-Forwarded-Forにリクエスト元のIPアドレスが入ります。
(詳細は要件に合わせて設定します。)
RemoteIPHeader X-Forwarded-For
<Location />
Require all denied
Require ip IPアドレス/32
</Location>
S3
バケットの作成
公式ドキュメント (http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/UG/CreatingaBucket.html) などを参照し、バケットを作成しておきます。
バケットポリシーの追加
ポリシージェネレーターを利用して、バケットポリシーを作成します。
(http://awspolicygen.s3.amazonaws.com/policygen.html)
- 例
{
"Id": "Policyxxxxxxxxxxxxx",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmtxxxxxxxxxxxxx",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::バケット名/*",
"Principal": "*"
}
]
}
静的ウェブサイトホスティングの設定
S3の静的ウェブサイトホスティングの設定を行います。
- インデックスドキュメント:必須設定となります。設定したいファイルがある場合は、設定したいファイル名を指定します。今回は特定のパスかつ特定のファイル名の場合のみS3から返すことを想定し、実在しないファイル名を指定しました。
- エラードキュメント:必要に応じて設定します。
- リダイレクト:必要に応じて設定します。今回は、インデックスドキュメントのindex.htmlは存在しないため、404になってしまった場合はELBにリダイレクトする、という形を試しました。
- リダイレクトルール例
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<HostName>ELB名.ap-northeast-1.elb.amazonaws.com</HostName>
<ReplaceKeyWith></ReplaceKeyWith>
</Redirect>
</RoutingRule>
</RoutingRules>
CloudFront
Distributionの設定
公式ドキュメント等を参照し、Distibutionの設定を行います。
設定後は以下のようになります。
Originの設定
Originの設定を行います。ELBとS3の2つ分を設定します。
設定後は以下のようになります。
S3向けの設定の注意点として、S3に設定したリダイレクト設定を効かせたい場合、Origin Domain Nameにはドロップダウンリストに表示されるS3バケット名ではなく、S3のEndpoint名を直接指定します。
(そうしないとリダイレクトが効かなかった)
Behaviorの設定
Behaviorの設定にて、振り分けるパスの設定を行います。
今回は、/test/* の場合はS3、それ以外はELBへ振り分けを行うようにしています。
IAM設定
EC2からS3にファイルをアップロード出来るようにするため、EC2に割り当てているIAMロールにS3へのポリシーをアタッチします。
AWS Management Consoleから行う場合、IAM - ポリシーの作成 - Policy Generator と進み、必要なアクションを指定してポリシーを作成します。
ここで必要分だけアクションを指定するのですが、とりあえずs3:DeleteObject、s3:GetObject、s3:PutObject、s3:RestoreObjectあたりを設定してEC2からAWS CLIにてlsを試したところ、エラーとなりました。
$ aws s3 ls s3://バケット名/
A client error (AccessDenied) occurred when calling the ListObjects operation: Access Denied
DEBUGしてみたところ、確かに403になっています。ListObjectという文言もありますが、S3のアクションではListObjectというのはありません。
$ aws s3 ls s3://バケット名 --debug
(snip)
MainThread - botocore.vendored.requests.packages.urllib3.connectionpool - INFO - Starting new HTTPS connection (1): バケット名.s3-ap-northeast-1.amazonaws.com
MainThread - botocore.vendored.requests.packages.urllib3.connectionpool - DEBUG - "GET /?prefix=&delimiter=%2F HTTP/1.1" 403 None
MainThread - botocore.hooks - DEBUG - Event after-call.s3.ListObjects: calling handler <function enhance_error_msg at 0x7fe82cb3e488>
(スタックトレース等が続く)
色々試行錯誤の結果、以下のようになりました。
その後、AWS CLIにてlsやrmが実行可能なことを確認しました。
細かい要件が決まっていない場合は、S3FullAccessとかでも良いかもしれません。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmtxxxxxxxxxxxxx",
"Effect": "Allow",
"Action": [
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetLifecycleConfiguration",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:GetObjectTorrent",
"s3:GetObjectVersion",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTorrent",
"s3:ListAllMyBuckets",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListBucketVersions",
"s3:ListMultipartUploadParts",
"s3:PutLifecycleConfiguration",
"s3:PutObject",
"s3:PutObjectAcl",
"s3:PutObjectVersionAcl",
"s3:RestoreObject"
],
"Resource": [
"arn:aws:s3:::バケット名",
"arn:aws:s3:::バケット名/*"
]
}
]
}
最終的には以下にファイルを配置しました。
$ aws s3 ls s3://バケット名/test/
2015-12-19 14:34:06 0
2015-12-19 14:34:34 8 test.html
Distributionを有効化
全て設定が終わったら、CloudFrontのDistributionを有効化します。
StateがEnabledに変化しています。
ブラウザからアクセス
それでは、この状態で、CloudFront経由でアクセスしてみます。
パスごとに振り分け出来ていることが確認出来ました。
→EC2上のコンテンツが表示される
→自分でS3に配置したコンテンツが表示される