Serverless Framework で AWS Chatbot と Amazon SNS のリソースを作成してみた

Serverless Framework で AWS Chatbot と Amazon SNS のリソースを作成してみよう
2022.07.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、サービスグロースチームの筧です。

「大量の Lambda 関数から CloudWatchLogs の Error などを取得して Slack に通知したい」

って思ったことありませんか? ソリューションの一つとして、Lambda 関数を CloudWatch アラームでモニタリングし、Amazon SNS 経由で AWS Chatbot で通知する方法があります。

Lambda 関数を 、AWS Chatbot で通知を受け取る | Amazon Web Services ブログ

上記ブログののソリューションでは、モニタリングしたい Lambda 関数を指定したい際に、 CloudFormation のパラメータに、Lambda 関数名をカンマ区切りリストで入力しています。 こちらのソリューションの利用を検討した際に、モニタリングしたい Lambda 関数をパラメータ入力ではなく、 自動的に追加されるような機能があれば、メンテナンスが減って更に良いなと思いました。

現在、上記を実現するべく PoC を作成しています。PoC の内容は以下の通りです。

  • 以下のリソースを Serverless Framework の resources として作成
    • Amazon SNS Topic
    • AWS Chatbot SlackChannelConfiguration
    • IAM Role(上記 AWS Chatbot 設定用の IAM Role)
  • 以下の機能を持つ Lambda 関数を Serverless Framework の functions として作成
    • CloudWatch アラーム未設定の Lambda 関数に、CloudWatch アラームを自動設定機能
    • 作成した CloudWatch アラームを一括削除機能

今回は前者の Serverless Framework の resources を作成する箇所をご紹介します。 後者の functions は次のブログで紹介予定です。

前提

筆者の環境

ターミナル

% sw_vers
ProductName:    macOS
ProductVersion: 12.2.1
BuildVersion:   21D62
% sls --version
Framework Core: 3.19.0 (local) 3.19.0 (global)
Plugin: 6.2.2
SDK: 4.3.2
% pipenv --version
pipenv, version 2022.6.7

やってみた

AWS Chatbot から Slack への接続を確立

AWS Chatbot から Slack への接続を確立は、コンソールで事前に設定しておく必要があります。 設定方法は先程紹介したブログを参照ください。 Slack チャンネル ID とワークスペース ID を利用するのでメモしておきます。

Lambda 関数を 、AWS Chatbot で通知を受け取る | Amazon Web Services ブログ

ワークスペース ID を取得するには、コンソールの AWS Chatbot サービスにアクセスしてください。

チャットクライアントで AWS Chatbot の設定を開始するには、AWS Chatbot コンソールで [Configure new client] を選択し、[Amazon Chime] または [Slack] を選択します。 セットアップウィザードで Slack OAuth 2.0 のページにリダイレクトされます。右上隅で設定する Slack ワークスペースを選択し、「Agree」を選択します。Slack ワークスペースが AWS Slack アプリをインストールします。 ワークスペース ID を書き留めておきます (例:T01UXHUCRMW)。これは、後で CloudFormation テンプレートをデプロイするときに必要になります。 Slack チャンネル ID を取得するため、デスクトップアプリまたはウェブ上の Slack にアクセスしてください。チャンネルを右クリックして、リンクをコピーします。コピーされたリンクの最後の部分がチャネル ID です(たとえば、C01U80K9KPD)。

パラメータストアの設定

上記でメモした Slack チャンネル ID とワークスペース ID を AWS Systems Manager のパラメータストアに格納します。

  • Slack チャンネル ID
    • 名前: /alert-lambda/ステージ名/SLACK_CHANNEL_ID
    • 値(例): C01U80K9KPD
  • ワークスペース ID
    • 名前: /alert-lambda/ステージ/SLACK_WORKSPACE_ID
    • 値(例): T01UXHUCRMW

serverless.yml

serverless.yml

service: alert-lambda
frameworkVersion: '3'
provider:
  name: aws
  runtime: python3.9
  lambdaHashingVersion: 20201221
  stage: ${opt:stage, 'dev'}
  region: ${opt:region, "ap-northeast-1"}
  memorySize: 256
  iam:
    role:
      statements:
        - Effect: 'Allow'
          Action:
            - 'ssm:GetParameter'
            - 'sts:AssumeRole'
            - 'logs:DescribeLogGroups'
            - 'cloudwatch:DescribeAlarms'
            - 'cloudwatch:PutMetricAlarm'
            - 'cloudwatch:DeleteAlarms'
            - 'lambda:ListFunctions'
          Resource:
            - '*'
  environment: ${self:custom.environment}
functions:
  add:
    handler: src/handlers/add.handler
    timeout: 300
  delete:
    handler: src/handlers/delete.handler
    timeout: 300
  create_error:
    handler: src/handlers/create_error.handler
    timeout: 60
plugins:
  - serverless-step-functions
  - serverless-python-requirements
  - serverless-prune-plugin
stepFunctions: ${file(includes/state-machines.yml)}
custom:
  pythonRequirements:
    usePipenv: true
  prune:
    automatic: true
    number: 3
  environment:
    STAGE: ${self:provider.stage}
    SLACK_CHANNEL_ID: ${ssm(${self:provider.region}):/${self:service}/${self:provider.stage}/SLACK_CHANNEL_ID}
    SLACK_WORKSPACE_ID: ${ssm(${self:provider.region}):/${self:service}/${self:provider.stage}/SLACK_WORKSPACE_ID}
    SNS_TOPIC_ARN:
      Ref: AlertLambdaTopic
package:
  patterns:
    - '!./**'
    - ./src/**/*.py
resources:
  Conditions:
    CreateTokyoResources:
      Fn::Equals:
        - !Ref AWS::Region
        - ap-northeast-1
  Resources:
    AlertLambdaTopic:
      Type: "AWS::SNS::Topic"
      Properties:
        DisplayName: "AlertLambda-${self:provider.stage}-${self:provider.region}"
        TopicName: "AlertLambdaTopic-${self:provider.stage}-${self:provider.region}"
    AlertLambdaChatbotRole:
      Type: "AWS::IAM::Role"
      Condition: CreateTokyoResources
      Properties:
        RoleName: "AlertLambdaChatbotRole-${self:provider.stage}"
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Principal:
                Service: chatbot.amazonaws.com
              Action: sts:AssumeRole
        Policies:
          - PolicyName: "AlertLambdaChatbotPolicy-${self:provider.stage}"
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: Allow
                  Action:
                    - cloudwatch:Describe*
                    - cloudwatch:Get*
                    - cloudwatch:List*
                    - logs:Describe*
                    - logs:Get*
                    - logs:List*
                    - logs:StartQuery
                    - logs:StopQuery
                    - logs:TestMetricFilter
                    - logs:FilterLogEvents
                  Resource:
                    - "*"
    AlertLambdaChatbot:
      Type: "AWS::Chatbot::SlackChannelConfiguration"
      Condition: CreateTokyoResources
      Properties:
        ConfigurationName: "AlertLambdaChatbot-${self:provider.stage}"
        GuardrailPolicies:
          - "arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess"
        IamRoleArn: !GetAtt AlertLambdaChatbotRole.Arn
        LoggingLevel: INFO
        SlackChannelId: "${self:custom.environment.SLACK_CHANNEL_ID}"
        SlackWorkspaceId: "${self:custom.environment.SLACK_WORKSPACE_ID}"
  • provider.iam.role には、次回作成する Lambda 関数で必要なロールなどを定義しています。
  • 環境変数の SLACK_CHANNEL_ID と SLACK_WORKSPACE_ID は、Serverless Framework で用意されている構文を使い、パラメータストアに保管したクレデンシャル情報を参照しています。SLACK_CHANNEL_ID には通知先の Slack チャンネル ID を値に設定します。SLACK_WORKSPACE_ID には、AWS Chatbot の設定時に作成された ワークスペース ID を値に設定します。

Reference Variables using the SSM Parameter Store | Serverless Framework

  • resources で定義した、Amazon SNS Topic の ARN は Ref を利用して環境変数で参照しています。このやり方については以下のブログもよかったら参照ください。

Serverless Framework で resources に定義したリソースを環境変数で参照しようとした時に、エラーが発生した場合の対処方法 | Serverless Framework

おわりに

最後まで読んでいただきありがとうございます。

  • 以下の機能を持つ Lambda 関数を Serverless Framework の functions として作成
    • CloudWatch アラーム未設定の Lambda 関数に、CloudWatch アラームを自動設定機能
    • 作成した CloudWatch アラームを一括削除機能

上記内容は以下のブログを参照ください。

既存の大量の Lambda 関数に、Errors と Throttles メトリクスのアラーム通知設定を自動で行う

本ブログが少しでも皆さんの役立っていると幸いです。 それではまた!