どうも、ちゃだいん(@chazuke4649)です。
AWS Cost Anomaly Detection を AWS Chatbot で Slack 通知させるリソース一式を Terraform で作りました。
ほぼ、以下ブログのTerraform版です。
手順
- AWS ChatbotにSlackワークスペースを登録する
- Terraformコードの適用する
- 通知テストする
1. AWS ChatbotにSlackワークスペースを登録する
まだ、AWS ChatbotにSlackワークスペースを登録していない場合は、Chatbotコンソールより実施します。
※詳細は割愛します
2. Terraformコードの適用する
メインとなるTerraoformコードは以下となります。
cost_anomaly_detection.tf
###############################################################################
# Cost Anomaly Detection
###############################################################################
resource "aws_ce_anomaly_monitor" "default" {
name = "default"
monitor_type = "DIMENSIONAL"
monitor_dimension = "SERVICE"
}
resource "aws_ce_anomaly_subscription" "default" {
name = "default"
frequency = "IMMEDIATE"
threshold_expression {
dimension {
key = "ANOMALY_TOTAL_IMPACT_PERCENTAGE"
values = ["50.0"]
match_options = ["GREATER_THAN_OR_EQUAL"]
}
}
monitor_arn_list = [aws_ce_anomaly_monitor.default.arn]
subscriber {
type = "SNS"
address = aws_sns_topic.cost_anomaly.arn
}
}
###############################################################################
# SNS Topic
###############################################################################
resource "aws_sns_topic" "cost_anomaly" {
name = "cost_anomaly"
}
data "aws_iam_policy_document" "sns_cost_anomaly" {
statement {
effect = "Allow"
resources = [aws_sns_topic.cost_anomaly.arn]
actions = ["sns:Publish"]
principals {
type = "Service"
identifiers = [
"costalerts.amazonaws.com",
]
}
}
}
resource "aws_sns_topic_policy" "sns_cost_anomaly" {
arn = aws_sns_topic.cost_anomaly.arn
policy = data.aws_iam_policy_document.sns_cost_anomaly.json
}
###############################################################################
# Chatbot
###############################################################################
data "aws_iam_policy_document" "cloudwatch_access" {
statement {
effect = "Allow"
resources = ["*"]
actions = [
"cloudwatch:Describe*",
"cloudwatch:Get*",
"cloudwatch:List*",
]
}
}
resource "aws_iam_policy" "chatbot_role" {
name = "chatbot"
policy = data.aws_iam_policy_document.cloudwatch_access.json
}
data "aws_iam_policy_document" "chatbot_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["chatbot.amazonaws.com"]
}
}
}
resource "aws_iam_role_policy_attachment" "chatbot_role" {
role = aws_iam_role.chatbot_role.name
policy_arn = aws_iam_policy.chatbot_role.arn
}
resource "aws_iam_role" "chatbot_role" {
name = "chatbot"
assume_role_policy = data.aws_iam_policy_document.chatbot_role.json
}
resource "aws_cloudformation_stack" "chatbot" {
name = "chatbot"
template_body = yamlencode({
Description = "Managed by Terraform"
Resources = {
AlertNotifications = {
Type = "AWS::Chatbot::SlackChannelConfiguration"
Properties = {
ConfigurationName = "CostAlertNotifications"
SlackWorkspaceId = "ABCDEFG123" ## SlackワークスペースID
SlackChannelId = "HIJKLMN456" ## SlackチャンネルID
IamRoleArn = aws_iam_role.chatbot_role.arn
SnsTopicArns = [aws_sns_topic.cost_anomaly.arn]
GuardrailPolicies = ["arn:aws:iam::aws:policy/ReadOnlyAccess"]
LoggingLevel = "NONE"
UserRoleRequired = false
}
}
}
})
}
一部を解説します。
Cost Anomaly Detection
###############################################################################
# Cost Anomaly Detection
###############################################################################
resource "aws_ce_anomaly_monitor" "default" {
name = "default"
monitor_type = "DIMENSIONAL"
monitor_dimension = "SERVICE"
}
resource "aws_ce_anomaly_subscription" "default" {
name = "default"
frequency = "IMMEDIATE"
threshold_expression {
dimension {
key = "ANOMALY_TOTAL_IMPACT_PERCENTAGE"
values = ["50.0"]
match_options = ["GREATER_THAN_OR_EQUAL"]
}
}
monitor_arn_list = [aws_ce_anomaly_monitor.default.arn]
subscriber {
type = "SNS"
address = aws_sns_topic.cost_anomaly.arn
}
}
基本的には以下ドキュメントのサンプルを参考にしています。
aws_ce_anomaly_monitor | Resources | hashicorp/aws | Terraform Registry
aws_ce_anomaly_subscription | Resources | hashicorp/aws | Terraform Registry
モニター側で注意点としては、組織にひもづかないAWSアカウントを2023年3月27日以降に開設すると、Cost Anomaly Detecitionモニターの「AWSサービス」タイプが自動作成されます。これは複数作ることができないので、すでに作成されている場合はすでに存在するため、上記コードだとエラーになります。
サブスクリプション側では、引数の threshold
が Depracated で、代わりに threshold_expression
で柔軟な設定が可能になっています。
今回は、ANOMALY_TOTAL_IMPACT_PERCENTAGE
(合計インパクト・パーセンテージ)を使用しており、異常と検出された金額が通常金額の何%かをしきい値とします。今回だと「50%以上」だと通知する設定にしています。
SNS
###############################################################################
# SNS Topic
###############################################################################
resource "aws_sns_topic" "cost_anomaly" {
name = "cost_anomaly"
}
data "aws_iam_policy_document" "sns_cost_anomaly" {
statement {
effect = "Allow"
resources = [aws_sns_topic.cost_anomaly.arn]
actions = ["sns:Publish"]
principals {
type = "Service"
identifiers = [
"costalerts.amazonaws.com",
]
}
}
}
resource "aws_sns_topic_policy" "sns_cost_anomaly" {
arn = aws_sns_topic.cost_anomaly.arn
policy = data.aws_iam_policy_document.sns_cost_anomaly.json
}
普通のSNSトピックとリソースポリシーですが、特筆すると、トピックへのアクセスを許可しているAWSサービスの識別子として costalerts.amazonaws.com
を指定しています。
Creating an Amazon SNS topic for anomaly notifications - AWS Cost Management
Chatbot
###############################################################################
# Chatbot
###############################################################################
data "aws_iam_policy_document" "cloudwatch_access" {
statement {
effect = "Allow"
resources = ["*"]
actions = [
"cloudwatch:Describe*",
"cloudwatch:Get*",
"cloudwatch:List*",
]
}
}
resource "aws_iam_policy" "chatbot_role" {
name = "chatbot"
policy = data.aws_iam_policy_document.cloudwatch_access.json
}
data "aws_iam_policy_document" "chatbot_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["chatbot.amazonaws.com"]
}
}
}
resource "aws_iam_role_policy_attachment" "chatbot_role" {
role = aws_iam_role.chatbot_role.name
policy_arn = aws_iam_policy.chatbot_role.arn
}
resource "aws_iam_role" "chatbot_role" {
name = "chatbot"
assume_role_policy = data.aws_iam_policy_document.chatbot_role.json
}
resource "aws_cloudformation_stack" "chatbot" {
name = "chatbot"
template_body = yamlencode({
Description = "Managed by Terraform"
Resources = {
AlertNotifications = {
Type = "AWS::Chatbot::SlackChannelConfiguration"
Properties = {
ConfigurationName = "CostAlertNotifications"
SlackWorkspaceId = "ABCDEFG123" ## SlackワークスペースID
SlackChannelId = "HIJKLMN456" ## SlackチャンネルID
IamRoleArn = aws_iam_role.chatbot_role.arn
SnsTopicArns = [aws_sns_topic.cost_anomaly.arn]
GuardrailPolicies = ["arn:aws:iam::aws:policy/ReadOnlyAccess"]
LoggingLevel = "NONE"
UserRoleRequired = false
}
}
}
})
}
こちらで紹介の方法を大変参考にさせていただいてます。ありがとうございます!
注意点としては、SlackワークスペースID と SlackチャンネルID はダミーなので差し替える必要があります。
ちなみに、TerraformがChatbotをサポートしていないのでCloudFormationをラップしていますが、今なら AWS Cloud Control Provider を使って直接作成する方法もあるようです、なるほど〜
3. 通知テストする
terraform apply後、Chatbotコンソールにて、テスト通知を行うと以下のような通知が届きました。
また、SNSトピックにて、Cost Anomaly Detectionのサンプルメッセージを送信すると、以下のような通知が届きました。
それでは今日はこの辺で。