はじめに
はじめてCloudFormationでS3のイベントでLambdaを発火させるスタックを作成したら失敗したのでメモ。
やりたいこと
- S3にPUTしたタイミングでLambdaを起動したい
- 上記をCloudFormationのテンプレートで作成したい
発生したエラー1
CloudFormationでスタック実行時に以下のエラーが発生
CreateS3Bucket Unable to validate the following destination configurations (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument;
原因
Type: AWS::Lambda::Permission
がない- Lambda 関数を呼び出す S3 バケットのアクセス許可がなかった
対策
- テンプレートに
LambdaInvokePermission
を追加。 - S3バケット作成のテンプレートに、
DependsOn
を追加。
Resources: # ----------------------------------------------------- # # Lambda関数を呼び出すS3バケットのアクセス許可 # ----------------------------------------------------- # LambdaInvokePermission: Type: 'AWS::Lambda::Permission' Properties: FunctionName: !GetAtt hogehogeLambdaFunction.Arn Action: 'lambda:InvokeFunction' Principal: S3.amazonaws.com SourceAccount: !Ref 'AWS::AccountId' SourceArn: !GetAtt CreateS3Bucket.Arn CreateS3Bucket: Type: 'AWS::S3::Bucket' DependsOn: - LambdaInvokePermission
参考情報
発生したエラー2
- スタック実行時のymlのチェックでエラー発生。
テンプレートにエラーがあります。: Circular dependency between resources: [LambdaInvokePermission, CreateS3Bucket, S3BucketPolicy]
原因
- 循環参照になっているため。(鶏が先か卵が先か状態)
対策
- 循環参照を解消するためには、
Fn::Join
を使う
この問題が発生した場合は、Fn::Join 組み込み関数とスタックパラメータを使用して循環依存を回避できます。
なぜFn::Join
を使うと循環参照が解消するのかが疑問だったが、
同様の機能の Fn::Sub 関数も参照してください。
とのことで、Fn::Sub
関数を見ると納得できた。Fn::Sub
および、Fn::Join
はスタックを作成(更新)するまで使用できない値を含むコマンドを実行できるようだ。スタック完了前に作成中のArnなどを返却するイメージと理解した。
テンプレートで、スタックを作成または更新するまで使用できない値を含むコマンドまたは出力を作成するために、この関数を使用できます。
Metadata: "AWS::CloudFormation::Interface": ParameterGroups: - Label: default: "input your environment(staging or production)" Parameters: - ENV Resources: # ----------------------------------------------------- # # Lambda関数を呼び出すS3バケットのアクセス許可 # ----------------------------------------------------- # LambdaInvokePermission: Type: 'AWS::Lambda::Permission' Properties: FunctionName: !GetAtt Scraper.Arn Action: 'lambda:InvokeFunction' Principal: s3.amazonaws.com SourceAccount: !Ref 'AWS::AccountId' # 循環参照を回避するために !GetAtt CreateS3Bucket.Arnではなく、Fn::Join を使用する # 参考:https://aws.amazon.com/jp/premiumsupport/knowledge-center/unable-validate-circular-dependency-cloudformation/ SourceArn: !Join - '' - - 'arn:aws:s3:::' - !Sub "MyBucketName-${ENV}" # ----------------------------------------------------- # # S3 # ----------------------------------------------------- # # クローリング結果を配置するS3バケット CreateS3Bucket: Type: 'AWS::S3::Bucket' DependsOn: - LambdaInvokePermission Properties: BucketName: !Sub "MyBucketName-${ENV}" # 以下略
まとめ
CloudFormationは非常に便利なので、今後もがしがし使っていきたいと思います!