目的
LambdaでCloudFrontの署名付きURLを生成し、S3オブジェクトのキャッシングを実装。
S3とCloudFrontの直接参照は不可とする。
参考記事
【AWS】CloudFrontで署名付きURLの設定方法(プライベートコンテンツの配信)
S3
- 新規でバケットを作成し、ファイルをアップロード
- アクセス許可:パブリックアクセスを全てブロック
- 静的ウェブサイトホスティング:無効
CloudFront
- 新規ディストリビューションを作成
- オリジンドメイン:作成したS3バケット
- S3バケットアクセス:
- OAIを使用(新規で作成)
- バケットポリシー:自動更新
キーペアを生成後、「ビューアーのアクセスを制限する」を変更
キーペアの作成
今回はOpenSSLで生成
openssl genrsa -out private_key.pem 2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
public_keyをAWSにアップロード
- CloudFrontの左メニューから「パブリックキー」を選択
- 新規で作成し、名前と内容を入力
- メニューから「キーグループ」を選択
- 新規で作成し、名前と、上記で作成したパブリックキーを選択し紐付ける
CloudFront Behavior
- 作成したCloudFrontディストリビューションを選択し編集
- 「ビヘイビア」メニューから作成済みのものを選択
- 「ビューアーのアクセスを制限する」を設定
- アクセスを制限する:YES
- 信頼された認可タイプ:Trusted key groups(recommended)
- キーグループを追加:作成したキーグループを選択
署名付きURLの発行【Lambda】
今回はNode.jsを使用
以下の手順でファイルを作成し、モジュールをzip形式でまとめる
mkdir modules
cd modules
npm i async
npm i aws-cloudfront-sign
- modulesディレクトリに「キーペアの作成」で作成したプライベートキーと、以下のファイルを設置
index.js
exports.handler = async(event) => {
const cloudFrontSign = require('aws-cloudfront-sign')
const expire = new Date();
expire.setTime(currentDate.getTime() + 24*60*60*1000);
const signedUrl = cloudFrontSign.getSignedUrl(
'CloudFrontのオリジンURL',
{
keypairId: 'キーペアID'
privateKeyPath: '.private_key.pem',
},
expire
);
return {JSON.stringify(signedUrl)}
}
- zip化
zip -r modules index.js private_key.pem node_modules/
- 新規でLambda関数を作成
- 「コード」メニューの「アップロード元」から、作成したzipファイルをアップロード後、デプロイ
APIゲートウェイ
- 新規でAPIゲートウェイを作成し、メソッドを定義
- 作成したLambda関数をAPIゲートウェイと紐付ける
動作確認
GETメソッドであればブラウザのURLから直接パスを入力して呼び出してもよし、そうでなければPostman等を使用するもよし。
返却されたURLを叩いてS3オブジェクトが参照できれば完了。
あとがき
- 使用しているモジュールのaws-cloudfront-signが暫くサポートされていないため、aws-sdkのAWS.CloudFront.Signerを使用するべき
- Lambdaに秘密鍵を設置するのはセキュリティ的に好ましくないため、パラメータストアやシークレットマネージャーを使用するべき(aws-sdkのSignerであれば、秘密鍵の情報をファイル指定ではなく文字列で渡せる)