CloudFormationスタックの失敗を整形して通知する

CloudFormationスタックの失敗をサクッと通知する仕組みをCloudFormationテンプレートで作ってみたよ。
2022.08.05

最近CloudFormationスタックの失敗を通知する仕組みが欲しいなーと思ったので、CloudFormationでサクッと通知できるテンプレートを作成しました。

できるようになること

スタックの作成や更新、失敗が失敗するとこんなメールを通知できます。

構成

EventBridgeでCloudFormationスタックの失敗イベントを取得。インプットトランスフォーマーで整形してSNS経由でメール通知します。

CloudFormationテンプレート

通知の構成を一発で作成できるCloudFormationテンプレートです。パラメータに通知先としたメールアドレスを入力すれば使えます。

AWSTemplateFormatVersion: 2010-09-09
Description: CloudFormation Stack Failed Notification

Parameters:
  NotificationTarget:
    Description: Email for notification
    Type: String

Resources:
  # アラーム検出・通知用のリソース
  ## SNSトピック
  SnsTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: cfn-failed-notification-topic
      Subscription:
        - Endpoint: !Ref NotificationTarget
          Protocol: email
  ## SNSトピックポリシー
  EventTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      PolicyDocument:
        Statement:
          - Effect: "Allow"
            Principal:
              Service: "events.amazonaws.com"
            Action: "sns:Publish"
            Resource: "*"
      Topics:
        - !Ref SnsTopic
  ## EventBridge
  AlarmEvent:
    Type: AWS::Events::Rule
    Properties:
      Description: "Get CloudFormation failures"
      EventPattern: !Sub |
        {
          "source": ["aws.cloudformation"],
          "detail-type": ["CloudFormation Stack Status Change"],
          "detail": {
            "status-details": {
              "status": ["CREATE_FAILED", "UPDATE_FAILED", "DELETE_FAILED","ROLLBACK_COMPLETE","ROLLBACK_FAILED"]
            }
          }
        }
      Targets:
        - Arn: !Ref SnsTopic
          Id: sns-topic
          InputTransformer:
            InputPathsMap:
              {
                "account": "$.account",
                "detail-type": "$.detail-type",
                "region": "$.region",
                "stack-id": "$.detail.stack-id",
                "status": "$.detail.status-details.status",
                "time": "$.time",
              }
            InputTemplate: |
              "CloudFormationスタックでエラーが発生しました。"
              "アカウント: <account>"
              "時間: <time>"
              "リージョン: <region>"
              "スタックID: <stack-id>"
              "ステータス: <status>"
              "コンソールURL: https://<region>.console.aws.amazon.com/cloudformation/home?#/stack/detail?stackId=<stack-id>"

動作確認

上記のCloudFormationテンプレートをデプロイします。入力したメールアドレスにサブスクリプションの承認メールが届きますので承諾してください。

動作確認のため、わざと失敗するCloudFormationスタックを作成してみます。

スタックの失敗オプションをデフォルト(すべてのスタックリソースをロールバックする)にした状態であれば、ステータスがROLLBACK_COMPLETEとなることが確認できます。

するとメールに通知が届き、アカウントIDやステータス、コンソールURL等が確認できました。

EventBridgeの実装詳細

CloudFormationで作成している以下を少し解説します。

  ## EventBridge
  AlarmEvent:
    Type: AWS::Events::Rule
    Properties:
      Description: "Get CloudFormation failures"
      EventPattern: !Sub |
        {
          "source": ["aws.cloudformation"],
          "detail-type": ["CloudFormation Stack Status Change"],
          "detail": {
            "status-details": {
              "status": ["CREATE_FAILED", "UPDATE_FAILED", "DELETE_FAILED","ROLLBACK_COMPLETE","ROLLBACK_FAILED"]
            }
          }
        }
      Targets:
        - Arn: !Ref SnsTopic
          Id: sns-topic
          InputTransformer:
            InputPathsMap:
              {
                "account": "$.account",
                "detail-type": "$.detail-type",
                "region": "$.region",
                "stack-id": "$.detail.stack-id",
                "status": "$.detail.status-details.status",
                "time": "$.time",
              }
            InputTemplate: |
              "CloudFormationスタックでエラーが発生しました。"
              "アカウント: <account>"
              "時間: <time>"
              "リージョン: <region>"
              "スタックID: <stack-id>"
              "ステータス: <status>"
              "コンソールURL: https://<region>.console.aws.amazon.com/cloudformation/home?#/stack/detail?stackId=<stack-id>"

Event Ruleのイベントパターン

CloudFormationスタックのステータスを以下のイベントパターンで取得しています。

        {
          "source": ["aws.cloudformation"],
          "detail-type": ["CloudFormation Stack Status Change"],
          "detail": {
            "status-details": {
              "status": ["CREATE_FAILED", "UPDATE_FAILED", "DELETE_FAILED","ROLLBACK_COMPLETE","ROLLBACK_FAILED"]
            }
          }
        }

取得したいステータスは「スタックが失敗」した時なので、失敗を表すステータスを対象としています。

CloudFormationスタックのステータスコード詳細は以下ドキュメント参照。

スタックの情報とリストの取得 - AWS CloudFormation

スタックのステータスはデプロイ時のオプションで変わります。選択できるのは「すべてのスタックリソースをロールバックする」と「正常にプロビジョニングされたリソースの保持」となっており、このオプションによって最終的なスタックのステータスが変わります。

デフォルトの動作であるロールバックでは最終的なスタックのステータスはROLLBACK_COMPLETEROLLBACK_FAILED

リソースの保持を設定していれば、作成やアップデート時の失敗でスタックが止まるためCREATE_FAILEDUPDATE_FAILEDを取得する必要があります。他に拾いたいステータスがあれば、お好みで追加してください。

入力トランスフォーマー

メッセージの整形はEvent Rule内の入力トランスフォーマーで行っています。個人的に必要な情報を入れましたが、こちらもお好みで変更ください。サンプルイベントを載せておきます。

サンプルイベント

{
  "version": "0",
  "source": "aws.cloudformation",
  "account": "123456789012",
  "id": "12345678-1234-1234-1234-111122223333",
  "region": "us-east-1",
  "detail-type": "CloudFormation Stack Status Change",
  "time": "2022-04-31T17:00:00Z",
  "resources": ["arn:aws:cloudformation:us-east-1:123456789012:stack/teststack"],
  "detail": {
    "stack-id": "arn:aws:cloudformation:us-west-1:123456789012:stack/teststack",
    "status-details": {
      "status": "CREATE_COMPLETE",
      "status-reason": ""
    }
  }
}

まとめ

CloudFormationスタックの失敗を入力トランスフォーマーで整形して通知してみました。とりあえずスタックの失敗を通知したい時にはご利用頂ければ幸いです。

参考