アラートメールにSlackで返事をする w/ SES + S3 + Lambda + API Gateway 〜Incoming篇〜

9日目。ネタ切れ感半端なさすぎてむりくりネタを作っています。

今日は監視システムからのアラートメールに対してSlackで返信をするというものです。最近はSlackにアラートを飛ばしたりするところも増えていますし、自分のいる部署でもメールとSlackに通知するようにしています。

こういった2つの通知先に通知を送った場合に、片方で返信をしても他方しか見ていないメンバーがいた場合に状況がわからないなんてこともあると思います。こんな状況を(第一報に対しては)解決できるであろう構成です。

f:id:matetsu:20151211015745p:plain

ニーズがあるかどうかは知りません。

Route 53の設定

メールを受信するドメインの設定をします。今回はOreginの受信用Endpointを利用するので、以下のとおりに。

f:id:matetsu:20151210004022p:plain

受信したメールを保存しておくS3バケットの設定

適当な名前でバケットを作成し、Bucket Policyに以下のようなPolicyを設定する。ドキュメントとしては、こちら

{
	"Version": "2008-10-17",
	"Statement": [
		{
			"Sid": "GiveSESPermissionToWriteEmail",
			"Effect": "Allow",
			"Principal": {
				"Service": [
					"ses.amazonaws.com"
				]
			},
			"Action": [
				"s3:PutObjectAcl",
				"s3:PutObject"
			],
			"Resource": "arn:aws:s3:::BUCKET_NAME/*",
			"Condition": {
				"StringEquals": {
					"aws:Referer": "ACCOUNT_NO"
				}
			}
		}
	]
}

SESの受信設定

受信用ドメインの認証をしますので、さきほどRoute 53でMXレコードとして設定したドメインをRecipientsとして登録して「Verify Domain」をします。

f:id:matetsu:20151210004508p:plain

「Verify Domain」をクリックするとダイアログが出てきます。今回はRoute 53を使っているので、素直に「Use Route 53」ボタンをどうぞ。

Verifyされたら次は受信時のアクションを設定していきます。今回は以下のように設定。

f:id:matetsu:20151210012226p:plain

ルールの詳細(TLS有効にするか、SPAMやウイルスチェックをするかなど)を入力。

f:id:matetsu:20151210010325p:plain

内容を確認して、「Create Rule」をします。

S3ではなく、SNSやLambdaで直接受けたほうが便利なのではとお思いでしょうが、S3でないとメールの本文を取得することができないのです。(他のブログでも書かれていますし、結構重要な点ですが、Amazonさんならそのうち取得できるようにしてくれるはず。)

イベント内容確認のためにLambda Functionの枠だけを作成しておく

Lambda Functionの作り方は、これまで何度もやってきたので省略。Blueprintのhello-world-pythonを少し変えて、以下の用意しておきます。

from __future__ import print_function

import json

print('Loading function')


def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))
   
    return "CONTINUE" 

割り当てるRoleのPolicyはこんな感じ。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/*"
      ]
    },
        {
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendRawEmail"
            ],
            "Resource": "*"
        }
  ]
}

これで、どんなEventが来たかをCloudWatch Logsから確認できます。


S3バケットに更新Eventを設定する

こんな感じで設定。先ほど作成したLambda FunctionにEventを送信するようにしています。
(名前の適当さは気にしないでくださいw)

f:id:matetsu:20151210231018p:plain

メールを受信して、eventの内容を確認

以上でメールを受信した時に発せられるEventを確認できる体制ができまたので、普段使っているメーラからSESで受信できるようにしたドメイン宛にメールを送ります(Local Partは適当で良いです)。

f:id:matetsu:20151210231449p:plain

CloudWatch LogsでEvent内容を確認

このような内容のEventが来ます。Bucket名とKey名がわかるので、これを使えばS3からメールの内容を取得することができますね。

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventTime": "2015-12-10T01:47:57.525Z",
      "requestParameters": {
        "sourceIPAddress": "IP.ADD.RE.SS"
      },
      "s3": {
        "configurationId": "notify-receiving-to-lambda",
        "object": {
          "eTag": "77ca66e4622ae4c5c113e9fd07109df0",
          "sequencer": "005668D9CD4BB230B3",
          "key": "KEY",
          "size": 1662
        },
        "bucket": {
          "arn": "arn:aws:s3:::BUCKET",
          "name": "BUCKET",
          "ownerIdentity": {
            "principalId": "PRINCIPAL_ID"
          }
        },
        "s3SchemaVersion": "1.0"
      },
      "responseElements": {
        "x-amz-id-2": "iDu7YW04ChE4HHC5HjGXC8/v1X8KzZZqNY6l7oXwulcjWQUiXY2DZfuNcHjsOfeW5Rriy8RfWTk=",
        "x-amz-request-id": "BBB6B16CB9E173EA"
      },
      "awsRegion": "ap-northeast-1",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "AWS:XXXXXXXXXXX"
      },
      "eventSource": "aws:s3"
    }
  ]
}

Lambda Functionを修正

Slackにも通知するために、こんな感じで修正します。SlackのIncoming Webhooksは各自で設定をしてください。


SES -> S3 -> Lambda -> Slack

これでテキストメールを受信するとSlackに内容が通知されます。HTMLメールやMultipartなメールはとりあえずは非対応ということで。

試してみる。

メーラからメールを送ってみると、こんな感じになります。keyと表示されてるのは、返信で使うためのS3のkeyです(イケてないですが見逃してつかあさい)。

f:id:matetsu:20151210235234p:plain

おわりに

はい、これで無事メールからSlack通知ができました。アラートメールなどの宛先に1つ追加しておけばよいので、簡単ですね。ただ、ここまでの流れであれば監視システムから直接Slackのincoming-webhooksを使ってポストしてあげれば簡単なんですけど、次回のOutgoing篇でこのシステムの真価を発揮できると思いますのでお楽しみに。

というわけで、第9日目を10日に更新するという事になってしまいましたが、無事終了です。