災害時に気づかれない安否確認を何とかしたかった
先日の台風19号の上陸時、自社の安否確認システムが発動し、全社員に一斉連絡が行われました。
この連絡は、安否確認システムに登録された電話番号とメールアドレス宛に行われることとなっています。
これは、各社でよくある安否確認システムの仕組みだと思われます。
しかし、今回の安否確認連絡に対する回答率は、普段実施している訓練の時よりも悪くなってしまったようです。
個人的な考察ですが、訓練では事前にメールを送信されると知らされているから回答率が良いのであり、いざ本番となると気づかない人が多いのだと考えました。
電話はEメールよりも効果的だと思うのですが、いたずら電話と勘違いして、取られないのかもしれません。
部員全員が使っているSlackに通知したら回答率が上がるのではないか
「Eメールは埋もれる」「電話は取られない」のだとすると、皆がもっと良く見るところに通知すれば、お互いに声を掛け合って安否確認できるのではないか、と考えました。
そこで、部員が全員使っているSlackに、緊急事態を煽るように通知すれば、回答率を高められるのではないかと思い、AWSのサーバレスアーキテクチャを駆使して、安否確認連絡をSlackに通知するようにしてみました。
安否確認をSlackに流すサーバレスアーキテクチャ
以下の図のように、安否確認システムが発送したメールを、Amazon SESのメール受信機能で受け、メール受信イベントでAWS Lambdaをトリガーして、LambdaからWebhookでSlackに通知します。
作り方
注: AWSのリージョンはus-east-1となります。
1. SlackのIncoming Webhookが使えるようにする
以下の記事に最高に詳しくまとめられています。
slackのIncoming webhookが新しくなっていたのでまとめてみた
https://qiita.com/kshibata101/items/0e13c420080a993c5d16
この記事の解説を読みながら、SlackにIncoming Webhookで通知するためのアプリを作成します。
その後、**#general(または全員が参加しているチャンネル)**に通知するためのWebhook URLを取得します。
こんな感じでWebhook URLが取れますのでコピーしておきます。
2. Lambda Functionを作る
Lambda Functionの環境変数SOURCE_MAIL_ADDRESS
に送信元メールアドレス(安否確認システムのメールアドレス)、WEBHOOK_URL_OF_SLACK
にSlackのWebhook URLを指定します。
urllib.requestを使ってWebhook URLに通知を流し込みます。
悪用防止の為、Amazon SESのメール受信イベントで送信元メールアドレスを判定し、安否確認システムからのメールのみ処理するようにしています。
また、通知メッセージはコードに埋め込みましたが、お好みで外部化したり、カスタマイズできます。
# -*- coding: utf-8 -*-
import datetime
import traceback
import urllib.request
import json
import os
# ロギング用関数
def logging(errorLv, lambdaName, errorMsg):
loggingDateStr=(datetime.datetime.now()).strftime('%Y/%m/%d %H:%M:%S')
print(loggingDateStr + " [" + errorLv + "] " + lambdaName + " " + errorMsg)
return 0
# Lambdaハンドラ
def lambda_handler(event, context):
logging("info", context.function_name, "実行開始")
try:
# メールの情報からソースメールアドレスを抽出
source = event["Records"][0]["ses"]["mail"]["source"]
# ソースメールアドレスをチェック
if source == os.environ['SOURCE_MAIL_ADDRESS']:
# Slack投稿用Data (textをお好みで変更可能)
slackData = {
"text": "安否確認メールが発報されました。至急、メールボックスを確認し、回答してください。",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": '*【プロパー宛】*\n*安否確認メールが発報されました。*\n*至急、メールボックスを確認し、回答してください。*\n※協力会社の方も、各社毎の安否確認の対応をお願いします。'
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": '*<https://xxxxx.co.jp|エマージェンシーコール>*\n安否確認システムからの緊急連絡です。'
}
},
{
"type": "divider"
},
{
"type": "context",
"elements": [
{
"type": "image",
"image_url": "https://a.slack-edge.com/80588/img/blocks/bkb_template_images/notificationsWarningIcon.png",
"alt_text": "notifications warning icon"
},
{
"type": "mrkdwn",
"text": '*緊急アラートです。至急の回答が必要です。*'
}
]
}
]
}
# Slackに投稿
headers = {
'Content-Type': 'application/json'
}
postRequest = urllib.request.Request(os.environ['WEBHOOK_URL_OF_SLACK'], data=json.dumps(slackData).encode("utf-8"), method="POST", headers=headers)
tempResponse = bytes()
with urllib.request.urlopen(postRequest) as postResponse:
tempResponse += postResponse.read()
if (str(tempResponse, encoding='utf-8') != 'ok'):
raise Exception("Invalid Response from " + os.environ['WEBHOOK_URL_OF_SLACK'])
response = {}
response.update([('response', 'OK'), ('request', slackData)])
logging("info", context.function_name, "Slackチャンネルへの投稿完了:" + str(response))
logging("info", context.function_name, "実行終了")
return response
else:
raise ValueError("Receiving mail from an invalid address")
except Exception as OtherException:
# error時. lambda_handlerは、Pythonの標準エラーをエラーログに出力する
logging("error", context.function_name, str(OtherException).replace("\n",""))
logging("info", context.function_name, "実行終了")
return {"errorMessage": str(OtherException)}
3. SESでドメインを設定し、受信ルールを設定
公式ドキュメントの解説に従って、簡単に設定できます。
AWSマネジメントコンソールのSESの画面で設定します。
まず、Route 53 を使用してドメインを購入および登録します。
2019/10時点では「.de」が年間$9.00で購入でき、最安値のようです。
https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/domain-register.html
次に、SESでドメインを検証します。
こちらも、解説に従って実施するだけなので簡単です。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/receiving-email-getting-started-verify.html
最後に受信ルールの設定ですが、以下の解説に従います。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/receiving-email-receipt-rules.html
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/receiving-email-action-lambda.html
Recipientには、安否確認メールを受信するメールアドレスを書きます。(受信用のメールアドレスはここで決めます)
次にActionはLambdaを選び、1で開発したLambda Functionを選択し、Invocation typeはEventにします。
※Lambda Functionの名前は各自によります。画像では、Cloud9で開発したため「cloud9-」という名前になっています。
ここまでの設定が完了すれば、AWSサーバレスアーキテクチャの実装は完成です。
4. 安否確認システムのメール送信先に、SES受信用メールアドレスを追加
これを忘れると意味がありませんので、ちゃんと設定しておきます。
Slackに通知される様子
安否確認システムからメールが送信されると、以下のようにSlackに通知されるようになりました。
もちろん、スマホにも通知が飛んできます。
自社の安否確認システムなので、システム的には自社プロパー宛の点呼になるのですが、Slackに連携させるにあたり、協力会社の方にも呼びかけをするようにしています。
補足
1. Slackのメール受信機能ではダメなのか?
以下のSlack公式サイト上では、Slackでメールを受信する方法が書かれていますが、blocksのmrkdwn等で自由に通知フォーマットをカスタマイズしたいとなると、今回のような方法を取る必要があります。
「Slack でメールを受信する」
https://slack.com/intl/ja-jp/help/articles/206819278-slack-%E3%81%A7%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E5%8F%97%E4%BF%A1%E3%81%99%E3%82%8B
フォーマットをカスタマイズするには、前述のコードのJSONの部分を変えます。
カスタマイズできる方が、何かと便利ですね。
2. 安否確認はそもそも個人宛ではないのか?
その通りです。
つまり、チャンネル毎に誰か1人が、この仕組みで作成したSESの受信用メールアドレスを安否確認の送信先に設定すれば、Slackに通知されるようになります。
同じチャンネルで全員が設定すると複数件通知されますので、チャンネル毎に誰か1人でOKです。
最後に
余談ですが、この仕組みを作りながら、会社の安否確認にどんな意義があるのだろうと、立ち返り、調べてみました。
従業員の安全を守ることは、経営者の務めだといえる
(略)公益財団法人 ひょうご震災記念21世紀研究機構 人と防災未来センターが行った調査で『BCPを決めているかどうかは別にして、災害発生を想定した対策をとっているか』という質問への回答です。実に95.5%もの企業が『社員の安否確認の手法・手段』を定めています。その背景には、事業を続ける施設が残っても、そこで働く人がいなくなっては、事業を続けることができないという現実があります。そして、経営者は従業員を守る責務があり、事業を継続することで働く場を提供する義務もあるのです。
https://www.kddi.com/business/column/20180620/security-verification/
様々に意見はあるのでしょうが、安否確認の回答率を上げることで、組織のメンバーや大事な人の命を守ることができるならば、その回答率を上げることに意義があると、私は考えました。
自社内のSlackは、単なるコミュニケーションツールだけでなく、RSS等による情報収集ツールとしても機能し、アクティブユーザが多い傾向にあります。
その性質を逆手に取り、安否確認をSlackに飛ばすことで、回答率を増やそうと試みました。
最近だと、社内のコミュニケーションでメールよりもSlackが使われる事例が増えてきていると思いますので、このような仕組みにより、万が一の災害時の安否確認がより確かに行われればと思いました。
なお、安否確認システムにAmazon Connectの電話番号を登録するというアーキテクチャも考えられましたが、冷静に考えた結果、見送っています。