SNS から Slack に通知する Lambda を CloudFormation で作成できるようにしたのでテンプレートについて解説します。
CloudFormation テンプレート
- Slack のチャンネル、Webhook は CloudFormation のパラメータとして定義し Lambda の環境変数に埋め込みます。
- Lambda 関数は Lambda > 関数 > 関数の作成 > 設計図の使用 > cloudwatch-alarm-to-slack-python をベースに作成しました。
AWSTemplateFormatVersion: 2010-09-09
Parameters:
System:
Type: String
Default: sample
Description: System name.
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- qa
- prod
Description: Environment name. Choose from [dev, qa, prod].
SlackChannel:
Type: String
Default: your-slack-channnel
Description: Slack channel.
SlackWebhook:
Type: String
Default: https://hooks.slack.com/services/XXXXXXXXXXX/XXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX
Description: Slack webhook url.
Resources:
SNSToSlackLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${Environment}-${System}-sns-to-slack"
Handler: index.lambda_handler
# Lambda 用の IAM Role を指定します。
Role: arn:aws:iam::012345678901:role/your-lambda-role
Environment:
Variables:
SlackChanel: !Ref SlackChannel
SlackWebhook: !Ref SlackWebhook
Code:
ZipFile:
Fn::Join:
- "\n"
- - 'import boto3'
- 'import json'
- 'import logging'
- 'import os'
- ''
- 'from urllib.request import Request, urlopen'
- 'from urllib.error import URLError, HTTPError'
- ''
- '# The Slack channel to send a message to stored in the slackChannel environment variable'
- 'SLACK_CHANNEL = os.environ["SlackChanel"]'
- 'HOOK_URL = os.environ["SlackWebhook"]'
- ''
- 'logger = logging.getLogger()'
- 'logger.setLevel(logging.INFO)'
- ''
- 'def lambda_handler(event, context):'
- ' """'
- ' Lambda > 関数 > 関数の作成 > 設計図の使用 > cloudwatch-alarm-to-slack-python をベースに作成。'
- ' CloudFormation のパラメータとして定義した Webhook の URL を参照して SNS のメッセージを Slack 通知する。'
- ' """'
- ' logger.info("Event: " + str(event))'
- ' message = json.loads(event["Records"][0]["Sns"]["Message"])'
- ' logger.info("Message: " + str(message))'
- ''
- ' alarm_name = message["AlarmName"]'
- ' #old_state = message["OldStateValue"]'
- ' new_state = message["NewStateValue"]'
- ' reason = message["NewStateReason"]'
- ''
- ' slack_message = {'
- ' "channel": SLACK_CHANNEL,'
- ' "text": "%s state is now %s: %s" % (alarm_name, new_state, reason)'
- ' }'
- ''
- ' req = Request(HOOK_URL, json.dumps(slack_message).encode("utf-8"))'
- ' try:'
- ' response = urlopen(req)'
- ' response.read()'
- ' logger.info("Message posted to %s", slack_message["channel"])'
- ' except HTTPError as e:'
- ' logger.error("Request failed: %d %s", e.code, e.reason)'
- ' except URLError as e:'
- ' logger.error("Server connection failed: %s", e.reason)'
- ''
Runtime: python3.7
Timeout: 180
MemorySize: 128
Tags:
- Key: !Ref CostTagKey
Value: !Ref CostTagValue
SNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName:
!Sub "${Environment}-{System}-sns"
DisplayName:
!Sub "${Environment}-{System}-sns"
Subscription:
- Endpoint: !GetAtt SNSToSlackLambdaFunction.Arn
Protocol: lambda
SNSToSlackLambdaPermission:
Type: 'AWS::Lambda::Permission'
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !Ref SNSToSlackLambdaFunction
Principal: 'sns.amazonaws.com'
SourceAccount: !Ref AWS::AccountId
SourceArn:
Fn::ImportValue: !Sub "${Environment}-${System}-sns"
Outputs:
SNSToSlackLambdaFunctionArn:
Value: !GetAtt SNSToSlackLambdaFunction.Arn
Export:
Name: !Sub "${Environment}-${System}-sns-to-slack-arn"
SNSTopic:
Value: !Ref SNSTopic
Export:
Name: !Sub "${Environment}-${System}-sns"
以下のリソースが作成されます。
- SNS
- Topic
${Environment}-${System}-sns
- Topic
- Lambda
- 関数
${Environment}-${System}-sns-to-slack
- トリガー
SNS: ${Environment}-${System}-sns
- 関数
疎通確認
- Amazon SNS > トピック >
${Environment}-${System}-sns
> メッセージの発行 - メッセージ本文に JSON のサンプルを入力しメッセージの発行を行います。
- Slack に
test-alarm state is now test-new-state: test-new-state-reason
のようにメッセージが通知されます。
{
"AlarmName": "test-alarm",
"NewStateValue": "test-new-state",
"NewStateReason": "test-new-state-reason"
}