アラートメールにSlackで返事をする w/ SES + S3 + Lambda + API Gateway 〜Incoming篇〜
9日目。ネタ切れ感半端なさすぎてむりくりネタを作っています。
今日は監視システムからのアラートメールに対してSlackで返信をするというものです。最近はSlackにアラートを飛ばしたりするところも増えていますし、自分のいる部署でもメールとSlackに通知するようにしています。
こういった2つの通知先に通知を送った場合に、片方で返信をしても他方しか見ていないメンバーがいた場合に状況がわからないなんてこともあると思います。こんな状況を(第一報に対しては)解決できるであろう構成です。
ニーズがあるかどうかは知りません。
受信したメールを保存しておく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」をします。
「Verify Domain」をクリックするとダイアログが出てきます。今回はRoute 53を使っているので、素直に「Use Route 53」ボタンをどうぞ。
Verifyされたら次は受信時のアクションを設定していきます。今回は以下のように設定。
ルールの詳細(TLS有効にするか、SPAMやウイルスチェックをするかなど)を入力。
内容を確認して、「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)
メールを受信して、eventの内容を確認
以上でメールを受信した時に発せられるEventを確認できる体制ができまたので、普段使っているメーラからSESで受信できるようにしたドメイン宛にメールを送ります(Local Partは適当で良いです)。
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は各自で設定をしてください。
これでテキストメールを受信するとSlackに内容が通知されます。HTMLメールやMultipartなメールはとりあえずは非対応ということで。
試してみる。
メーラからメールを送ってみると、こんな感じになります。keyと表示されてるのは、返信で使うためのS3のkeyです(イケてないですが見逃してつかあさい)。
おわりに
はい、これで無事メールからSlack通知ができました。アラートメールなどの宛先に1つ追加しておけばよいので、簡単ですね。ただ、ここまでの流れであれば監視システムから直接Slackのincoming-webhooksを使ってポストしてあげれば簡単なんですけど、次回のOutgoing篇でこのシステムの真価を発揮できると思いますのでお楽しみに。
というわけで、第9日目を10日に更新するという事になってしまいましたが、無事終了です。