経緯
IoT CoreからIoTルールアクションでLambdaを実行していたが、コールドスタートが気になりSAMテンプレートでProvisioned Concurrencyを適用。
Provisioned Concurrency適用時の設定
IoTルールのSQLステートメントとSAMテンプレート
SQLステートメント
SELECT
aws_lambda("arn:aws:lambda:ap-northeast-1:111111111111:function:hoge-func:Live", {"payload": *})
FROM
'topic/subtopic'
SAMテンプレート(Lambda部分)
hogeFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub hoge-func
CodeUri: src/handler
Role: !GetAtt LambdaHogeRole.Arn
AutoPublishAlias: Live
ProvisionedConcurrencyConfig:
ProvisionedConcurrentExecutions: 10
SAMテンプレート(リソースベースポリシー部分)
IoTRuleInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref hogeFunction
Principal: iot.amazonaws.com
SourceArn: !Sub arn:aws:iot:ap-northeast-1:${AWS::AccountId}:rule/*
SourceAccount: !Ref AWS::AccountId
Action: lambda:InvokeFunction
問題
Provisioned Concurrency適用後から、IoTルールアクション経由でのLambda実行ができなくなった。
エラー
IoTログを確認したところ、以下のエラーが出力されていた。
エラー
Received an error while making a request to Lambda: ErrorType: Client, ErrorCode: AccessDeniedException, StatusCode: 403
原因
Provisioned Concurrencyの適用でLambdaのARNが変更されており、変更後のARNにリソースベースのポリシーステートメントがアタッチされていなかった。
変更前のARN
arn:aws:lambda:ap-northeast-1:111111111111:function:hoge-func
変更後のARN
arn:aws:lambda:ap-northeast-1:111111111111:function:hoge-func:Live
解決方法
DependsOnでLambdaのAliasLiveが作成されるのを待ってから、リソースベースのポリシーステートメントをLambdaにアタッチするように記載したらうまくいった。
SAMテンプレート(リソースベースポリシー部分)
IoTRuleInvokePermission:
Type: AWS::Lambda::Permission
DependsOn: hogeFunctionAliasLive
Properties:
FunctionName: !Join [ '', [ !GetAtt hogeFunction.Arn, ':Live' ] ]
Principal: iot.amazonaws.com
SourceArn: !Sub arn:aws:iot:ap-northeast-1:${AWS::AccountId}:rule/*
SourceAccount: !Ref AWS::AccountId
Action: lambda:InvokeFunction
まとめ
リソース間の依存関係が問題だと早い段階で気づき、以下のように書いていたが、hogeFunctionのAliasに対して、リソースベースのポリシーをアタッチすることはできなかった。
DependsOn: hogeFunction
DependsOnで指定しているAliasLiveのリソースは、テンプレート上どこにも存在しないので、かなりの引っかかりポイントだと思われる。
おわりに
同じような問題に突き当たった人の助けになれば幸いです。