S3 + CloudFront + Lambda@EdgeでBasic認証付き静的サイトホスティング(インデックスドキュメントサポートあり)
S3 + CloudFront + Lambda@EdgeでBasic認証付き静的サイトホスティング(インデックスドキュメントサポートあり):
はじめに
- 静的サイトをホスティングしているレガシーなVPS上のWebサーバがあり時折発生する運用作業でつらみが発生していました
- クラウド上に構築してなるべく運用作業を0に近づけたいと思いAWSのS3をベースに再構築しようと思いました
- 少しググって簡単に出来そうだなと思ったもののよく見つかる方法では要件を微妙に満たせなく苦戦してしまったのでQiitaに書いときます
- サブディレクトリでindex.htmlを省略した場合に403となってしまいました
- インデックスドキュメントがルートでしか効きません
- 要件としてはBasic認証ありでサブディレクトリでもindex.html省略可能でホスティングしたい感じです
- 認証なしで良いのであればS3のStatic website hostingを有効にするだけで大丈夫なはずです
構成
- S3 + CloudFront + Lambda@Edgeで作ります
- S3は静的ファイル置き場
- CloudFront経由で公開
- Lambda@EdgeでCloudFrontで認証処理+αな処理の差し込み
- ここでサブディレクトリのindex.html対応もやります
-
クラメソさんの記事を大いに参考にしています - この記事を見つけるまで苦戦していました
-
- ここでサブディレクトリのindex.html対応もやります
S3
- Static website hostingは無効でOK
- 特別な設定は不要ですがバージョニングを有効にしています
Lambda
- 現時点ではLambda@Edgeがus-east-1(米国東部 バージニア北部)でないといけないのでus-east-1でLambdaを作ります
- Lambda@Edgeのポリシーテンプレートを使った新しいロールを作ります
-
Lambdaのコードは以下
index.js
'use strict'; exports.handler = (event, context, callback) => { // Get request and request headers const request = event.Records[0].cf.request; const headers = request.headers; // Configure authentication const authUser = 'user'; const authPass = 'pass'; // Construct the Basic Auth string const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64'); // Require Basic authentication if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) { const body = 'Unauthorized'; const response = { status: '401', statusDescription: 'Unauthorized', body: body, headers: { 'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}] }, }; callback(null, response); } // Extract the URI from the request var olduri = request.uri; // Match any '/' that occurs at the end of a URI. Replace it with a default index var newuri = olduri.replace(/\/$/, '\/index.html'); // Replace the received URI with the URI that includes the index page request.uri = newuri; // Continue request processing if authentication passed callback(null, request); };
- よく見つかる方法ではサブディレクトリでindex.htmlを省略したURLを表示できません
- ここがハマりポイントでした
- CloudFrontでDefault Root Objectにindex.htmlを設定してもRootでしか有効になりません
- なのでLambda@EdgeでURIを書き換える方法を採用しました
- S3のStatic website hostingを有効にしてCloudFrontからのアクセスのみを通すこともできると思いますがIPが変わるたびに対応が必要になると思うのでLambdaで書き換えるほうがお手軽とだと思います
- authUserとauthPassは任意のものに変えてください
- Lambda@Edgeにはバージョンの発行が必要になります
- CloudFrontにバージョン番号付きのARNを設定します
CloudFront
- Original Domain Nameに公開したいバケットのあるS3を選択
- Restrict Bucket AccessをYes
- Origin Access IdentityをCreate a New Identity
- Grant Read Permissions on BucketをYes, Update Bucket Policy
- Object CachingをCustomize
- 今回の要件ではキャッシュが不要だったのでTTLを0にします
- CloudFront EventをViewer Request
- Lambda Function ARNを先程作成したバージョン番号付きのARNを設定
おわりに
- ここまでやればBasic認証付きの静的サイトホスティング環境ができると思います
- この記事では一旦ここまでで終了ですが発展として以下2つを更に考えていきたいと思います
- AWS Transfer for SFTPやAWS Storage GatewayでSMBを使えるようにして昔ながらのファイル転送方法を用意する
- 認証情報がLambdaハードコードになっているのでもう少し管理をちゃんとやる
- 1つでいいならLambdaの環境変数が良さそうですが複数CloudFrontから1つのLambda@Edgeでフックしたく、CloudFrontごとに異なる認証情報を持てるようにしたい
コメント
コメントを投稿