俺のアウトプット

調べたこと、試したことを書きます

CloudFormationスタック完了時だけメールを受信する

前回のエントリで、スタックイベントをメールで受信できるようになりました。

しかし、全てのイベントを受信するため、大量のメールが届きます。

完了時だけひょっこりメールを受け取りたい!!

最初は、メッセージのフィルタリング機能を使えばできると思ったのですが、メッセージ属性 に対してのフィルタリングであって メッセージ本文 ではできません。

そこで、間に AWS Lambda を挟んで、完了イベントのみ再通知する仕組みを検討します。

概要

大まかな流れは以下になります。

f:id:kitsugi:20180806074701p:plain

  1. ユーザーがスタックを作成
  2. CloudFormationがスタックイベントをLambdaに送信
  3. Lambdaでメッセージをチェック、スタックの完了メッセージならSNSメール送信
  4. ユーザーがメールを受信

トピックの作成

Lambda用とMail用の2つのトピックを作成します。
サービス [アプリケーション統合] - [Simple Notification Service] を選択して、Lambda用のトピックを作成します。

Lambda用
  • トピック名: cloudformation_filter
  • サブスクリプション
    • ここでは作成しません。(Lambda作成時に作成される)
Mail用
  • トピック名: cloudformation
  • サブスクリプション
    • プロトコル: Email
    • エンドポイント: 送信したいメールアドレス

Mail用は前回の記事を参照してください。

AWS Lambdaの作成

次にLambdaを作成します。
サービス [コンピューティング] - [Lambda] を選択し、[関数の作成]ボタンをクリックします。

関数の作成

f:id:kitsugi:20180806074738p:plain

  1. 設計図を選択
  2. テキストボックスにsnsと入力してEnterキー、設計図をフィルタリング
  3. sns-messageを選択
  4. [設定]ボタンをクリック
基本的な情報

f:id:kitsugi:20180806074759p:plain

  • 名前: filterMessage
  • ロール: テンプレートから新しいロールを作成
  • ロール名: lambda_send_sns
  • ポリシーテンプレート: SNN 発行ポリシー
SNSトリガー

f:id:kitsugi:20180806074819p:plain

  • SNSトピック: cloudformation_filter
  • トリガーの有効化: ON

問題なければ、[関数の作成]ボタンをクリックします。

Designer

Lambdaの左側に SNS、右側にAmazon CloudWatchAmazon SNSが表示されていることを確認します。

f:id:kitsugi:20180808175626p:plain

関数コード

以下のコードを入力します。
************は自身のAWSアカウントを指定してください。

var aws = require('aws-sdk');
var sns = new aws.SNS();
let result = {};

exports.handler = async (event, context) => {
    try {
        const mail = event.Records[0].Sns;
        const found = mail.Message.match(/^(?=[\s\S]*ResourceStatus='CREATE_COMPLETE')(?=[\s\S]*ResourceType='AWS::CloudFormation::Stack')/);
    
        if (found) {
            result = await sns.publish({
                Subject: mail.Subject,
                Message: mail.Message,
                TopicArn: "arn:aws:sns:ap-northeast-1:************:cloudformation"
            }).promise();            
        }
  } catch (err) {
      console.log(err);
      return err;
  }

  return result;
};

補足

  • デフォルトのランタイムはNode.js 8.10です。async, await, promiseを利用しています。
  • 改行を含む文字列、メッセージ内に ResourceStatus='CREATE_COMPLETE' かつ ResourceType='AWS::CloudFormation::Stack' を含む正規表現でチェックしています。
  • メールの件名と本文は、受信したメールをそのまま設定しています。わかりやすい内容に変更してください。
Lambdaの保存

右上の[保存]ボタンをクリックします。
「保存されました。」と表示されれば正常です。

f:id:kitsugi:20180806074845p:plain

Lambdaのテスト

メールが受信できるか確認をします。
[テスト]ボタンをクリックして、テストイベントの設定をします。

f:id:kitsugi:20180808182219p:plain

  • 新しいテストイベントの作成: ON
  • イベントテンプレート: SNS
  • イベント名: myEvent

JSON文字列内の "Message" 値を変更します。

"Message": "ResourceStatus='CREATE_COMPLETE' ResourceType='AWS::CloudFormation::Stack'"

[作成]ボタンをクリック、テストイベントmyEventが選択されている状態で、再度[テスト]ボタンをクリックします。

メールが届けば成功です。これで準備が整いました。

CloudFormationスタックの作成

スタックの作成時にLambda用のトピックを指定します。

f:id:kitsugi:20180808184820p:plain

既存のAmazon SNSトピックでLambda用のcloudformation_filterを選択します。
スタック作成後、メールが1件だけ届いたでしょうか?

まとめ

AWS Lambdaを挟むことによって、メールをフィルタリングすることが出来ました。 今回はメール通知ですが、Slackに通知したりするのも面白そうです。

参考