A simple, serverless, asynchronous HTTP back end for your Slack app.
NOTE — v22.0.0 is a complete rewrite the module. See the release notes for more info
The application intentionally does very little: it will receive an event from Slack in the form of an HTTP request, verify its origin, and then hand off the payload to EventBridge, where it can be processed downstream using event patterns.
Adding features to your slackbot is as simple as adding the appropriate EventBridge rule/target, and some kind of handler function. See the section on processing events for details.
Endpoints are provided for the following routes:
GET /health
— a simple healthcheck to ensure your slackbot is upGET /install
— a helper to begin Slack's OAuth flowGET /oauth/v2
— completes Slack's OAuth2 workflow (v2)POST /callbacks
— handle Slack's interactive messagesPOST /events
— handle events from Slack's Events APIPOST /slash/{cmd}
— handle Slack's slash commands
Payloads from POST
requests are published to EventBridge, as are successful logins during the execution of the OAuth callback route, GET /oauth/v2
.
EventBridge events are discoverable using event patterns. Filter events using a bus name, source value, detail-type, or even parts of the event payload.
By default, the EventBridge bus name is default
and the source is slack
. Both these values are configurable in the module. The detail-type is derived from the endpoint and the detail is the payload itself.
The following table shows the mapping of route-to-detail-type:
Route | Detail Type |
---|---|
GET /oauth/v2 |
oauth |
POST /callbacks |
callback |
POST /events |
event |
POST /slash/{cmd} |
slash |
In addition to handing events from Slack, you can use EventBridge to send payloads to Slack. Publish an event to EventBridge with the detail-type api/<slack-api-method>
.
For example, to send a message using the chat.postMessage
, the following payload could be sent to the PutEvents
method of the EventBridge API:
{
"EventBusName": "<your-bus>",
"Source": "slack",
"DetailType": "api/chat.postMessage",
"Detail": "{\"text\":\"hello, world\"}"
}
After executing the Slack API method, the response from Slack is itself published to EventBridge with the same detail-type value, prefixed with result/
. In the example above, the result would be published to:
{
"EventBusName": "<your-bus>",
"Source": "slack",
"DetailType": "result/api/chat.postMessage",
"Detail": "<slack-response-JSON>"
}
Create an HTTP API
resource "aws_apigatewayv2_api" "http_api" {
name = "my-slack-api"
protocol_type = "HTTP"
# …
}
(Optional) Create an event bus
resource "aws_cloudwatch_event_bus" "slackbot" {
name = "slackbot"
}
Add the slackbot module
module "slackbot" {
source = "amancevice/slackbot/aws"
version = "~> 22.0"
# Required
http_api_execution_arn = aws_apigatewayv2_api.http_api.execution_arn
http_api_id = aws_apigatewayv2_api.http_api.id
lambda_post_function_name = "slack-http-proxy"
lambda_proxy_function_name = "slack-api-post"
role_name = "my-role-name"
secret_name = module.slackbot_secrets.secret.name
# Optional
event_bus_arn = aws_cloudwatch_event_bus.slackbot.arn
event_source = "slackbot"
lambda_post_description = "My Slack post lambda description"
lambda_post_publish = true | false
lambda_post_memory_size = 128
lambda_post_runtime = "python3.8"
lambda_post_timeout = 3
lambda_proxy_description = "My API proxy lambda description"
lambda_proxy_publish = true | false
lambda_proxy_memory_size = 128
lambda_proxy_runtime = "python3.8"
lambda_proxy_timeout = 3
log_group_retention_in_days = 14
role_description = "My role description"
role_path = "/"
lambda_tags = { /* … */ }
log_group_tags = { /* … */ }
role_tags = { /* … */ }
}
Use the slackbot-secrets
module to add your Slack credentials
WARNING Be extremely cautious when using this module. NEVER store secrets in plaintext and encrypt your remote state. I recommend applying this module in a workspace without a remote backend.
module "slackbot_secrets" {
source = "amancevice/slackbot-secrets/aws"
version = "~> 7.0"
secret = module.slackbot.secret
slack_client_id = "{slack_client_id}"
slack_client_secret = "{slack_client_secret}"
slack_oauth_error_uri = "{slack_oauth_error_uri}"
slack_oauth_redirect_uri = "{slack_oauth_redirect_uri}"
slack_oauth_success_uri = "{slack_oauth_success_uri}"
slack_signing_secret = "{slack_signing_secret}"
slack_signing_version = "{slack_signing_version}"
slack_token = "{slack_token}"
}
In order to process a given event you will need to create an EventBridge rule with a pattern that targets a specific event.
The following examples show how a subscription might me made in Terraform:
Callback
resource "aws_cloudwatch_event_rule" "callback" {
event_pattern = jsonencode({
source = ["slack"]
detail-type = ["callback"]
})
}
Event
resource "aws_cloudwatch_event_rule" "event" {
event_pattern = jsonencode({
source = ["slack"]
detail-type = ["event"]
})
}
OAuth
resource "aws_cloudwatch_event_rule" "oauth" {
event_pattern = jsonencode({
source = ["slack"]
detail-type = ["oauth"]
})
}
Slash Command
resource "aws_cloudwatch_event_rule" "slash" {
event_pattern = jsonencode({
source = ["slack"]
detail-type = ["slash"]
})
}
Some plugins are provided that can be hooked into the Slackbot out-of-the-box:
Slash Command
module "slackbot_slash_command" {
source = "amancevice/slackbot-slash-command/aws"
version = "~> 19.0"
# Required
lambda_role_arn = module.slackbot.role.arn
slack_secret_name = module.slackbot.secret.name
slack_topic_arn = module.slackbot.topic.arn
lambda_function_name = "my-slash-command"
slack_slash_command = "example"
slack_response = jsonencode({
response_type = "ephemeral | in_channel"
text = ":sparkles: This will be the response"
blocks = [ /* … */ ]
})
# Optional
lambda_description = "Slackbot handler for /example"
lambda_kms_key_arn = "<kms-key-arn>"
lambda_memory_size = 128
lambda_timeout = 3
log_group_retention_in_days = 30
slack_response_type = "direct | modal"
log_group_tags = { /* … */ }
lambda_tags = { /* … */ }
}