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対応もやります



S3

  • Static website hostingは無効でOK
  • 特別な設定は不要ですがバージョニングを有効にしています


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


cloudfront-1.png


  • Object CachingをCustomize

    • 今回の要件ではキャッシュが不要だったのでTTLを0にします
  • CloudFront EventをViewer Request
  • Lambda Function ARNを先程作成したバージョン番号付きのARNを設定


cloudfront-2.png


  • ついでに403もキャッシュしないように設定します
    cloudfront-3.png



おわりに

  • ここまでやればBasic認証付きの静的サイトホスティング環境ができると思います
  • この記事では一旦ここまでで終了ですが発展として以下2つを更に考えていきたいと思います

    • AWS Transfer for SFTPやAWS Storage GatewayでSMBを使えるようにして昔ながらのファイル転送方法を用意する
    • 認証情報がLambdaハードコードになっているのでもう少し管理をちゃんとやる

      • 1つでいいならLambdaの環境変数が良さそうですが複数CloudFrontから1つのLambda@Edgeでフックしたく、CloudFrontごとに異なる認証情報を持てるようにしたい

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)