ENGINEERING ARTICLE
OACで非公開S3を使う静的サイト!CloudFront Functionでindex.htmlへ変換
この記事は約4分で読めます
こんにちは、 @Manabu です。
S3で静的サイトを公開する場合、静的Webサイトホスティング機能を使い、インデックスドキュメントにindex.htmlを設定する方法が一般的です。
ただし、S3の静的WebサイトエンドポイントではOACを使用できません。S3を非公開にし、CloudFrontからだけアクセスを許可したい場合は、通常のS3バケットオリジンとOACを使う必要があります。
この構成では、トップページは表示できても、/article/へアクセスした時に/article/index.htmlが自動的に返らず、AccessDeniedや404になる場合があります。
今回は、OACで非公開S3へアクセスする静的サイトを対象に、CloudFront FunctionでURLをindex.htmlへ変換する方法を紹介します。
この記事は、以下のような方におすすめです。
こんな方におすすめ
- OACを使ってS3を非公開にしたい
- CloudFrontからだけS3へのアクセスを許可したい
- 末尾に
/が付いたURLで記事を表示したい - S3オリジンでAccessDeniedや404が発生している
なぜURLの書き換えが必要なのか
S3には、静的Webサイトエンドポイントと通常のバケットエンドポイントがあります。
| 構成 | ディレクトリのindex.html | OAC |
|---|---|---|
| S3静的Webサイトエンドポイント | インデックスドキュメントを設定できる | 使用できない |
| S3バケットオリジン | ディレクトリごとの補完はされない | 使用できる |
S3静的WebサイトエンドポイントをCloudFrontのオリジンにする場合は、カスタムオリジンとして扱われます。そのため、S3バケットを公開しておく必要があります。
一方、通常のS3バケットオリジンでOACを使うと、S3のパブリックアクセスを禁止したままCloudFrontからファイルを取得できます。
CloudFrontのDefault root objectにindex.htmlを設定しても、対象になるのは基本的にルートURLです。/article/のようなサブディレクトリまでは、自動的にindex.htmlへ変換されません。
そのため、CloudFront Functionを使って、S3へ転送する前にリクエストURIを書き換えます。
実装する処理
次のようにURIを書き換えます。
/ → /index.html
/aws/example/ → /aws/example/index.html
/aws/example → /aws/example/index.html
/assets/style.css → 変更しない
/api/contact → 変更しない
CloudFront Function
function handler(event) {
var request = event.request;
var uri = request.uri;
// 同じCloudFrontからAPIも配信する場合は、APIのパスを書き換えない
if (uri === '/api' || uri.startsWith('/api/')) {
return request;
}
if (uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!uri.split('/').pop().includes('.')) {
request.uri += '/index.html';
}
return request;
}
拡張子があるパスはCSSや画像などの静的ファイルと判断し、そのままS3へ転送します。
API Gatewayなどを同じCloudFrontから配信していない場合は、/api/を除外する処理は不要です。
CloudFrontへ関連付ける
作成した関数は発行したうえで、対象ビヘイビアのViewer requestへ関連付けます。
API Gateway用の/api/*ビヘイビアにも同じ関数を使う場合、APIのパスを必ず書き換え対象から外します。除外しないと、/api/contact/index.htmlとしてAPI Gatewayへ転送され、404になる可能性があります。
まとめ
今回は、OACで非公開S3を使用する静的サイトで、CloudFront Functionを使ってディレクトリ形式のURLをindex.htmlへ変換する方法について紹介しました。
S3の静的Webサイトホスティングを使う場合は、インデックスドキュメントを設定できるため、同じ対応が必要になるとは限りません。
S3を非公開にしてCloudFrontからだけアクセスさせたい場合に、通常のS3バケットオリジン、OAC、CloudFront Functionを組み合わせるのがポイントです。
CloudFrontとS3で記事ページが表示されない場合は、リクエストURIがS3上のファイルパスと合っているか確認してみてください。
参考資料
REFERENCEAmazon S3 オリジンへのアクセスを制限する - Amazon CloudFrontdocs.aws.amazon.com↗
REFERENCEデフォルトのルートオブジェクトを指定する - Amazon CloudFrontdocs.aws.amazon.com↗