At PolymerSearch, we use CodeDeploy to deploy our services to AWS. We have a Slack channel where we post deployment notifications. We used to manually manage our infrastructure, but we recently switched to Terraform. Part of the migration required adding these Slack notifications, and since it wasn’t a straightforward process, this post will explain how to do it.
The AWS Terraform provider doesn’t provide ChatBot integration as of this writing. To achieve this, we’ve included Terraform AWS Cloud Control provider as well.
There is a manual step you have to to take to integrate AWS Chatbot with Slack. You can find the steps here. The steps are straightforward, and you’ll need to have admin access to your Slack workspace.
- Add AWS Chatbot to your Slack workspace
- Login to your AWS account, open ChatBot, select Configure New Client -> Slack.
- Select your Slack workspace and provide Access Permissions to AWS ChatBot.
The whole setup is available at GitHub here.
Terraform
Below are the Terraform resources we used to set up the integration. You’ll need at least two providers, hashicorp/aws
and hashicorp/awscc
. The first one is the official AWS provider, and the second one is the AWS Cloud Control provider. The second one is used to create the AWS Chatbot Slack channel configuration.
You’ll need to update locals with your Slack workspace ID and Slack channel ID. You can find the Slack channel ID by opening the Slack channel and copying the ID from Channel Settings -> About this channel.
Slack Workspace ID can be found in the Slack web client URL by navigating to your Slack workspace in your browser. The ID after “client/” is the Slack Workspace ID.
https://app.slack.com/client/TT896HKILP/
You can set variables to default values or pass them as command-line arguments / via your CI/CD pipeline.
ChatBot
resource "awscc_chatbot_slack_channel_configuration" "deployment_notifications" {
configuration_name = "deployment_notifications"
iam_role_arn = aws_iam_role.chatbot_slack.arn
slack_channel_id = local.slack_deployment_notifications_channel_id
slack_workspace_id = local.slack_workspace_id
sns_topic_arns = [aws_sns_topic.deployment_notifications.arn]
}
CloudWatch Log Group
resource "aws_cloudwatch_log_group" "chatbot_slack" {
name = "sns/${var.region}/${var.account_id}/deployment_notifications"
retention_in_days = 7
}
CodeDeploy
resource "aws_codedeploy_app" "my_app" {
name = "my_app"
}
resource "aws_codedeploy_deployment_group" "my_app" {
deployment_group_name = "my_app"
app_name = aws_codedeploy_app.my_app.name
service_role_arn = aws_iam_role.codedeploy.arn
// Rest of the configuration is omitted as that is specific to your application
}
resource "aws_iam_role" "codedeploy" {
name = "codedeploy"
assume_role_policy = data.aws_iam_policy_document.assume_by_codedeploy.json
lifecycle {
ignore_changes = [managed_policy_arns]
}
}
data "aws_iam_policy_document" "assume_by_codedeploy" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["codedeploy.amazonaws.com"]
}
}
}
CodeStar Notifications
resource "aws_codestarnotifications_notification_rule" "deployment_notifications" {
name = "deployment_notifications"
detail_type = "FULL"
resource = aws_codedeploy_deployment_group.my_app.arn
event_type_ids = ["codedeploy-application-deployment-failed", "codedeploy-application-deployment-succeeded"]
target {
address = aws_sns_topic.deployment_notifications.arn
}
}
IAM
data "aws_iam_policy_document" "chatbot_slack" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["sns.amazonaws.com"]
}
}
}
resource "aws_iam_role" "chatbot_slack" {
name = "chatbot_slack"
description = "Allows AWS Chatbot to publish to SNS topics on your behalf."
assume_role_policy = data.aws_iam_policy_document.chatbot_slack.json
}
resource "aws_iam_role_policy_attachment" "sns_chatbot_slack_logging" {
role = aws_iam_role.chatbot_slack.name
policy_arn = aws_iam_policy.sns_chatbot_slack_logging.arn
}
resource "aws_iam_policy" "sns_chatbot_slack_logging" {
name = "sns_chatbot_slack_logging"
policy = data.aws_iam_policy_document.sns_chatbot_slack_logging.json
}
data "aws_iam_policy_document" "sns_chatbot_slack_logging" {
statement {
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"cloudwatch:Describe*",
"cloudwatch:Get*",
"cloudwatch:List*"
]
resources = [aws_cloudwatch_log_group.chatbot_slack.arn]
}
}
Locals
locals {
slack_workspace_id = "REPLACE_WITH_YOUR_SLACK_WORSKAPCE_ID"
slack_deployment_notifications_channel_id = "REPLACE_WITH_YOUR_SLACK_CHANNEL_ID"
}
SNS
resource "aws_sns_topic" "deployment_notifications" {
name = "deployment_notifications"
http_failure_feedback_role_arn = aws_iam_role.chatbot_slack.arn
http_success_feedback_role_arn = aws_iam_role.chatbot_slack.arn
}
resource "aws_sns_topic_subscription" "deployment_notifications" {
topic_arn = aws_sns_topic.deployment_notifications.arn
protocol = "https"
endpoint = "https://global.sns-api.chatbot.amazonaws.com"
}
resource "aws_sns_topic_policy" "deployment_notifications" {
arn = aws_sns_topic.deployment_notifications.arn
policy = data.aws_iam_policy_document.deployment_naws_sns_topic.deployment_notifications.json
}
Variables
variable "region" {
type = string
}
variable "account_id" {
type = number
}