CloudFormationでAWS Budgets の予算超過アラートを Slack へ通知してみた

AWS Budgetsの予算アラートをCloudFormationを使って簡単にSlackへ通知させてみました。
2021.02.28

こんにちは、コンサルティング部の鈴木(純)です。

いくつもAWSアカウントを管理しているとき、どのアカウントでどのくらいのAWS利用料になっているか気になることってありませんか?私は最近ちょっと検証用などのAWSアカウントの数が増えてきていて、どのくらい利用料になっているか時々不安になることがありました。

そんな時にAWS Budgetsの予算超過アラートの機能を使うことで、Slackに通知できると聞いたので、CloudFormation一発で展開できるテンプレートを作成してみました。

やりたいこと

  • 予算を設定してしきい値を超えたらSlackにアラートを通知する
  • 実際の月額利用料を計測

ゴールイメージはこんな感じ

前準備

CloudFormationを展開する前にいくつか前準備が必要です。

Chatbotのワークスペースを作成

Slackへ通知する時にはChatbotを経由して通知をするため、最初にワークスペースを作成します。

Chatbotをコンソールから開いて「新しいクライアントを設定」をクリックします。

ChimeかSlackか選択画面が出るので、Slackを選択して設定。

連携先のSlackワークスペースへのリクエスト画面になるので、①今回通知させたいチャンネルがあるワークスペースを選択して、②許可するをクリックして下さい。

そうすると、以下のようにChatbot上でワークスペースIDが確認できるので、このIDを控えておきましょう。

通知先のSlackチャンネルのIDを取得する

通知先のSlackチャンネルIDを取得する必要があるので、通知させたいチャンネルを右クリックして「リンクのコピー」をして下さい。

そうするとhttps://testworkspace.slack.com/archives/AAAAAAAAAのようなURLがコピーされるので、末尾のAに該当する9桁をコピーしておいて下さい。

AAAAAAAAAがSlackチャンネルのIDになります。

CloudFormationを展開する

テンプレート

テンプレートはこんな感じです。

AWSTemplateFormatVersion: 2010-09-09
Description:
  'Notify Slack of monthly usage fees'

Parameters:
  TargetWorkspaceId:
    Description: Chatbot workspace ID
    Type: String

  TargetChannelId:
    Description: Slack channel ID
    Type: String

  BudgetAmount:
    Description: Please specify the budget amount in USD
    Type: String

  BudgetThreshold:
    Description: Please specify the threshold you want to be notified in %
    Type: String

Resources:

  SnsTopic:
    Type: AWS::SNS::Topic
    Properties: 
      DisplayName: notification-to-slack-topic
      TopicName: notification-to-slack-topic

  SnsTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties: 
      PolicyDocument: 
          {
      "Version": "2008-10-17",
      "Id": "__default_policy_ID",
      "Statement": [
        {
          "Sid": "E.g., AWSBudgetsSNSPublishingPermissions",
          "Effect": "Allow",
          "Principal": {
            "Service": "budgets.amazonaws.com"
          },
          "Action": "SNS:Publish",
          "Resource": !Sub "arn:aws:sns:ap-northeast-1:${AWS::AccountId}:notification-to-slack-topic"
        },
        {
          "Sid": "__default_statement_ID",
          "Effect": "Allow",
          "Principal": {
            "AWS": "*"
          },
          "Action": [
            "SNS:GetTopicAttributes",
            "SNS:SetTopicAttributes",
            "SNS:AddPermission",
            "SNS:RemovePermission",
            "SNS:DeleteTopic",
            "SNS:Subscribe",
            "SNS:ListSubscriptionsByTopic",
            "SNS:Publish",
            "SNS:Receive"
          ],
          "Resource": "arn:aws:sns:ap-northeast-1:${AWS::AccountId}:notification-to-slack-topic",
          "Condition": {
            "StringEquals": {
              "AWS:SourceOwner": !Ref "AWS::AccountId"
            }
          }
        }
      ]
    }
      Topics: 
        - !Ref SnsTopic

  Chatbot:
    Type: AWS::Chatbot::SlackChannelConfiguration
    Properties: 
      ConfigurationName: ChatbotForCloudFormation
      IamRoleArn: !GetAtt ChatbotIamRole.Arn
      LoggingLevel: INFO
      SlackChannelId: !Ref TargetChannelId
      SlackWorkspaceId: !Ref TargetWorkspaceId
      SnsTopicArns: 
        - !Ref SnsTopic

  ChatbotIamRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: AWSChatBot-For-Budgets
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: chatbot.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: chatbot-iam-policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - cloudwatch:Describe*
                  - cloudwatch:Get*
                  - cloudwatch:List*
                Resource:
                  - "*"
  Budget:                
    Type: AWS::Budgets::Budget
    Properties: 
      Budget: 
        BudgetLimit:
          Amount: !Ref BudgetAmount
          Unit: USD
        BudgetType: COST
        BudgetName: 'Monthly usage'
        TimeUnit: MONTHLY
      NotificationsWithSubscribers: 
        - Notification:
            NotificationType: ACTUAL
            ComparisonOperator: GREATER_THAN
            Threshold: !Ref BudgetThreshold
            ThresholdType: PERCENTAGE
          Subscribers:
          - SubscriptionType: SNS
            Address: !Ref SnsTopic

コンソールからこのテンプレートを展開してみます。

パラメータ

以下4つのパラメータを入力します。

  • BudgetAmount(予算額 USD)
  • BudgetThreshold(アラートのしきい値 %)
  • TargetChannelId(SlackチャンネルID)
  • TargetWorkspaceId(ChatbotのワークスペースID)

今回は10$超えている環境でテストしていたので、そのまま予算額を10$にしてしきい値は適当に80%としました。

その他はデフォルトのまま最後に「IAM リソースがカスタム名で作成される場合があることを承認します。」にチェックを入れてスタックを作成すれば完了です。

出力結果

スタック作成が完了するとすぐに通知がSlackに飛びました。今回のように既にアラートのしきい値を超えている場合は、スタック展開直後に通知が飛んでくると思います。

ちゃんと設定した予算としきい値、実際の利用料が表示されていますね。かなり手軽にアラートを通知させることができるので、みなさんも是非お試し下さい。

参考情報

DevelopersIO

  • Slackじゃなくてメールで通知させたい

  • 同じ構成でコンソールから通知を試したい

公式ドキュメント