💂

EventBridge Scheduler からの Lambda 関数起動に Lambda Permission は不要

2023/09/22に公開

AWS Lambda 関数の他サービスからの呼び出し

AWS Lambda 関数にはリソースベースポリシーを割り当てることができます。
関数を他のサービスから呼び出すとき,通常はリソースベースポリシーにそのサービスからの実行を許可するポリシーを追加する必要があります。

例えば,Amazon SNS からイベント駆動で呼び出す場合は,以下のように add-permission コマンドを実行することでポリシーを追加することができます。

aws lambda add-permission --function-name example-function \
--action lambda:InvokeFunction \
--statement-id AllowExecutionFromSNS \
--principal sns.amazonaws.com

Terraform では aws_lambda_permission リソースを使います。

resource "aws_lambda_permission" "with_sns" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.example.function_name
  principal     = "sns.amazonaws.com"
  source_arn    = aws_sns_topic.example.arn
}

マネジメントコンソール上でトリガーを追加すると,自動的にリソースベースポリシーも追加されます。

一方で,AWS CLI や Terraform など API 経由で関数を作成する場合は,リソースベースポリシーも手動で追加する必要があります。
Lambda 関数と連携するのに必要なリソースを作成したのになぜか実行されない場合は,リソースベースポリシー(permission)を作り忘れていたということがよくあります。エラーも出ないので,知らないと原因特定が難しくて厄介です。

EventBridge からの呼び出しでは必要

Amazon EventBridge というサービスから Lambda 関数を呼び出す場合も同様にリソースベースポリシーへの追加が必要になります。principal は events.amazonaws.com です。

EventBridge Scheduler からの呼び出しでは不要

Amazon EventBridge Scheduler は2022年11月にリリースされた新しいサービスで,EventBridge ルールとは別のスケジューリング機能を提供します。

EventBridge という名前がついていますが,ドキュメントもサービスプリンシパルも分かれているので,内部的には独立したサービスとみなせます。

EventBridge と EventBridge Scheduler の違いは以下の記事に書かれています。

https://aws.amazon.com/jp/blogs/compute/introducing-amazon-eventbridge-scheduler/

呼び出しにはなぜか Lambda 関数のリソースベースポリシーが不要で,InvokeFunction を許可した IAM ロールを付与するだけで実現できます。

Terraform で表現すると以下のようになります。

EventBridge Scheduler の権限設定
locals {
  function_name = "example-function"
}

resource "aws_scheduler_schedule" "scheduler" {
  name = local.function_name

  flexible_time_window {
    mode = "OFF"
  }

  schedule_expression          = "cron(0 3 * * ? *)"
  schedule_expression_timezone = "Asia/Tokyo"

  target {
    arn      = aws_lambda_function.example.arn
    role_arn = aws_iam_role.scheduler.arn
  }
}

resource "aws_iam_role" "scheduler" {
  name               = local.function_name
  assume_role_policy = data.aws_iam_policy_document.trust_scheduler.json
}

data "aws_iam_policy_document" "trust_scheduler" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["scheduler.amazonaws.com"]
    }
  }
}

resource "aws_iam_policy" "scheduler" {
  name   = local.function_name
  policy = data.aws_iam_policy_document.scheduler.json
}

data "aws_iam_policy_document" "scheduler" {
  statement {
    actions   = ["lambda:InvokeFunction"]
    resources = [aws_lambda_function.example.arn]
  }
}

resource "aws_iam_role_policy_attachment" "scheduler" {
  role       = aws_iam_role.scheduler.name
  policy_arn = aws_iam_policy.scheduler.arn
}

なぜこのサービスだけリソースベースポリシーが不要なのかはよくわかりませんでした。ご存じの方がいらっしゃいましたらご教示頂けると助かります。

参考:リソースベースポリシーの追加画面

Lambda 関数のマネジメントコンソールで,リソースベースポリシーを追加する画面で許可する AWS のサービスを選択できるのですが,選択肢は以下に挙げるものになっていました。EventBridge Scheduler の名前がないことが関連しているのかもしれません。

  • API Gateway
  • AWS IoT
  • Alexa Skills Kit
  • Alexa Smart Home
  • Application Load Balancer
  • CloudWatch Logs
  • CodeCommit
  • Cognito Sync Trigger
  • EventBridge (CloudWatch Events)
  • Kinesis
  • S3
  • Secrets Manager
  • SNS
  • SQS
  • Other

Discussion