⚠️

「AWSのコストが設定した閾値以上になったらSlackに通知するリソース群」をCloudFormationで作成する

2024/10/21に公開

概要

予想外のコストがかかり出したら一刻も早く知りたいですよね。
というわけで、その日の予算に対して n %を超えたらSlackの指定チャンネルに通知してくれる仕組みを作りました。

予算には固定値も設定できるのですが、担当しているプロジェクトでは「過去30日の移動平均」をその日の予算としました。

パラメータとして以下の4つを受け取る仕様にしました。

  • 環境名(リソースへの命名に使用)
  • SlackワークスペースID
  • SlackチャンネルID
  • 予算の何%でアラートを鳴らすか

yamlの全貌

billing-alert.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Alert via Slack when AWS cost increases

Parameters:
  EnvironmentName:
    Description: An environment name that will be prefixed to resource names
    Type: String
    Default: stg
    AllowedValues:
      - stg
      - prd
  SlackWorkspaceID:
    Description: Workspace ID to send billing alert
    Type: String
  SlackChannelID:
    Description: Channel ID to send billing alert
    Type: String
  AlertThresholdPerBudget:
    Type: Number
    Default: 110

Resources:
  SlackNotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub ${EnvironmentName}-billing-alert-topic

  TopicPolicyForBilling:
    Type: AWS::SNS::TopicPolicy
    Properties:
      Topics:
        - !Ref SlackNotificationTopic
      PolicyDocument:
        Statement:
          - Sid: "AWSBudgetsSNSPublishingPermissions"
            Effect: Allow
            Principal:
              Service: budgets.amazonaws.com
            Action: SNS:Publish
            Resource: !Ref SlackNotificationTopic
            Condition:
              StringEquals:
                aws:SourceAccount: !Sub ${AWS::AccountId}
              ArnLike:
                aws:SourceArn: !Sub arn:aws:budgets::${AWS::AccountId}:*

  Budget:
    Type: AWS::Budgets::Budget
    Properties:
      Budget:
        BudgetName: !Sub ${EnvironmentName}-budget
        BudgetType: COST
        TimeUnit: DAILY
        AutoAdjustData:
          AutoAdjustType: HISTORICAL
          HistoricalOptions:
            BudgetAdjustmentPeriod: 30
        CostTypes:
          IncludeTax: false
      NotificationsWithSubscribers:
        - Notification:
            NotificationType: ACTUAL
            ComparisonOperator: GREATER_THAN
            Threshold: !Ref AlertThresholdPerBudget
            ThresholdType: PERCENTAGE
          Subscribers:
            - SubscriptionType: SNS
              Address: !GetAtt SlackNotificationTopic.TopicArn

  BillingSlackChannelConfig:
    Type: AWS::Chatbot::SlackChannelConfiguration
    Properties:
      ConfigurationName: !Sub ${EnvironmentName}-billing-alert-configuration
      IamRoleArn: !GetAtt BillingAlertIAMRole.Arn
      SlackChannelId: !Ref SlackChannelID
      SlackWorkspaceId: !Ref SlackWorkspaceID
      SnsTopicArns:
        - !Ref SlackNotificationTopic

  BillingAlertIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: chatbot.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: !Sub ${EnvironmentName}-BillingAlertPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - sns:Publish
                Resource: !Ref SlackNotificationTopic

参考

https://docs.aws.amazon.com/ja_jp/cost-management/latest/userguide/sns-alert-chime.html

Discussion