はじめに

AWS SAMでEventBridge + Lambdaを作成する際に、Lambdaのリソースポリシー(リソースベースのポリシー)が必要となります。その定義の仕方についてまとめます。

構成

Lambdaを定期実行させるための、EventBridge + Lambdaの環境。
この際、EventBridgeからLambdaの実行を許可するリソースポリシーを設定する必要があります。

Lambda でのリソースベースのポリシーの使用

2パターンで定義できる

上記の構成をSAMテンプレートで定義する場合、EventBridgeルールをどう定義するかで以下の2パターンがあり、ケースによって使い分ければ良いと思います。

パターン EventBridgeルール リソースポリシー ケース
組み合わせテンプレート AWS::Serverless::Function 内にEventsプロパティで定義する 自動生成される EventBridge:Lambdaが1:1のようなシンプルな構成の場合
分離テンプレート AWS::Events::Rule で定義 AWS::lambda::Permission で定義 上記以外の複雑なルーティングロジックがある場合や、SAMテンプレートの外部のリソースに接続している場合

Amazon EventBridge と AWS Serverless Application Model テンプレートの使用

やってみる

組み合わせテンプレートの場合

AWS::Serverless::Function にEventsプロパティを定義しておきます。
Lambdaのリソースベースポリシーは自動で作成されます。

[template.yaml]

CombinedTemplateFunction:
Type: AWS::Serverless::Function
Properties:
  FunctionName: combined-template-function
  CodeUri: function/
  Handler: combined-template-function.main
  Runtime: python3.9
  Events:
    Trigger:
      Type: Schedule
      Properties:
        Name: combined-template-function-rule
        Schedule: cron(0 19 * * ? *)
        Enabled: true

Lambdaの リソースベースのポリシーステートメント に設定されます。
ステートメントの名前は、 SAMにて展開されるCFnテンプレート名SAMテンプレートで定義したLambdaのリソース名 が使われているようです。

ポリシーの中身はこんなJSONになってます。
EventBridgeからLambdaを実行できるようなポリシーです。

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "matsuki-sam-test-stack-CombinedTemplateFunctionTriggerPermission-1W1YZ5AHM55JM",
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:combined-template-function",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:events:ap-northeast-1:xxxxxxxxxxxx:rule/combined-template-function-rule"
        }
      }
    }
  ]
}

注意

組み合わせテンプレートで定義した上に、AWS::Events::Rule , AWS::lambda::Permission を定義すると、自動作成されるリソースベースポリシーと合わせて2つのポリシーができてしまうので注意。(もちろんEventBridgeルールも2つ作成することになります)

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "matsuki-sam-test-stack-CombinedTemplateFunctionTriggerPermission-1V9ZUVBPFTLY2",
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:combined-template-function",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:events:ap-northeast-1:xxxxxxxxxxxx:rule/combined-template-function-rule"
        }
      }
    },
    {
      "Sid": "matsuki-sam-test-stack-PermissionForEventsToInvokeLambda-DPGG7INS0F8H",
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:combined-template-function",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:events:ap-northeast-1:xxxxxxxxxxxx:rule/separated-template-function-rule"
        }
      }
    }
  ]
}

分離テンプレートの場合

AWS::Serverless::Function にEventsプロパティを定義しません。
AWS::lambda::Permission で、LambdaとEventBridgeを紐づけるような定義をします。

  • Lambda Function
    [template.yaml]
SeparatedTemplateFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: function/
    Handler: handler.case1Handler
    Runtime: python3.9
  • EventBridge Rule
    [template.yaml]
  SeparatedTemplateFunctionRule:
    Type: AWS::Events::Rule
    Properties:
      Name: separated-template-function-rule
      ScheduleExpression: cron(0 19 * * ? *)
      State: ENABLED
      Targets:
      -
        Arn: !GetAtt SeparatedTemplateFunction.Arn
        Id: "TargetFunctionV1"
  • Lambda リソースポリシー
    [template.yaml]
  PermissionForEventsToInvokeLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName:
        Ref: SeparatedTemplateFunction
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt SeparatedTemplateFunctionRule.Arn

デプロイするとこんな形となります。

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "matsuki-sam-test-stack-PermissionForEventsToInvokeLambda-12RZWZ0IU5Z5Y",
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:separated-template-function",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:events:ap-northeast-1:xxxxxxxxxxxx:rule/separated-template-function-rule"
        }
      }
    }
  ]
}

ちなみに、CFnテンプレートの場合

CFnテンプレートも同じかなと思ったら、AWS::lambda::Function のプロパティにはEventsはありませんでした。
よって、組み合わせテンプレートの書き方を使えば良いと思います。
AWS::Lambda::Function

おわりに

SAMテンプレートでLambda + EventBridgeを作成する際の定義の仕方についてまとめました。
ケースによって組み合わせテンプレートと分離テンプレートを使い分けましょう。