Configuring AWS SNS with Terraform
A comprehensive guide to setting up Amazon Simple Notification Service (SNS) using Terraform Infrastructure as Code
Configuring AWS SNS with Terraform
Amazon Simple Notification Service (SNS) is a fully managed pub/sub messaging service. This guide shows how to set up SNS using Terraform.
Prerequisites
- AWS CLI configured
- Terraform installed
- Basic understanding of pub/sub messaging
- Subscriber endpoints ready (email, Lambda, etc.)
Project Structure
aws-sns-terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars
Basic SNS Configuration
# main.tf
provider "aws" {
region = var.aws_region
}
# SNS Topic
resource "aws_sns_topic" "main" {
name = "${var.project_name}-topic"
tags = {
Environment = var.environment
}
}
# Topic Policy
resource "aws_sns_topic_policy" "default" {
arn = aws_sns_topic.main.arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Default SNS Policy"
Effect = "Allow"
Principal = {
AWS = "*"
}
Action = [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish"
]
Resource = aws_sns_topic.main.arn
Condition = {
StringEquals = {
"AWS:SourceOwner": data.aws_caller_identity.current.account_id
}
}
}
]
})
}
Subscription Configuration
# Email Subscription
resource "aws_sns_topic_subscription" "email" {
topic_arn = aws_sns_topic.main.arn
protocol = "email"
endpoint = var.email_endpoint
}
# Lambda Subscription
resource "aws_sns_topic_subscription" "lambda" {
topic_arn = aws_sns_topic.main.arn
protocol = "lambda"
endpoint = var.lambda_function_arn
}
# SQS Subscription
resource "aws_sns_topic_subscription" "sqs" {
topic_arn = aws_sns_topic.main.arn
protocol = "sqs"
endpoint = var.sqs_queue_arn
}
# HTTP/HTTPS Endpoint
resource "aws_sns_topic_subscription" "https" {
topic_arn = aws_sns_topic.main.arn
protocol = "https"
endpoint = var.https_endpoint
}
FIFO Topic Configuration
# FIFO Topic
resource "aws_sns_topic" "fifo" {
name = "${var.project_name}.fifo"
fifo_topic = true
content_based_deduplication = true
tags = {
Environment = var.environment
}
}
# FIFO Topic Subscription (SQS FIFO Queue)
resource "aws_sns_topic_subscription" "fifo_sqs" {
topic_arn = aws_sns_topic.fifo.arn
protocol = "sqs"
endpoint = var.fifo_queue_arn
}
Cross-Account Access
# Topic Policy for Cross-Account Access
resource "aws_sns_topic_policy" "cross_account" {
arn = aws_sns_topic.main.arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "CrossAccountPublish"
Effect = "Allow"
Principal = {
AWS = var.allowed_aws_account_ids
}
Action = "SNS:Publish"
Resource = aws_sns_topic.main.arn
}
]
})
}
Variables Configuration
# variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "us-west-2"
}
variable "project_name" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
variable "email_endpoint" {
description = "Email endpoint for subscription"
type = string
}
variable "lambda_function_arn" {
description = "Lambda function ARN"
type = string
}
variable "allowed_aws_account_ids" {
description = "List of AWS account IDs allowed to publish"
type = list(string)
default = []
}
Best Practices
-
Topic Management
- Use meaningful topic names
- Implement proper access controls
- Consider using FIFO topics for ordered delivery
- Use topic tags for organization
-
Security
- Implement least privilege access
- Use encryption for sensitive data
- Regularly audit topic policies
- Monitor failed deliveries
-
Reliability
- Implement proper error handling
- Use DLQ for failed messages
- Monitor delivery status
- Implement retry policies
-
Cost Optimization
- Monitor message volume
- Clean up unused subscriptions
- Use appropriate message filtering
- Consider message batching
Message Filtering
# Subscription with Filter Policy
resource "aws_sns_topic_subscription" "filtered" {
topic_arn = aws_sns_topic.main.arn
protocol = "sqs"
endpoint = var.sqs_queue_arn
filter_policy = jsonencode({
environment = ["production"]
severity = ["high", "critical"]
})
}
Dead Letter Queue Configuration
# DLQ for Failed Message Delivery
resource "aws_sqs_queue" "dlq" {
name = "${var.project_name}-dlq"
}
resource "aws_sns_topic_subscription" "with_dlq" {
topic_arn = aws_sns_topic.main.arn
protocol = "lambda"
endpoint = var.lambda_function_arn
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.dlq.arn
})
}
Monitoring Configuration
# CloudWatch Alarms
resource "aws_cloudwatch_metric_alarm" "failed_deliveries" {
alarm_name = "${var.project_name}-failed-deliveries"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "NumberOfNotificationsFailed"
namespace = "AWS/SNS"
period = "300"
statistic = "Sum"
threshold = "1"
alarm_description = "This metric monitors failed SNS deliveries"
alarm_actions = [var.alarm_topic_arn]
dimensions = {
TopicName = aws_sns_topic.main.name
}
}
Deployment Steps
- Initialize Terraform:
terraform init
- Plan the deployment:
terraform plan
- Apply the configuration:
terraform apply
Clean Up
Remove all resources when done:
terraform destroy
Common Use Cases
- Event Notification System
resource "aws_sns_topic" "events" {
name = "${var.project_name}-events"
}
resource "aws_sns_topic_subscription" "events_email" {
count = length(var.notification_emails)
topic_arn = aws_sns_topic.events.arn
protocol = "email"
endpoint = var.notification_emails[count.index]
}
- Multi-Region Fanout
resource "aws_sns_topic" "primary" {
name = "${var.project_name}-primary"
}
resource "aws_sns_topic" "secondary" {
provider = aws.secondary_region
name = "${var.project_name}-secondary"
}
resource "aws_sns_topic_subscription" "region_fanout" {
provider = aws.secondary_region
topic_arn = aws_sns_topic.primary.arn
protocol = "sns"
endpoint = aws_sns_topic.secondary.arn
}
Conclusion
This setup provides a comprehensive foundation for deploying SNS using Terraform. Remember to:
- Plan your messaging architecture carefully
- Implement proper security measures
- Monitor delivery status and failures
- Keep your configurations versioned
- Test thoroughly before production deployment
The complete code can be customized based on your specific requirements and use cases.