RDSリストアで起動するLambda実行EventBridgeをCloudFormationで構築してみた!

AWS

はじめに

RDSをスナップショットからリストア(復元)した際に、少し時間が経過した後に、起動したRDSが使用可能状態になります。
この使用可能状態なってからLambdaの処理に移りたいケースを想定したEventBridgeをCloudFormationを用いて構築していきます。

参考資料

今回のEventBridge構築に必要なCloudFormationテンプレート(YAMLファイル)は以下を参考にします。

AWS::Events::Rule - AWS CloudFormation
When you create or update a rule, incoming events might not immediately start matching to new or updated rules. Allow a ...
Amazon RDS イベントでトリガーするルールの作成 - Amazon Relational Database Service
Amazon EventBridge などのターゲットに Amazon RDS イベントを送信するためのルールを記述する方法について説明します。

また、EventBridgeのイベントパターンに使用するEventIDは以下から選択します。

の Amazon RDS イベントカテゴリとイベントメッセージ - Amazon Relational Database Service
Amazon RDS では、多数のイベントがカテゴリ分けされて生成され、これらには Amazon RDS コンソール、AWS CLI、または API を使用してのサブスクライブが可能です。

事前準備

以下の内容を事前に準備しておきます。

リストア用RDSスナップショットを作成

RDSの作成時には、多数のパラメータ入力が必要ですが、任意のデータベース識別子を入力ステイドで他の入力項目はデフォルトで問題ないです。
というのも、今回は、RDSデータベースへのログインなどはせず、単にRDSリストアイベントが取得したいだけなので、細かい設定は不要です。

  • 任意のRDSインスタンスを作成
    • RDSは高価なサービスのため、最小スペックで作成しておく
  • アクションからスナップショットを取得

コード配置用S3バケットを作成するCloudFormationテンプレートの実行

S3バケットを作成するCloudFormationテンプレートは以下にございます。

GitHub - kosments/eventbridge-to-lambda-for-rds-state-change: eventbridge-to-lambda-for-rds-state-change
eventbridge-to-lambda-for-rds-state-change. Contribute to kosments/eventbridge-to-lambda-for-rds-state-change developmen...

ダウンロードしてデスクトップなど任意のフォルダに保存します。
s3bucket-for-lambda-code.yml
※その他のファイルも後述の手順で使用するためダウンロードしておきます

  • EventBridgeのターゲットにしたいLambda関数を配置するS3バケットの作成
    • CloudFormationテンプレートを使用します
  • CloudFormation画面を開き、スタックの作成>新しいソースを使用(標準)を選択
  • テンプレートの準備完了を選択
  • テンプレートファイルのアップロードを選択して、保存したymlを選択
  • スタック名とPrefixには、任意の名称を入力して、次へを選択
    • バケット名はユニークでなければならないため、例えば日付などを足したりして被らないようにします
  • 他の項目は特に変更なく送信を選択
  • S3画面を開き、バケットを選択するとS3バケットが作成されています

S3バケットにコードを配置

Lambda関数用のコードをzip化して、PCのローカル環境に配置する必要があります。
sample_lambda_001.zip

  • 作成しておいたS3バケットを開き、アップロードを選択
  • 作成しておいたS3バケットを開き、アップロードを選択
  • S3バケットに選択したzipファイルがアップロードされる

CloudFormationテンプレートの解説

  1. テンプレートのフォーマットバージョンとテンプレートの説明文です。よくわからないうちは、CloudFormationを使う上でのおまじないという認識でOKです。
    https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html
  2. 手入力を要求するパラメータです。#3にハードコーディングしたくない情報やテンプレートを使い回す際に別の値に変わる値(環境名や環境変数)を要求したい場合に使用します。
    https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
  3. 作成するリソースとそのパラメータを指定します。今回は、S3バケットとその設定を入力します。例えば、PublicAccessBlockConfigurationは、パブリックアクセスをブロックするかどうかを指定できます。
    https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-publicaccessblockconfiguration.html
  4. CloudFormationエクスポートに出力したい値を設定します。下記テンプレートでは、別のスタックで、このS3バケットを参照したいため設定しています。
    https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html
#1
AWSTemplateFormatVersion: "2010-09-09"
Description: s3bucket-for-lambda-code

#2
Parameters:
  Prefix:
    Type: String
    Default: "dev"

#3
Resources:
  # ------------------------------ #
  # S3bucket
  # ------------------------------ #
  S3bucketForLambdaCode:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: Private
      BucketName: !Sub "${Prefix}-lambda-code-bucket"
      VersioningConfiguration:
        Status: Enabled
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

#4
Outputs:
  S3BucketNameForLambdaCode:
    Value: !Ref S3bucketForLambdaCode
    Export:
      Name: "S3BucketNameForLambdaCode"

EventBridgeを作成

ここから本題となるEventBridgeの作成をしていきます。
とはいえ、CloudFormationで作成しますので、S3バケットの作成のときとGUIで行う手順は同様です。

EventBridge作成用のCloudFormationテンプレートの実行

  • CloudFormationテンプレートは以下を使用します。
    eventbridge-to-lambda-for-rds-state-change.yml
  • CloudFormation画面を開き、スタックの作成>新しいソースを使用(標準)を選択
  • テンプレートの準備完了を選択
  • テンプレートファイルのアップロードを選択して、保存した上記のymlを選択
  • スタック名は、任意の名称を入力する。パラメータはデフォルトの値のままで次へを選択
    • ダウンロードしたLambda関数名以外やこの後リストアするRDSのデータベース識別子を任意の名称を使用される際は、その名称を入力します。
  • 他の項目は特に変更なく送信を選択
  • 数分経過すると全てのリソースの作成が完了します
  • リソースタブから作成されたそれぞれのリソース画面にアクセスできますので、確認しておきます

CloudFormationテンプレートの解説

EventBridgeと必要なほかリソース(ロールやLambda関数)を作成するCloudFormationテンプレートについての解説です。
S3バケットのテンプレート解説で触れた点は割愛します。

  1. テンプレートフォーマットのバージョンと説明文です。
  2. 入力を要求するパラメータです。
    今回は、予め使用したい値が判明しているのでデフォルト値を設定しています。
  3. Lambda関数を作成します。
    事前に作成したS3バケットを指定します。
    その他ランタイムや後述のロールも指定しています。
  4. Lambda関数用のIAMロールを作成してアタッチしています。
    ポリシーは、AWS管理で通常デフォルトでアタッチされるものを使用します。
  5. EventBridgeルールを作成します。
    EventPatternで条件を設定できます。今回は、RDSスナップショットが復元された時としたいので、該当するEvenrIDを指定しています。また、リストアされるRDSのデータベース識別子も指定できます。
    RDS-EVENT-0043:スナップショット name から復元しました。
    https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_Events.Messages.html#USER_Events.Messages.instance
    Targetで条件に一致した時に起動するサービスとしてLambda関数を指定しています。必要なパラメータはLambda関数名とARNです。
  6. Lambda関数にEventBridgeからLambda関数を実行できる権限を与えています。
    ここでも対象のEventBridgeのARNを受け取るようにします。
#1
AWSTemplateFormatVersion: "2010-09-09"
Description: eventbridge-to-lambda-for-rds-state-change

#2
Parameters:
  RestoredRdsInstaceIdentifer:
    Type: String
    Default: "sample-rds-001"
  TargetLambdaName:
    Type: String
    Default: "sample_lambda_001"
  Handler:
    Type: String
    Default: "sample_lambda_001"
  Runtime:
    Type: String
    Default: "python3.10"

#3
Resources:
  # ------------------------------ #
  # Lambda
  # ------------------------------ #
  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !ImportValue S3BucketNameForLambdaCode
        S3Key: !Sub "${TargetLambdaName}.zip"
      FunctionName: !Ref TargetLambdaName
      Handler: !Sub "${TargetLambdaName}.lambda_handler"
      Runtime: !Ref Runtime
      Role: !GetAtt LambdaRole.Arn

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

#5
  # ------------------------------ #
  # EventBridgeRule
  # ------------------------------ #
  EventRule: 
    Type: AWS::Events::Rule
    Properties: 
      Description: "EventRule"
      EventPattern: 
        source: 
          - "aws.rds"
        detail-type: 
          - "RDS DB Instance Event"
        detail: 
          EventID: 
            - "RDS-EVENT-0043"
          SourceIdentifer:
            - !Ref RestoredRdsInstaceIdentifer
      State: "ENABLED"
      Targets: 
        - Arn: !GetAtt Lambda.Arn 
          Id: !Ref TargetLambdaName

#6
  # ------------------------------ #
  # EventBridgeRule-ResourceBasePolicy
  # ------------------------------ #
  PermissionForEventsToInvokeLambda: 
    Type: AWS::Lambda::Permission
    Properties: 
      FunctionName: !Ref TargetLambdaName
      Action: "lambda:InvokeFunction"
      Principal: "events.amazonaws.com"
      SourceArn: !GetAtt EventRule.Arn

動作検証

スナップショットをリストアして、Lambdaが実行されるか確認します。

  • RDS画面を開き、作成しておいたスナップショットを選択して、アクション>復元を選択
  • 可溶性と耐久性は、単一のDBに設定
  • DBインスタンス識別子は、CloudFormationで設定したパラメータを入力
  • インスタンスの設定では、最小のクラスを選択
  • ストレージは、汎用SSD(gp2)を選択
  • その他の項目は、デフォルトのままDBインスタンスを復元を選択

復元後数分間は、[作成中]のステータスになります。
RDSステータスは、[作成中]>[バックアップ中]>[変更中]>[利用可能]の順で更新されていきます。

CloudTrail画面のイベント履歴で確認すると、リストアイベントが発行されています。しかし、こちらはEventBridgeでイベントパターンに設定しているEventIDとは別です。

ステータスが利用可能になりました。

EventBridgeの条件にマッチしているか確認すると、該当時間帯に確かにトリガールールに一致しています。

Lambdaの方も確認してみます。Lambdaは、1度でも実行されると自動的にCloudWatchLogsにロググループが作成されログが保存されます。
該当時間帯に実行されたログを確認できました。

まとめ

今回は、RDSリストアを起因にラムダを実行するEventBridgeをCloudFormationで作成しました。EventBridgeは様々なAWSサービスのイベントを受け取れるため非常に便利ですので、もっと応用していきたいと思います!

コメント

タイトルとURLをコピーしました