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
こちらもおすすめ
-
Slack、Brobotなどで快適GAレポーティング!
2015.12.20
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28

AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16


