Serverless FrameworkでLambdaを使ってS3にあるオブジェクト名を取得する

Serverless Frameworkを使ってLambdaをS3にアクセスさせてみたいと思います。

まずserverless.ymlを以下のように書きました。

service: serverless-tutorial

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  versionFunctions: false
  lambdaHashingVersion: 20201221
  memorySize: 128
  region: ap-northeast-1

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: echo/hello
          method: get
  s3test:
    handler: s3test.handler
    events:
      - s3:
          bucket: photos20220120
          event: s3:ObjectCreated:*

そしてs3test.pyを以下のように書きました。

import datetime
import boto3

def handler(event, context):
  dt_now = datetime.datetime.now()
  print('object created at ' + str(dt_now) + '.') # 時刻を出力

  s3 = boto3.client('s3')

  response = s3.list_objects_v2(Bucket="photos20220120") # serverless.ymlで定義しているバケット名

  for object in response['Contents']:
      print(object['Key']) #S3バケットにあるオブジェクト名を出力する

動作確認用に時刻を出力した後、S3にあるオブジェクト一覧を出すようにしています。

そして以下のコマンドでデプロイしました。

sls deploy -v

-vをつけると詳細なログが出力できるようです。

--verbose or -v Shows all stack events during deployment, and display any Stack Output.

あと、以前はdeployコマンドに--regionオプションをつけてap-northeast-1を指定していたのですが、serverless.ymlでリージョンを書いておけばデフォルトがそのリージョンになるようです。

無事デプロイできたのでS3にファイルをアップロードしてみました。(GUIでアップロードしましたが、そろそろ慣れてきたのでCLIも使っていきたい)

f:id:JunpeiNakasone:20220128061513p:plain www.serverless.com

するとCloudWatch Logs groupにログが出力されていましたが、時刻は出力されているもののS3のオブジェクト名はAccess Deniedになってエラーが出力されていました。
f:id:JunpeiNakasone:20220128061917p:plain

時刻の出力はLambda関数の中で完結しているので問題ないが、S3からオブジェクトの情報を取得するにはS3バケットにアクセスする必要があるので、その権限が無くエラーになっているようです。

IAMの設定方法についてはこちらのページを読みました。

www.serverless.com

まずは細かい設定はせずにS3への全アクションを許可してみました。
serverless.ymlのproviderプロパティにiamを追加しています。

service: serverless-tutorial

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  versionFunctions: false
  lambdaHashingVersion: 20201221
  memorySize: 128
  region: ap-northeast-1
  iam:
    role:
      statements:
        - Effect: "Allow"
          Action:
            - "S3:*"
          Resource:
            - "*"

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: echo/hello
          method: get
  s3test:
    handler: s3test.handler
    events:
      - s3:
          bucket: photos20220120
          event: s3:ObjectCreated:*

再度デプロイしました。

sls deploy -v

改めてS3にファイルをアップロードすると、今度は無事オブジェクト名が取得できていました。

f:id:JunpeiNakasone:20220128062615p:plain

ちなみにIAMは実際どう設定されているか探してみると「serverless-tutorial-dev-ap-northeast-1-lambdaRole」が設定されていました。 f:id:JunpeiNakasone:20220128062829p:plain

ポリシーにはS3へのアクセスを許可する設定がありました。
f:id:JunpeiNakasone:20220128062938p:plain

以上です。