CloudFormationカスタムリソースを最速理解できる簡単な例

2024/03/29に公開

最近CloudFormation Lambda-backedカスタムリソースを触りはじめて、やっと理解できた気がしたので投稿します。

CloudFormationとLambdaには馴染みがある」「カスタムリソースは、Lambda関数を使ってリソースが作れるらしいけど、具体的には知らない」という人が見れば、一瞬でカスタムリソースの実装の要点を掴めそうなCloudFormationテンプレートのサンプルを用意しました[1]

自分でデプロイして動きを確認してみると、理解が深まると思います。

言語はYAML、Pythonです。

サンプル

template.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Deploy sample custom resource

Outputs:
  ResponseData:
    Value: !GetAtt SampleResource.Data

Resources:
  SampleResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt Function.Arn
      Input: 2

  Function:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.12
      Role: !GetAtt FunctionRole.Arn
      Handler: index.handler
      LoggingConfig:
        LogGroup: !Ref FunctionLogGroup
      Code:
        ZipFile: |
          import json
          import cfnresponse
          def handler(event, context):
            responseValue = int(event['ResourceProperties']['Input']) * 5
            responseData = {}
            responseData['Data'] = responseValue
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")

  FunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  FunctionLogGroup:
    DeletionPolicy: Delete
    UpdateReplacePolicy: Delete
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /aws/lambda/MyFunction

※2024/05/23追記:ロググループに関する記述を少し修正しました。詳細はこちら

ざっくり解説

まずは、裏側のLambda関数を作成します。AWS提供のcfn-responseモジュールを使うと、CloudFormationへの応答を書くのが若干楽になります。ZipFileimport cfnresponseした場合、Lambda関数の作成時に自動的にcfnresponse.pyが作られます(作成したLambda関数をコンソールで見ると、index.pyの横にcfnresponse.pyが置いてあることが確認できます)。

参考:

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html

カスタムリソースの作成が開始されると、裏側のLambda関数が実行されます。コードを見てのとおり、今回のカスタムリソースは特に何も作らず、CloudFormationに成功と戻り値(Inputを5倍した数。サンプルなら10)を返すだけです。

次のステップ

カスタムリソースに対して作成、更新、削除が実行される時、それぞれevent['RequestType']CreateDeleteUpdateの文字列が入るので、それぞれの場合の処理を書きましょう。また、応答ステータスにはcfnresponse.SUCCESScfnresponse.FAILEDがあるので、うまくいかなかったら失敗を返すように実装しましょう。

これ以降は、公式リファレンスと戦ってください:

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref.html

脚注
  1. 本文中にもリンクを貼っていますが、Pythonコードはcfn-response module - AWS CloudFormationから拝借しました ↩︎

Discussion