AWS API Gateway+LambdaでSlackにメッセージをPOSTする(前編)
Slackはincoming webhooksがあり、POSTするだけで、簡単にメッセージを送ることができます。
スクリプトで直接Incoming Webhook使ってもいいんですが、これ自体は別に認証も何もないので、誰かが知ってしまうと、好き放題投稿できます。そんな時に入れ替えたりする場合、いろんなスクリプトの設定に埋め込まれていて、方々に散っているのはちょっと辛いです。また、多言語環境の場合は、一定の処理を行う場合に各言語でライブラリ作るのもしんどいかなーということで、AWSのAPI Gateway + Lambdaを使って汎用化してみます。*1
Slackのteam、AWSアカウントはあるものとして、以下を行っていきます。
Slack Incoming Webhookの作成
Incoming Webhookは、channelを指定するので、今回は#general
を使います。必要に応じてchannelを作成してください。
次に、incoming webhook integration(新規作成ページへのリンク)を開きます。
channelに#generalを選択して作成します。
そうすると、settingsのページに行くので、Webhook URLをコピーしておきます。
また、下の方に行くと、名称とアイコンを設定できるので、用途に合わせて変更します。
以下のcurlで試すと、メッセージが表示されます。(URL部分は置き換えてください)
curl -X POST -H 'Content-type: application/json' \ --data '{"text":"This is a line of text.\nAnd this is another one."}' \ https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
レスポンスは、成功したらok
だけです。以下のように表示されます。(画像は名称の反映が遅延しているのか、incoming webhookのままでした)
AWS Lambdaでincoming Webhookを使う
次に、Lambda上に実装していきます。
-- 2018/02/18 追記
この後の、Lambda+API GatewayをCloudFormationで自動構築できるようにしたので、面倒な方はそちらもどうぞ。
-- 追記ここまで
AWS consoleからLambdaサービスを開き、Functionsから[create a Lambda function]を選んでスタートします。BluePrintには、pythonでのCloudWatch->APIGateway->Lambda->Slackはありますが、今回はnode.jsで行うので、Blank functionから作ります。
Triggerは、作らないまま進みます。
詳細が出てくるので、Nameにpost-slack-general
(好きな名称で構いません)を入力して、RuntimeはデフォルトのNode.js 4.3
にします。
Lambda function codeは[Edit in inline]で、以下を入れます。
console.log('Loading function'); const https = require('https'); const url = require('url'); const slack_url = process.env.SLACK_WEBHOOK_URL; const slack_req_opts = url.parse(slack_url); slack_req_opts.method = 'POST'; slack_req_opts.headers = {'Content-Type': 'application/json'}; exports.handler = function(event, context) { if (event.text) { var req = https.request(slack_req_opts, function (res) { if (res.statusCode === 200) { context.succeed('posted to slack'); } else { context.fail('status code: ' + res.statusCode); } }); req.on('error', function(e) { console.log('problem with request: ' + e.message); context.fail(e.message); }); // ここで、メッセージの編集を必要に応じて行う。 var message = event.text; req.write(JSON.stringify({text: message})); req.end(); } }); };
このAWS LambdaでSlackのIncoming Webhookでメッセージを送る例は、 CloudWatchのAlertをAWS Lambda経由でSlackに飛ばすを参考にさせていただきました。
上記ページは、SNS用のpayload構造になっているので、その部分などを変更しています。{"text":"message"}
というJSONが来て、そのtextのvalueをSlackに送るLambda(node.js)です。*2
また、Webhook URLは環境変数で入れるように変更しています。そのあとのEnvironment variablesで、SLACK_WEBHOOK_URL
というkeyでWebhook URLを設定します。
Lambdaの実行のIAMRoleは、特に追加の権限は必要ないので、最低限Lambda実行に必要なIAMRoleを作ります。すでにある方は飛ばしてください。[Create a custom role]を選択して、IAMの画面に移動します。
デフォルトで表示されているものを[Allow]で許可すれば大丈夫です。
作成したIAMRoleが選択されます。
Advanced settingsのところは特に変更しません。最下部の[Next]で次のプレビューに進み、[Create function]で作成完了です。
Lambdaの実行確認
Lambdaは、テスト実行ができます。[Action] -> [configure test event]を選びます。
デフォルトで[Hello world]が選択されているので、その下のJSONを、以下に変更して、[Save and Test]で実行します。
{"text":"Message from AWS Lambda"}
成功したら、Slackにメッセージが表示されます。 出てこない場合は、AWS console画面下部に実行ログが出てくるので、それで確認しましょう。