SNSからSlackに通知するLambdaをCloudFormationで作成する方法まとめ

SNS

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
  • 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"
}
タイトルとURLをコピーしました