Lambda@Edge を AWS CLI でデプロイする
はじめに
CloudFront + Cognito + Lambda@Edge (cognito-at-edge) でサイトに認証をかけたいのですが、複数ハマったポイントがありました。
Cognito の話は別途、記事を書く予定ですが、今回は Lambda@Edge を AWS CLI でデプロイする方法について書きます。
Lambda@Edge って何
一言で言えば、ユーザーに近いロケーションで実行できる Lambda です。
詳しくは 公式ドキュメント を参照ください。
とにもかくにもデプロイ
実行したいコードができたら、とにもかくにもデプロイして動作確認したいですよね。
ググっても、マネジメントコンソールからデプロイする方法や、Serverless framework を使う方法は出てくるのですが、 AWS CLI でデプロイする方法はなかなか出てきません。
以下、試行錯誤した結果、確立した方法を紹介します。
デプロイ手順
ざっくり言うと、以下の3ステップが必要です。
Lambda 関数のデプロイ
新しい Lambda 関数の バージョン発行
CloudFront の更新
Lambda 関数のデプロイ
AWS SAM でテンプレートを書く場合、以下のようになります。
# template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
LambdaEdgePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: Policy for Lambda@Edge Function
Path: /
ManagedPolicyName: !Sub "${AWS::StackName}-iam-policy-lambda-edge"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- iam:CreateServiceLinkedRole
Resource: "*"
- Effect: Allow
Action:
- lambda:GetFunction
- lambda:EnableReplication
Resource:
- !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:${AWS::StackName}-*:*"
- Effect: Allow
Action:
- cloudfront:UpdateDistribution
Resource:
- !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/*"
FunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- edgelambda.amazonaws.com
Action: ['sts:AssumeRole']
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- !Ref LambdaEdgePolicy
CognitoAtEdgeFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: dist/
Runtime: nodejs20.x
Handler: index.handler
MemorySize: 128
Timeout: 5
AutoPublishAlias: latest
Role: !GetAtt FunctionRole.Arn
Tracing: Disabled
以下のポイントがあります。
Lambda@Edge 用の関数は us-east-1 に作る
Lambda@Edge 用の IAM アクセス権限とロールの設定
サービスプリンシパルに edgelambda.amazonaws.com を追加
lambda:EnableReplication を追加
cloudfront:UpdateDistribution を追加
iam:CreateServiceLinkedRole を追加
詳しくは、こちら を参照ください。
デプロイ
デプロイは sam build と sam deploy で実行します。
新しい Lambda 関数の バージョン発行
ようやく AWS CLI が登場しますが、以下のような感じで新しいバージョンを発行します。
# Makefile
publish-lambda-version:
aws --profile "$(profile)" lambda publish-version \
--function-name $(function_arn) \
--region us-east-1 \
--no-cli-pager
尚、関数の最新バージョンを取得するには、以下のようにします。
# Makefile
latest-lambda-edge-function-version:
aws --profile "$(profile)" lambda list-versions-by-function \
--function-name $(function_arn) \
--region us-east-1 \
--query '$.Versions[-1].Version' \
--no-cli-pager
CloudFront の更新
CloudFront を CloudFormation で構築している場合、以下のように更新できます。
# Makefile
deploy-cloud-front-admin:
aws --profile "$(profile)" cloudformation deploy \
--template ./cloud-front.yml \
--stack-name my-cloud-front \
--parameter-overrides LambdaEdgeFunctionArn="$(function_arn)" LambdaEdgeFunctionVersion="$(function_version)" \
--capabilities CAPABILITY_IAM \
--no-fail-on-empty-changeset
LambdaEdgeFunctionArn に関数の ARN、LambdaEdgeFunctionVersion に最新バージョンを指定すればOKです。
CloudFormation 側は以下のように、LambdaFunctionAssociations を変更可能にしておきます。
# cloud-front.yml
AWSTemplateFormatVersion: 2010-09-09
Parameters:
LambdaEdgeFunctionArn:
Type: String
LambdaEdgeFunctionVersion:
Type: String
Resources:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
DefaultCacheBehavior:
TargetOriginId: !Sub "${StackFamily}-admin"
LambdaFunctionAssociations:
- EventType: viewer-request
LambdaFunctionARN: !Sub "${LambdaEdgeFunctionArn}:${LambdaEdgeFunctionVersion}"
デプロイ後のイメージ
デプロイができると、以下のように、Lambda 関数に新しいバージョンが作成され、CloudFront がトリガーとして表示されていることを確認できます。
おわりに
こうして記事に書き起こすことで気付くこともあるので、やはりアウトプット大事ですね。
誰かのお役に立てれば嬉しいです。
ではでは。