見出し画像

Lambda@Edge を AWS CLI でデプロイする

はじめに

CloudFront + Cognito + Lambda@Edge (cognito-at-edge) でサイトに認証をかけたいのですが、複数ハマったポイントがありました。
Cognito の話は別途、記事を書く予定ですが、今回は Lambda@EdgeAWS 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 に作る

US-East-1 (バージニア北部) リージョン (us-east-1) にいることを確認します。Lambda@Edge 関数を作成するには、このリージョンに設定されている必要があります。

「チュートリアル:シンプルな Lambda@Edge 関数の作成」 - Amazon CloudFront

Lambda@Edge 用の IAM アクセス権限とロールの設定

  • サービスプリンシパルに edgelambda.amazonaws.com を追加

  • lambda:EnableReplication を追加

  • cloudfront:UpdateDistribution を追加

  • iam:CreateServiceLinkedRole を追加

詳しくは、こちら を参照ください。

デプロイ

デプロイは sam buildsam 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 の更新

CloudFrontCloudFormation で構築している場合、以下のように更新できます。

# 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 がトリガーとして表示されていることを確認できます。

AWS Lambda

おわりに

こうして記事に書き起こすことで気付くこともあるので、やはりアウトプット大事ですね。
誰かのお役に立てれば嬉しいです。
ではでは。