TerraformでCodepipelienの進捗をSNSとChatbotを使ってSlackに通知する

# TerraformでCodepipelienの進捗をSNSとChatbotを使ってSlackに通知する


### コンソールで事前準備

とりあえずChatbotとSlackのワークフロー連携はGUIじゃないと出来ないのでやります（残念

- Chatbot開いて
- `新しいクライアントを設定`押して
![スクリーンショット 2024-05-13 17.24.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131778/94c65cb8-06ba-97e7-f7fe-67f6d6effa98.png)

- 一覧から`Slack`を選択して連携してください
![スクリーンショット 2024-05-13 17.24.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131778/c7727730-1079-1910-a536-d8c0c2a04d2c.png)

### 以下Terraform

provider awsだとChatbotとslackチャンネルの連携ができないので provder awsccを入れる


```terraform
terraform {
  required_version = "1.8.3"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.42.0"
    }
  
    awscc = {
      source  = "hashicorp/awscc"
      version = "0.76.0"
    }
  }
}
```

sns topicを作成

```terraform
// IAMでユーザーのIDを利用したいので用意しとく
data "aws_caller_identity" "current" {}

resource "aws_sns_topic" "sns_topic" {
  name = "sns-topic"
}

# デフォルトで用意されるSNSのIAMでは権限不足なので、デフォルトののIAM + `odestar-notifications.amazonaws.com` も追加
data "aws_iam_policy_document" "iam_policy_sns_topic" {
  statement {
    sid = "1"
    actions = [
      "SNS:GetTopicAttributes",
      "SNS:SetTopicAttributes",
      "SNS:AddPermission",
      "SNS:RemovePermission",
      "SNS:DeleteTopic",
      "SNS:Subscribe",
      "SNS:ListSubscriptionsByTopic",
      "SNS:Publish",
      "SNS:Receive"
    ]

    principals {
      identifiers = ["*"]
      type        = "AWS"
    }

    resources = [aws_sns_topic.sns_topic.arn]

    condition {
      test     = "StringEquals"
      variable = "AWS:SourceOwner"
      values   = [data.aws_caller_identity.current.account_id]
    }
  }
  statement {
    sid     = "2"
    actions = ["SNS:Publish"]

    principals {
      type        = "Service"
      identifiers = ["codestar-notifications.amazonaws.com"]
    }

    resources = [aws_sns_topic.sns_topic.arn]
  }
}

resource "aws_sns_topic_policy" "sns_topic" {
  arn    = aws_sns_topic.sns_topic.arn
  policy = data.aws_iam_policy_document.iam_policy_sns_topic.json
}


```

Chatbot記述

```terraform

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

# これだけawsccを利用してリソースを作成
resource "awscc_chatbot_slack_channel_configuration" "chatbot" {
  configuration_name = "chatbot"
  slack_workspace_id = "SlackのワークスペースID"
  slack_channel_id   = "SlackのチャンネルID"
  iam_role_arn       = aws_iam_role.iam_chatbot_role.arn
  user_role_required = false
  logging_level      = "ERROR"
  guardrail_policies = ["arn:aws:iam::aws:policy/ReadOnlyAccess"]
  # sns_topic_arnsは既存のsubscriptionの定義等と喧嘩してしまうのでaws_sns_topic_subscriptionを利用します
  # sns_topic_arns     = [aws_sns_topic.sns_topic.arn]
}

# ChatbotをSNSにサブスクリプションさせる
resource "aws_sns_topic_subscription" "sns_topic_subscription_chatbot" {
  endpoint  = "https://global.sns-api.chatbot.amazonaws.com" #固定値
  protocol  = "https" #固定値
  topic_arn = aws_sns_topic.sns_topic.arn
}
```

CodePipelineをSNSと連携させる

```terraform
resource "aws_codestarnotifications_notification_rule" "codepipeline_notify" {
  name = "codepiepeline-notify"

  detail_type = "FULL"

  event_type_ids = [
    "codepipeline-pipeline-pipeline-execution-started",
    "codepipeline-pipeline-pipeline-execution-failed",
    "codepipeline-pipeline-pipeline-execution-succeeded"
  ]

  resource = aws_codepipeline.this.arn

  target {
    type    = "SNS"
    address = aws_sns_topic.sns_topic.arn
  }
}
```

これでSlackに通知がいくと思います...!


## 番外編 CodePipelineの通知はSNSを使わなくても出来ます

CodePipelineの通知は直接Chatbotと連携できるので、こちらでも可

```terraform
resource "aws_codestarnotifications_notification_rule" "codepipeline_notify" {
  name = "codepiepeline-notify"

  detail_type = "FULL"

  event_type_ids = [
    "codepipeline-pipeline-pipeline-execution-started",
    "codepipeline-pipeline-pipeline-execution-failed",
    "codepipeline-pipeline-pipeline-execution-succeeded"
  ]

  resource = aws_codepipeline.this.arn

  target {
    type    = "AWSChatbot" 
    address = awscc_chatbot_slack_channel_configuration.chatbot.arn
  }
}
```

```diff
target {
-    type    = "SNS" 
+    type    = "AWSChatbot" 
-    address = aws_sns_topic.sns_topic.arn
+    address = awscc_chatbot_slack_channel_configuration.chatbot.arn
  }
```

SNSがAWSChatbotとなり、addressもChatbotのarnになっています