S3のPutイベントで起動するLambdaをAWS SAMでデプロイする

NeeNetです。

今回はS3のPutイベントで起動するLambdaをAWS SAMでデプロイする方法をご紹介します。

具体的には、以下のリソースをAWS SAMで作成したいと思います。

  • S3バケット
  • バケットポリシー
  • Lambda
  • Lambdaの実行ロール
構成図

事前準備

AWS SAM CLIのインストールがまだな方は、公式ドキュメントを参考にインストールしてください。

sam --versionコマンドでバージョンが表示できればインストールできています。

$ sam --version
SAM CLI, version 1.113.0

スクリプトの作成

今回のフォルダ構成は以下の通りです。

.
├── handler
│   └── app.py
├── samconfig.toml
└── template.yaml

samconfig.toml

samconfig.tomlには、SAMでデプロイするための設定を記載します。

version = 0.1

[default]
region = "ap-northeast-1"

[default.build.parameters]
debug = true

[default.deploy.parameters]
stack_name = "<YOUR STACK NAME>"
s3_bucket = "<YOUR S3 BUCKET>"
s3_prefix = "sam-deploy"
capabilities = "CAPABILITY_NAMED_IAM"
confirm_changeset = true

<YOUR STACK NAME><YOUR S3 BUCKET>には、それぞれご自身で決めた任意のスタック名と、SAMのデプロイを行うための資材を配置するS3バケット名を入力してください。

template.yaml

SAMでデプロイするリソースを記載したテンプレートファイルであるtemplate.yamlは以下の通りです。

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: "SAM Application"

Parameters:
  BucketName:
    Type: String
    Default: "<YOUR S3 BUCKET NAME>"
  LambdaName:
    Type: String
    Default: "<YOUR LAMBDA FUNCTION NAME>"

Globals:
  Function:
    Timeout: 180 # 180 seconds
    MemorySize: 128

Resources:
  # S3
  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${BucketName}"
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      NotificationConfiguration:
        EventBridgeConfiguration:
          EventBridgeEnabled: true
  # S3 Bucket Policy
  MyS3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref MyS3Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: AllowSSLRequestsOnly
            Action:
              - "s3:*"
            Effect: Deny
            Resource:
              - !Sub "arn:aws:s3:::${MyS3Bucket}"
              - !Sub "arn:aws:s3:::${MyS3Bucket}/*"
            Principal: "*"
            Condition:
              Bool:
                "aws:SecureTransport": "false"
  # Lambda
  MyLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${LambdaName}"
      Role: !GetAtt MyLambdaFunctionRole.Arn
      CodeUri: handler/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Layers:
        - arn:aws:lambda:ap-northeast-1:336392948345:layer:AWSSDKPandas-Python39:15
      Events:
        S3PutEvent:
          Type: S3
          Properties:
            Bucket: !Ref MyS3Bucket
            Events: "s3:ObjectCreated:*"
  # IAM Role for Lambda
  MyLambdaFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${LambdaName}-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AmazonS3FullAccess

<YOUR S3 BUCKET NAME><YOUR LAMBDA FUNCTION NAME>には、それぞれご自身で決めた今回新規作成するS3バケット名とLambda関数名を入力してください。

それぞれのリソースについて簡単に説明すると、まずS3バケットは暗号化を有効にし、EventBridgeへの通知をONにする設定にしています。
またパブリックアクセスについても明示的にブロックするようにしています。

バケットポリシーについては、SSL以外でのアクセスを拒否するように設定しています。

Lambda関数について、アーキテクチャはx86_64とし、LambdaレイヤーとしてマネージドレイヤーであるAWS SDK for pandasを利用できるようにしています。

AWS SDK for pandasにはnumpypandasがモジュールとして含まれているので、ファイル処理等をする際に便利です。

Lambda関数の実行ロールについては、どちらもマネージドポリシーであるAWSLambdaBasicExecutionRoleAmazonS3FullAccessを設定しています。

app.py

今回Lambda関数で動かすためのapp.pyは以下の通りです。

import json
import logging

logger = logging.getLogger()
logger.setLevel("INFO")


def lambda_handler(event, context):
    s3_bucket = event["Records"][0]["s3"]["bucket"]["name"]
    object_key = event["Records"][0]["s3"]["object"]["key"]

    logger.info(f"s3_bucket: {s3_bucket}, object_key: {object_key}")

    return {"message": "success"}

今回はS3へのPutイベントを契機にLambdaが起動するよう設定しているので、PutされたファイルのS3バケット名とオブジェクトキーをログに表示するようなサンプルにしています。

デプロイと実行

デプロイは以下のコマンドで実行可能です。

$ sam deploy

実行すると、以下のようにスタックのchange setが表示されると思うので、内容を確認します。

change set

デプロイが完了すると、CloudFormation上でsamconfig.tomlに設定したスタック名でデプロイがされていることを確認できると思います。

作成されたS3バケットに適当なファイルをアップロードすると、Lambdaが起動します。

CloudWatchのログを確認すると、以下のようにバケット名とアップロードしたファイルのオブジェクトキーが表示されていることを確認できます。

CloudWatchのログ

最後に

今回はS3のPutイベントで起動するLambdaをAWS SAMでデプロイする方法をご紹介しました。

参考になりましたら幸いです。

ご依頼について

NeeNetではIaC(Infrastructure as Code)を利用したAWS上でのインフラ環境の構築、およびその上で動くアプリケーションの開発のご依頼・ご相談をお引き受けしております。

個人・法人問わず、何かご相談事項がございましたら、一度ご連絡いただければと思います。

  • URLをコピーしました!