How to Create a Slack News Bot Using AWS Lambda and Terraform
It’s so easy to get distracted by the modern media which is full of click baits, fake sensationalism, ads, and generally poor content. If I check the latest news (or worse, Social Media updates) first thing in the morning, I find myself in the media rabbit hole, following article links, and researching various irrelevant topics waisting the most productive part of the day.
This article is a step by step guide showing how to create a Slack bot which posts the highest ranked Hacker News(HN) and/or Product Hunt(PH) articles to Slack at a specific time each day. If you set yourself a rule “No news until I get this Slack message at 2pm” and stick to it, you could boost your productivity by keeping clear mind for deep work and build a habit for it.
The Slack bot you’ll build ranks HN articles by the amount of comments, with links to discussions as well as article source URL. PH posts are ranked by votes count and link to PH product page as well as the product website. Below is an example of Slack post:
It’s worth mentioning that you can disable specific news sources. For example, you could disable Product Hunt news if you are not interested in product development. This bot can also be easily extended by adding other media sources, for example the highest ranking posts in the subreddits you subscribe to.
A few technologies used:
- terraform-aws-lambda Terraform module to build Lambda package and provision AWS resources.
- Python
asyncio
to query large number of URLs (Hacker News). - Python
requests
to query GraphQL API (Product Hunt). pytest
and Github Actions to run AWS Lambda unit tests.- Slack blocks to format messages.
Prerequisites
- AWS account. The aim is to run the news Bot free of charge, so all resources created in AWS use free tier.
- Slack workspace.
- Product Hunt account API token(Optional).
- Terraform installed on local machine.
Architecture
The architecture of this bot is very straightforward. AWS EventBridge runs on cron like schedule and triggers the Lambda function at a set time. The Lambda queries the Hacker News and/or Product Hunt API, filters top posts, formats text, and sends to the Slack channel. All AWS resources are deployed with Terraform.
Setting up the bot
Slack
Sign it to your Slack workspace and create a new public Slack channel #news. This is where you’ll receive Lambda posts.
Navigate to https://api.slack.com/apps. Click on “Create New App” and select “From scratch”. Give your App a Name, pick a workspace, and click on “Create App”.
Click on “Permissions” section and under “Scopes” part click on “Add an OAuth Scope”. You need to add incoming-webhook
and chat:write
scopes to allow Lambda posting to channel.
At the top of the page find “OAuth Tokens for Your Workspace” section and click on “Install to Workspace”. This will create a request to access your workspace. Enter #news channel for NewsBot posts and click on “Allow”. You will be issued a “Bot User OAuth Token” which is used when deploying AWS Lambda with Terraform.
Invite the bot to your Slack channel by entering the below command in #news:
/invite @NewsBot
You should see:
In this example the bot icon is customised, you can modify it by adding an image in Basic Information -> Display Information.
Deploying AWS Lambda
First of all, we need to create a private S3 bucket to store Terraform state. If it’s your first time using AWS, make sure you’ve created a non-root AWS IAM admin user and have the AWS cli installed on your local machine. The S3 bucket name has to be globally unique, you can create a random string, but it’s a good practice to append the bucket name with your AWS account ID:
## Get AWS Acount ID
$ aws sts get-caller-identity --query Account --output text
123456789012## Create S3 bucket
$ aws s3 mb s3://slack-news-bot-123456789012 --region eu-west-1
make_bucket: slack-news-bot-123456789012
Clone the NewsBot github repo. If you don’t have git installed, you can set it up using this guide:
git clone https://github.com/aurimasmick/slack-news-bot.git
Main repository files and folders:
./github
— Github Actions workflows and templates./src
— Lambda Python source code and unit tests..coveragerc
—pytest-cov
plugin settings..flake8
—flake8
settings for Python linting..pre-commit-config.yaml
— pre-commit hooks for Terraform linting.Makefile
— helper functions.main.tf
— Terraform code for AWS resources.secrets.tfvars.example
— template to store secrets locally. It should not be pushed to public repo. It’s added to.gitignore
by default.state.tf
— Terraform state file location. You need to modify this file to use the newly created bucket.
terraform {backend "s3" {
bucket = "slack-news-bot-123456789012"
key = "slack-news-bot/main.tfstate"
region = "eu-west-1"
encrypt = true
}
}
terraform.tfvars
— variable values.variables.tf
— variable definitions.
It is worth mentioning that there are multiple ways to handle Lambda secrets. The most secure method is to use a secrets store like AWS Secrets Manager and fetch secrets dynamically during Lambda execution. However, this service is not free and we don’t want NewsBot to cost anything. You could also use a tool like sops which encrypts the secrets file using PGP or AWS KMS allowing to store it on Git. After we decrypt the file and run Terraform to deploy Lambda, we still store that secret as a Lambda environment variable in plain text on AWS, so it defeats the purpose in our use case.
Since this is not a Production or mission critical project, and the secrets involved aren’t hard to rotate/regenerate if compromised, you will export the secrets as environment variables. After you run Terraform in the next step, the secrets will be stored in AWS as Lambda environment variables.
export TF_VAR_slack_bot_token=(TOKEN CREATED IN SLACK STEP)
export TF_VAR_ph_api_token=(PRODUCT HUNT API TOKEN)
You would still need some place to store those secrets, like a 1Password or LastPass vault. If you don’t use either of those tools, you can create a secrets.tfvars
file. Make sure this file is not pushed to a public repo, by default it’s added to .gitignore:
slack_bot_token = (TOKEN CREATED IN SLACK STEP)
ph_api_token = (PRODUCT HUNT API TOKEN)
PRODUCT HUNT API TOKEN can be obtained by creating a Product Hunt account. If you don’t want Product Hunt posts, you don’t need to export or specify a value for this variable. In such case, modify terraform.tfvars
and change post_ph
to “false”
:
name = "slack-news-bot"
slack_channel_name = "news"
post_hn = "true"
post_ph = "false"
stories_number = 5
schedule_expression = "cron(0 14 * * ? *)"
Deploy AWS resources with Terraform:
terraform initterraform plan
terraform apply## If using secrets.tfvars
terraform plan -var-file=secrets.tfvars
terraform apply -var-file=secrets.tfvars
Terraform will create the following resources:
- Lambda .zip package in /build directory
- AWS Lambda function
- AWS IAM Role and Policy for Lambda
- AWS CloudWatch Logs Group
- AWS EvenBridge rule and event target
- Lambda permission to allow event trigger
Once all resources are provisioned, you can trigger the Lambda function manually from the AWS Lambda console by using the default “Hello World” template. Make sure to select Ireland as the region for the AWS console if you are following this example verbatim or change it to the region
you specified when configuring your Terraform variables.
Making changes to Lambda
If you want to modify or add functionality to the Lambda function, you need to create a Python virtual environment and install dependencies:
python3 -m venv venv
source venv/bin/activate
pip install -r src/slacknewsbot/requirements.txt
There are a few Makefile
helper functions to lint, unit test and deploy lambda:
make tests
make deploy## if using secrets.tfvars
make deploy-with-secrets-file
Conclusion
I hope the NewsBot you’ve created will increase your productivity and reduce distractions which are so common when working from home. If you’ve followed this step by step guide, you have been using a few modern technologies along the way. Now it’s your turn to fine-tune the bot to your liking and preferences and dive deeper into the code to further improve your skills. Enjoy!