AWSサービスをTerraformでコード化する:AWS Chatbot編
はじめに
こんにちは、Shunです。
今回は、ChatbotをTerraformを使ってコード化する機会があったため、その方法をご紹介します。
本記事では以下のコード化を行っています。
想定読者
- ChatbotやSNSなどの関連リソースを使用している方
- AWSのコード化を検討している方
本記事で取り扱う内容
- Chatbotのコード化の方法
- コード化を実装する上での注意点
本記事で取り扱わない内容
- ChatbotやSNSのサービス説明
- Chatbotなどの設定値(これらは上述したブログでご紹介しています。)
実施すること
以下でご紹介する内容をTerraformでコード化したものです。
Chatbotなどの関連サービスを初めて使用する方は、先に上記の記事を読むことをお勧めします。
料金
- Chatbot: 無料
- SNS: $0.5/100万通知
- CloudWatch Alarm: $0.1/アラームメトリクス(月)
- EventBridge: $1.00/100万イベント
今回の検証を通して、発生する費用は数円です。
構成図
今回実装するTerraformの構成は以下の通りです。
前提
- Terraform環境がセットアップ済み
- SlackのワークスペースとChatbotが連携済み
tfファイルとJSONファイルの解説
tfファイルと各ポリシーをJSON形式で切り出しています。
ディレクトリ構造は以下です。
├─ provider.tf ├─ chatbot.tf ├─ cloudwatch.tf ├─ eventbridge.tf ├─ sns.tf ├─ alarm_event.json ├─ alarm_template.json ├─ ok_event.json ├─ ok_template.json └─ sns_policy.json
provider.tf
provider.tf
は以下の通りです。
locals { aws_id = "[accout_id]" name_prefix = "[xxxxx]" region = "ap-northeast-1" Environment = "[xxxxx]" slack_workspace_id = "[workspace_id]" slack_channel_id = "[channel_id]" instanceId = "[監視対象EC2のインスタンスID]" } terraform { required_version = "~> 1.7.0" backend "s3" { bucket = "[bucket_name]" region = "ap-northeast-1" key = "chatbot/terraform.tfstate" encrypt = true } required_providers { aws = { source = "hashicorp/aws" version = "~> 5.19.0" } awscc = { source = "hashicorp/awscc" version = "0.70.0" } } } provider "aws" { region = "ap-northeast-1" } provider "awscc" { region = "ap-northeast-1" }
特に注目すべき点は、providerにawsccを指定していることです。
TerraformでAWSリソースを作成する際、通常はawsをproviderとして指定しますが、Chatbotには対応していません。
そのため、AWS Cloud Control APIを使用するawsccを使用します。
AWS Cloud Control API
AWS Cloud Control API を使用して、幅広いサービス (AWS およびサードパーティの両方) に属するクラウドリソースを作成、読み取り、更新、削除、一覧表示 (CRUD-L、Create, Read, Update, Delete, and List) します。Cloud Control API のアプリケーションプログラミングインターフェイス (API) の標準化されたセットを使用すると、AWS アカウント でサポートされているあらゆるリソースで CRUD-L オペレーションを実行できます。Cloud Control API を使用すると、リソースを担当する個々のサービスに固有のコードやスクリプトを生成する必要がなくなります。
providerはこちらです。
chatbot.tf
chatbot.tf
は以下の通りです。
resource "awscc_chatbot_slack_channel_configuration" "chatbot" { configuration_name = "${local.name_prefix}-${local.Environment}" slack_workspace_id = local.slack_workspace_id slack_channel_id = local.slack_channel_id iam_role_arn = aws_iam_role.chatbot.arn sns_topic_arns = [aws_sns_topic.chatbot.arn] user_role_required = false logging_level = "ERROR" guardrail_policies = ["arn:aws:iam::aws:policy/CloudWatchFullAccess"] } resource "aws_iam_role" "chatbot" { name = "${local.name_prefix}-${local.Environment}" assume_role_policy = data.aws_iam_policy_document.chatbot_assume.json } data "aws_iam_policy_document" "chatbot" { statement { effect = "Allow" actions = [ "sts:AssumeRole", ] principals { type = "Service" identifiers = [ "chatbot.amazonaws.com", ] } } } resource "aws_iam_role_policy_attachment" "chatbot" { role = aws_iam_role.chatbot.name policy_arn = "arn:aws:iam::aws:policy/AWSResourceExplorerReadOnlyAccess" }
resource "awscc_chatbot_slack_channel_configuration" "chatbot"
で示しているように、awsccのproviderを指定して、リソースを作成しています。
また、9行目で定義しているguardrail_policies
はChatbotへ付与されるIAMロールのガードレールです。
Chatbotは、SlackからCLIコマンドを打つことができる機能があります。
付与されたIAMロールによって、チャネルにいるメンバー全員に同様の権限を付与することができます。
そのため、大きな権限を付与すると事故に繋がりかねないので、IAMロールのガードレールという形で予防線が定義されています。
cloudwatch.tf
cloudwatch.tf
は以下の通りです。
resource "aws_cloudwatch_metric_alarm" "chatbot" { actions_enabled = true alarm_actions = [] ok_actions = [] alarm_description = "chatbot" alarm_name = "${local.name_prefix}-${local.Environment}" comparison_operator = "GreaterThanOrEqualToThreshold" datapoints_to_alarm = 1 dimensions = { InstanceId = local.instanceId } evaluate_low_sample_count_percentiles = null evaluation_periods = 1 extended_statistic = null insufficient_data_actions = [] metric_name = "CPUUtilization" namespace = "AWS/EC2" period = 300 statistic = "Average" threshold = 80 threshold_metric_id = null treat_missing_data = "missing" unit = null }
EC2インスタンスのCPU使用率が80%以上になった時にアラームが発生する設定を行います。
アラーム時のアクションは、EventBridgeのイベントルールで取得します。
eventbridge.tf
eventbridge.tf
は以下の通りです。
resource "aws_cloudwatch_event_rule" "alarm" { event_bus_name = "default" event_pattern = file("alarm_event.json") is_enabled = true name = "${local.name_prefix}-${local.Environment}-alarm" } resource "aws_cloudwatch_event_target" "alarm" { arn = aws_sns_topic.chatbot.arn rule = aws_cloudwatch_event_rule.alarm.id input_transformer { input_paths = { "account" : "$.account", "alarm" : "$.detail.alarmName", "description" : "$.detail.configuration.description", "instance" : "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId", "metrics_name" : "$.detail.configuration.metrics[0].metricStat.metric.name", "state" : "$.detail.state.value", "timestamp" : "$.detail.state.timestamp" } input_template = file("alarm_template.json") } } resource "aws_cloudwatch_event_rule" "ok" { event_bus_name = "default" event_pattern = file("ok_event.json") is_enabled = true name = "${local.name_prefix}-${local.Environment}-ok" } resource "aws_cloudwatch_event_target" "ok" { arn = aws_sns_topic.chatbot.arn rule = aws_cloudwatch_event_rule.ok.id input_transformer { input_paths = { "account" : "$.account", "alarm" : "$.detail.alarmName", "description" : "$.detail.configuration.description", "instance" : "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId", "metrics_name" : "$.detail.configuration.metrics[0].metricStat.metric.name", "state" : "$.detail.state.value", "timestamp" : "$.detail.state.timestamp" } input_template = file("ok_template.json") } }
ここでは、EventBridgeのルールとターゲットを定義しています。
3,28行目では、EventBridgeが駆動するためのルールをJSONで定めています。
12,37行目では、22,47行目で指定しているJSONで使用する変数を定義しています。
各ファイルの中身は以下です。
alarm_event.json
{ "source": [ "aws.cloudwatch" ], "detail-type": [ "CloudWatch Alarm State Change" ], "resources": [ "arn:aws:cloudwatch:ap-northeast-1:xxxxxx:alarm:xxxxxxxx" ], "detail": { "state": { "value": ["ALARM"] } } }
ok_event.json
{ "source": [ "aws.cloudwatch" ], "detail-type": [ "CloudWatch Alarm State Change" ], "resources": [ "arn:aws:cloudwatch:ap-northeast-1:xxxxxx:alarm:xxxxxxxx" ], "detail": { "state": { "value": ["OK"] } } }
alarm_template.json
{ "version": "1.0", "source": "custom", "content": { "textType": "client-markdown", "title": ":red_circle: <state>:EC2インスタンス(<instance>)ステータスチェックアラート", "description": "発生時刻 : `<timestamp>`\nアカウント : <account>\nインスタンス : `<instance>`\nメトリクス : <metrics_name>\nアラーム : <alarm>", "nextSteps": [ "CPU増加の原因を調査してください。" ] } }
ok_template.json
{ "version": "1.0", "source": "custom", "content": { "textType": "client-markdown", "title": ":large_blue_circle: <state>:EC2インスタンス(<instance>)CPU使用率80%", "description": "EC2インスタンスは復旧しました \n発生時刻 : `<timestamp>`\nアカウント : <account>\nインスタンス : `<instance>`\nメトリクス : <metrics_name>\nアラーム : <alarm>" } }
sns.tf
sns.tf
の中身は以下です。
resource "aws_sns_topic" "chatbot" { name = "${local.name_prefix}-${local.Environment}" } resource "aws_sns_topic_policy" "chatbot" { arn = aws_sns_topic.chatbot.arn policy = file("sns_policy.json") }
コンソールからSNSを作成する際は、ポリシーを設定しなくとも自動で設定を行ってくれるのですが、Terraformで記述する場合は、明示的にポリシーを記述する必要があります。
明示的に追加する必要がある部分をハイライトしております。
sns_policy.json
{ "Version": "2008-10-17", "Id": "__default_policy_ID", "Statement": [ { "Sid": "__default_statement_ID", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "SNS:Publish", "SNS:RemovePermission", "SNS:SetTopicAttributes", "SNS:DeleteTopic", "SNS:ListSubscriptionsByTopic", "SNS:GetTopicAttributes", "SNS:AddPermission", "SNS:Subscribe" ], "Resource": "arn:aws:sns:ap-northeast-1:xxxxx:xxxxx", "Condition": { "StringEquals": { "AWS:SourceOwner": "xxxxxxxxxx" } } }, { "Sid": "AWSEvents-chatbot-ok_Id2f80f695-2648-4cdf-b32d-f296630b6c35", "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Action": "sns:Publish", "Resource": "arn:aws:sns:ap-northeast-1:xxxxx:xxxxx" } ] }
コンソールとTerraformでの挙動の違いを以下のブログで解説しておりますので、気になる方はご覧ください。
まとめ
今回ご紹介したTerraformファイルは、provider.tf
のlocals
セクションに必要な設定を追加し、各種リソースに対応するJSONファイルを編集することで簡単に利用開始できます。
最後まで読んでいただきありがとうございます!
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitterGoogle Cloud Partner Top Engineer 2025、2024 AWS All Cert、ビール検定1冠
Recommends
こちらもおすすめ
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28
AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16