🙆

[Terraform]AWS Budgetアラート通知をSNS,Chatbot経由でSlack通知

2024/09/16に公開

前提

  • terraformにおけるprovider等の準備段階で必要な設定の記載は省略しています。

要件

  • AWSの月次使用金額の状況を把握したい.
  • 段階ごとに設定したBudgetの閾値を超過した場合はSlackへアラート通知を行いたい。

構成

結果イメージ

  • 以下画像のようにBudgetで設定した閾値を超過した際にSLack通知が飛ぶこと。

 

Slackで予め必要な設定

1.slack app directoryにて、AWS Chatbotを自身のSlackワークスペースで使用出来るよう承認、追加する。

https://slack.com/intl/ja-jp/help/articles/222386767-ワークスペースで使用するアプリの承認を管理する

2.通知するSlackチャンネルのインテグレーションに追加する。

  • 筆者の環境では、既に複数アプリケーションを追加しているため、画像の内容が厳密に同じである必要はないです。


     

コード

Budget

  • 月額30$を予算とし、アラートを発砲する閾値を2$,10$,20$,30$で設定。
  • アラートの通知先は、SNSに設定。
budget.tf
locals {
  monthly_budget = {
    test   = 2  # ブログの画像用に少額で設定。
    low    = 10
    middle = 20
    high   = 30
  }
}

resource "aws_budgets_budget" "notify_slack" {
  name              = "monthly-budget"
  budget_type       = "COST"
  limit_amount      = 30 # 予算値を30$に設定
  limit_unit        = "USD"
  time_period_start = "2024-08-01_00:00" # 適用開始をブログに掲載している年月へ設定
  time_unit         = "MONTHLY"

  cost_types {
    include_tax     = true # デフォルトでtrueだが、コードを見れば分かるよう明示的に記載している
    include_support = true
  }

  # SNS通知の設定
  # 最小のコード量で済むよう、dynamicブロック使用。
  dynamic "notification" {
    for_each = { for k, v in local.monthly_budget : k => v }
    content {
      comparison_operator = "GREATER_THAN"
      notification_type   = "ACTUAL"
      threshold           = notification.value
      threshold_type      = "ABSOLUTE_VALUE"
      subscriber_sns_topic_arns = [aws_sns_topic.slack_alert.arn]
    }
  }
}

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/budgets_budget

SNS

sns.tf
resource "aws_sns_topic" "slack_alert" {
  name     = "slack-alert"
  provider = aws.us-east-1
}

resource "aws_sns_topic_policy" "slack_alert" {
  arn = aws_sns_topic.slack_alert.arn
  provider = aws.us-east-1
  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = {
          Service = "budgets.amazonaws.com"
        },
        Action = "SNS:Publish",
        Resource = aws_sns_topic.slack_alert.arn,
        Condition = {
          StringEquals = {
            "aws:SourceAccount" = data.aws_caller_identity.self.account_id
          }
        }
      }
    ]
  })
}

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_policy

Chatbot

  • Chatbotの権限は、ガードレールポリシーの範囲内でIAMロールで設定した権限を行使する事が出来る。
chatbot.tf
locals {
  chatbots = {
    my_account = {
      name               = "budget-alert-notify"
      slack_workspace_id = "{通知したいSlackのワークスペースIDを記載}"
      slack_channel_id   = "{通知したいSlackチャンネルIDを記載}"
    }
  }
}

resource "awscc_chatbot_slack_channel_configuration" "notify_slack" {
  for_each           = { for k, v in local.chatbots : k => v }
  configuration_name = each.key
  iam_role_arn       = aws_iam_role.chatbot.arn
  guardrail_policies = [
    "arn:aws:iam::aws:policy/ReadOnlyAccess",
  ]
  slack_channel_id   = each.value.slack_channel_id
  slack_workspace_id = each.value.slack_workspace_id
  logging_level      = "ERROR"
  sns_topic_arns     = [aws_sns_topic.slack_alert.arn]
  user_role_required = true

  tags = [
    {
      key   = "Name"
      value = each.key
    }
  ]
}

https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/chatbot_slack_channel_configuration

  • Chatbotに設定するIAMロール
iam.tf
resource "aws_iam_role" "chatbot" {
  name                  = "AWSChatbot-role"
  description           = "AWS Chatbot Execution Role"
  path                  = "/service-role/"
  force_detach_policies = false
  max_session_duration  = 3600

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "chatbot.amazonaws.com"
        }
      }
    ]
  })
}

# 想定外のエラーにならないよう、デフォルトのテンプレートポリシーに沿った設定しているためワイルドーカードで定義している。
#tfsec:ignore:aws-iam-no-policy-wildcards
data "aws_iam_policy_document" "chatbot" {
  statement {
    actions = [
      "cloudwatch:Describe*",
      "cloudwatch:Get*",
      "cloudwatch:List*"
    ]
    effect    = "Allow"
    resources = ["*"]
  }
}

resource "aws_iam_role_policy" "chatbot" {
  name   = aws_iam_role.chatbot.name
  role   = aws_iam_role.chatbot.name
  policy = data.aws_iam_policy_document.chatbot.json
}

 

SlackワークスペースとChatbotの関連付け

1.AWSマネジメントコンソール画面でChatbotの画面へ遷移

2.設定済みクライアントを選択し、以下画像の流れで関連付けを行う。

※注意

エラーメッセージ
Error: AWS SDK Go Service Operation Incomplete
Waiting for Cloud Control API service CreateResource operation completion returned: waiter state transitioned to FAILED. StatusMessage:
# 以下省略
GitHubで編集を提案

Discussion