AWS LambdaのInvokeFunctionを正しく理解する
akippaの山下です。突然ですが皆さんは、AWSの好きなサービスは何ですか?色々ある中でも、個人的には Step Functions がとても魅力的だと思っています。
Lambdaと組み合わせることでロジックとフローをキレイに切り離せます(ただし、うまく設計しないとあっという間にピタゴラスイッチ)し、AWSサービスとの統合もかなり拡充した事で、大抵の事はStep Functionsで実現できるんじゃないかと思っています。
残念ながら、akippaではまだ導入のチャンスが無いものの、隙あらば活用したい、今回はそんなStep FunctionsとLambdaの連携でハマった話のご紹介です。
結論
IAMポリシーで、LambdaのInvokeFunctionは 修飾ARN と 非修飾ARN の違いを正しく理解して定義しましょう。
背景
GW中に、プライベートで以下のようなプログラムを書く機会がありました。
入力パラメーター基づいて特定の処理を実行
成果物をS3に保存
一定時間ウェイト
パラメータを変えて1.〜3.をループ
条件を満たしたら終了
Step Functionsがジャストフィットするシチュエーションですね。さっそくステートマシンを作成して、でき上がったものがこちらです。
一部のパラメーターをマスクしたJSONはこちらです。また、Lambdaのコードは本筋でないため割愛します。
{
"StartAt": "Do the job",
"States": {
"Do the job": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"OutputPath": "$.Payload",
"Parameters": {
"Payload.$": "$",
"FunctionName": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:my-job:$LATEST"
},
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"Next": "Still remain?"
},
"Still remain?": {
"Type": "Choice",
"Choices": [
{
"And": [
{
"Variable": "$.x",
"IsPresent": true
},
{
"Variable": "$.y",
"IsPresent": true
},
{
"Variable": "$.remain",
"BooleanEquals": true
}
],
"Next": "Wait"
}
],
"Default": "Done"
},
"Wait": {
"Type": "Wait",
"Seconds": 3,
"Next": "Do the job"
},
"Done": {
"Type": "Pass",
"End": true
}
}
}
これで後は、Step Functionsから初期パラメーターを与えて実行を開始すれば良いのですが、このままではStep FunctionsがLambdaの関数を呼び出す権限を持っていないため、実行は失敗してしまいます。
AWS SAM を使うべしという話もあるでしょうが、久々のStep Functionsだったので、自身の理解度を再確認する意味も含め、今回はすべて自前定義でチャレンジしています。
AWSコンソールからStep Functionsを作成すると、最低限のポリシーを持つロールを作成してくれるので、ここへ単純にLambdaのInvokeFunctionポリシーを追加しました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:my-job"
}
]
}
さてこれであらためて実行してみると、無情にもLambda関数の呼び出しでエラー終了してしまいます。
真っ先に疑うべきはARNの入力ミスですが、LambdaのARNをコピペしているので間違いないはず。他のパラメーターでミスしている可能性も含め、何度ポリシーを定義し直しても同じエラーでLambda関数が実行されません。
ポリシー側で呼び出しを許可する関数を「*(すべて)」にしてしまえば動くのですが、これでは根本解決にならないため、原因を特定するのにかなり手間どりました。
原因
分かってしまえば非常に単純ですが、以下が原因でした。
Step Functions側は、FunctionName に "$LATEST" を含む 修飾ARN で定義している
IAMポリシー側は、関数名までの 非修飾ARN で定義している
ARNに関数のバージョンまで含めない場合は $LATEST と同等である、と理解していたのですが、これがそもそもの誤りでした。公式ドキュメントにもしっかり記載されていました。
今回のケースでは、IAMポリシーにバージョンを含めない「非修飾ARN」を記述し、Step Functions側ではバージョンも含めた「修飾ARN」で定義していたので、これがバッチリ引っかかっていたということでした。
Step FunctionsのFunctionName(修飾ARN)
function:my-job:$LATEST
IAMポリシーのResource(非修飾ARN)
function:my-job
対応
作ったものは書き捨てで構わないので、Lambda関数もバージョン管理する予定はありません。常に$LATESTで構わないので、IAMポリシー側を修飾ARNに変更しました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:my-job:$LATEST"
}
]
}
この状態であらためて実行すると、ステートマシンは期待どおり動作開始、オールグリーンで処理完了しました。処理状況がUIで確認できるのもStep Functionsの良いところです。きれいに完了すると気持ちいいですね。
ちょっとした躓きでしたが、どなたかのお役に立てれば幸いです。
この記事が気に入ったらサポートをしてみませんか?