Skip to content

Instantly share code, notes, and snippets.

@kdgregory
Last active February 26, 2023 21:35
Show Gist options
  • Save kdgregory/54ca643f3ab6021679cfddb1d9401062 to your computer and use it in GitHub Desktop.
Save kdgregory/54ca643f3ab6021679cfddb1d9401062 to your computer and use it in GitHub Desktop.
Example of Terraform module to create an SQS queue with modular policy documents
##
## Main configuration: creates several SQS queues using a module, then
## combines their policies into an application role.
##
provider "aws" {}
module "notifications_queue" {
source = "./modules/sqs"
queue_name = "Notifications"
}
module "rendering_queue" {
source = "./modules/sqs"
queue_name = "Rendering"
}
module "reports_queue" {
source = "./modules/sqs"
queue_name = "ReportGeneration"
visibility_timeout = 600
receive_count = 1
}
resource "aws_iam_role" "application_role" {
name = "ApplicationRole"
assume_role_policy = jsonencode({
"Version" = "2012-10-17",
"Statement" = [
{
"Effect" = "Allow"
"Action" = "sts:AssumeRole"
"Principal" = { "Service" = "ec2.amazonaws.com" }
}
]
})
}
resource "aws_iam_role_policy" "application_role_queue_policy" {
name = "application_role_queue_policy"
role = aws_iam_role.application_role.id
policy = jsonencode({
"Version" = "2012-10-17",
"Statement" = [
module.notifications_queue.producer_policy_statement,
module.rendering_queue.producer_policy_statement,
module.reports_queue.producer_policy_statement
]
})
}
##
## A module to create an SQS queue, along with its dead-letter queue and access policies
##
provider "aws" {}
data "aws_region" "current" {}
##
## The primary and dead-letter queues
##
resource "aws_sqs_queue" "base_queue" {
name = var.queue_name
message_retention_seconds = var.retention_period
visibility_timeout_seconds = var.visibility_timeout
redrive_policy = jsonencode({
"deadLetterTargetArn" = aws_sqs_queue.deadletter_queue.arn,
"maxReceiveCount" = var.receive_count
})
}
resource "aws_sqs_queue" "deadletter_queue" {
name = "${var.queue_name}-DLQ"
message_retention_seconds = var.retention_period
visibility_timeout_seconds = var.visibility_timeout
}
##
## the policy statements are defined as locals so that they can be
## used by the consuming module to build a larger policy
##
locals {
consumer_policy_statement = {
"Sid" = "c${sha1(aws_sqs_queue.base_queue.arn)}"
"Effect" = "Allow",
"Action" = [
"sqs:ChangeMessageVisibility",
"sqs:ChangeMessageVisibilityBatch",
"sqs:DeleteMessage",
"sqs:DeleteMessageBatch",
"sqs:GetQueueAttributes",
"sqs:GetQueueUrl",
"sqs:ReceiveMessage"
],
"Resource" = [
aws_sqs_queue.base_queue.arn,
aws_sqs_queue.deadletter_queue.arn
]
}
producer_policy_statement = {
"Sid" = "p${sha1(aws_sqs_queue.base_queue.arn)}"
"Effect" = "Allow",
"Action" = [
"sqs:GetQueueAttributes",
"sqs:GetQueueUrl",
"sqs:SendMessage",
"sqs:SendMessageBatch"
],
"Resource" = [
aws_sqs_queue.base_queue.arn
]
}
}
##
## managed policies are created for convenience when there's
## just a few queues that an application might use
##
resource "aws_iam_policy" "consumer_policy" {
name = "SQS-${var.queue_name}-${data.aws_region.current.name}-consumer"
description = "Attach this policy to consumers of the ${var.queue_name} queue"
policy = jsonencode({
"Version" = "2012-10-17",
"Statement" = [local.consumer_policy_statement]
})
}
resource "aws_iam_policy" "producer_policy" {
name = "SQS-${var.queue_name}-${data.aws_region.current.name}-producer"
description = "Attach this policy to producers for the ${var.queue_name} queue"
policy = jsonencode({
"Version" = "2012-10-17",
"Statement" = [local.producer_policy_statement]
})
}
output "base_queue_url" {
value = aws_sqs_queue.base_queue.id
}
output "deadletter_queue_url" {
value = aws_sqs_queue.deadletter_queue.id
}
output "consumer_policy_statement" {
value = local.consumer_policy_statement
}
output "producer_policy_statement" {
value = local.producer_policy_statement
}
output "consumer_policy_arn" {
value = aws_iam_policy.consumer_policy.arn
}
output "producer_policy_arn" {
value = aws_iam_policy.producer_policy.arn
}
variable "queue_name" {
description = "The name of the queue. Used as a prefix for related resource names."
type = string
}
variable "retention_period" {
description = "Time (in seconds) that messages will remain in queue before being purged"
type = number
default = 86400
}
variable "visibility_timeout" {
description = "Time (in seconds) that consumers have to process a message before it becomes available again"
type = number
default = 60
}
variable "receive_count" {
description = "The number of times that a message can be retrieved before being moved to the dead-letter queue"
type = number
default = 3
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment