diff --git a/.github/workflows/manual-combine-dependabot-prs.yaml b/.github/workflows/manual-combine-dependabot-prs.yaml new file mode 100644 index 0000000..c527a23 --- /dev/null +++ b/.github/workflows/manual-combine-dependabot-prs.yaml @@ -0,0 +1,24 @@ +name: Combine Dependabot PRs + +on: + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + checks: read + +jobs: + combine-prs: + runs-on: ubuntu-latest + + steps: + - name: combine-prs + id: combine-prs + uses: github/combine-prs@v5.1.0 + with: + ci_required: false + labels: dependencies + pr_title: Combined Dependabot PRs + combine_branch_name: dependabotCombined + pr_body_header: Combined Dependabot PRs diff --git a/infrastructure/modules/lambda/outputs.tf b/infrastructure/modules/lambda/outputs.tf index 802eb23..3fc5366 100644 --- a/infrastructure/modules/lambda/outputs.tf +++ b/infrastructure/modules/lambda/outputs.tf @@ -15,7 +15,7 @@ output "function_qualified_arn" { } output "function_env_vars" { - value = length(var.lambda_env_vars) == 0 ? [] : aws_lambda_function.main.environment[0].variables + value = length(var.lambda_env_vars) == 0 ? {} : aws_lambda_function.main.environment[0].variables } output "iam_role_name" { diff --git a/infrastructure/modules/sqs/data_iam_policy_document_deadletter_queue.tf b/infrastructure/modules/sqs/data_iam_policy_document_deadletter_queue.tf new file mode 100644 index 0000000..a3e0456 --- /dev/null +++ b/infrastructure/modules/sqs/data_iam_policy_document_deadletter_queue.tf @@ -0,0 +1,24 @@ +data "aws_iam_policy_document" "deadletter_queue" { + count = var.create_dlq ? 1 : 0 + + statement { + effect = "Allow" + + resources = [aws_sqs_queue.deadletter_queue[0].arn] + + actions = [ + "sqs:ChangeMessageVisibility", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ListQueueTags", + "sqs:ReceiveMessage", + "sqs:SendMessage", + ] + + principals { + type = "AWS" + identifiers = [var.aws_account_id] + } + } +} diff --git a/infrastructure/modules/sqs/data_iam_policy_document_sqs_queue.tf b/infrastructure/modules/sqs/data_iam_policy_document_sqs_queue.tf new file mode 100644 index 0000000..0c9858a --- /dev/null +++ b/infrastructure/modules/sqs/data_iam_policy_document_sqs_queue.tf @@ -0,0 +1,54 @@ +data "aws_iam_policy_document" "sqs_queue" { + statement { + effect = "Allow" + + resources = [aws_sqs_queue.sqs_queue.arn] + + actions = [ + "sqs:ChangeMessageVisibility", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ListQueueTags", + "sqs:ReceiveMessage", + "sqs:SendMessage", + ] + + principals { + type = "AWS" + identifiers = [var.aws_account_id] + } + } + + dynamic "statement" { + for_each = var.sns_source_arn != null ? [1] : [] + + content { + effect = "Allow" + + principals { + type = "Service" + identifiers = [ + "sns.amazonaws.com" + ] + } + + actions = [ + "sqs:SendMessage", + "sqs:SendMessageBatch", + ] + + condition { + test = "ArnEquals" + variable = "aws:SourceArn" + values = [ + var.sns_source_arn + ] + } + + resources = [ + aws_sqs_queue.sqs_queue.arn, + ] + } + } +} diff --git a/infrastructure/modules/sqs/locals.tf b/infrastructure/modules/sqs/locals.tf new file mode 100644 index 0000000..c2549e7 --- /dev/null +++ b/infrastructure/modules/sqs/locals.tf @@ -0,0 +1,36 @@ +locals { + # Compound Scope Identifier + csi = replace( + format( + "%s-%s-%s-%s", + var.project, + var.environment, + var.component, + var.name + ), + "_", + "", + ) + + # CSI for use in resources with a global namespace, i.e. S3 Buckets + csi_global = replace( + format( + "%s-%s-%s-%s-%s", + var.project, + var.aws_account_id, + var.region, + var.environment, + var.component, + ), + "_", + "", + ) + + default_tags = merge( + var.default_tags, + { + Module = var.module + Name = local.csi + }, + ) +} diff --git a/infrastructure/modules/sqs/outputs.tf b/infrastructure/modules/sqs/outputs.tf new file mode 100644 index 0000000..09a5ca0 --- /dev/null +++ b/infrastructure/modules/sqs/outputs.tf @@ -0,0 +1,23 @@ +output "sqs_queue_url" { + value = aws_sqs_queue.sqs_queue.id +} + +output "sqs_queue_arn" { + value = aws_sqs_queue.sqs_queue.arn +} + +output "sqs_dlq_url" { + value = var.create_dlq ? aws_sqs_queue.deadletter_queue[0].id : null +} + +output "sqs_dlq_arn" { + value = var.create_dlq ? aws_sqs_queue.deadletter_queue[0].arn : null +} + +output "sqs_queue_name" { + value = "${local.csi}-queue" +} + +output "sqs_dlq_name" { + value = var.create_dlq ? aws_sqs_queue.deadletter_queue[0].name : null +} diff --git a/infrastructure/modules/sqs/sqs_queue.tf b/infrastructure/modules/sqs/sqs_queue.tf new file mode 100644 index 0000000..1a9817c --- /dev/null +++ b/infrastructure/modules/sqs/sqs_queue.tf @@ -0,0 +1,14 @@ +resource "aws_sqs_queue" "sqs_queue" { + name = "${local.csi}-queue" + + message_retention_seconds = var.message_retention_seconds + visibility_timeout_seconds = var.visibility_timeout_seconds + fifo_queue = var.fifo_queue + content_based_deduplication = var.content_based_deduplication + max_message_size = var.max_message_size + + kms_master_key_id = var.sqs_kms_key_arn + kms_data_key_reuse_period_seconds = var.kms_data_key_reuse_period_seconds + + tags = local.default_tags +} diff --git a/infrastructure/modules/sqs/sqs_queue_deadletter_queue.tf b/infrastructure/modules/sqs/sqs_queue_deadletter_queue.tf new file mode 100644 index 0000000..ac7e85b --- /dev/null +++ b/infrastructure/modules/sqs/sqs_queue_deadletter_queue.tf @@ -0,0 +1,16 @@ +resource "aws_sqs_queue" "deadletter_queue" { + count = var.create_dlq ? 1 : 0 + + name = "${local.csi}-dlq" + + message_retention_seconds = var.message_retention_seconds + visibility_timeout_seconds = var.visibility_timeout_seconds + fifo_queue = var.fifo_queue + content_based_deduplication = var.content_based_deduplication + max_message_size = var.max_message_size + + kms_master_key_id = var.sqs_kms_key_arn + kms_data_key_reuse_period_seconds = var.kms_data_key_reuse_period_seconds + + tags = local.default_tags +} diff --git a/infrastructure/modules/sqs/sqs_queue_policy.tf b/infrastructure/modules/sqs/sqs_queue_policy.tf new file mode 100644 index 0000000..e9ad7cf --- /dev/null +++ b/infrastructure/modules/sqs/sqs_queue_policy.tf @@ -0,0 +1,4 @@ +resource "aws_sqs_queue_policy" "sqs_queue_policy" { + queue_url = aws_sqs_queue.sqs_queue.id + policy = data.aws_iam_policy_document.sqs_queue.json +} diff --git a/infrastructure/modules/sqs/sqs_queue_policy_deadletter_queue.tf b/infrastructure/modules/sqs/sqs_queue_policy_deadletter_queue.tf new file mode 100644 index 0000000..4a6af82 --- /dev/null +++ b/infrastructure/modules/sqs/sqs_queue_policy_deadletter_queue.tf @@ -0,0 +1,6 @@ +resource "aws_sqs_queue_policy" "deadletter_queue" { + count = var.create_dlq ? 1 : 0 + + queue_url = aws_sqs_queue.deadletter_queue[0].id + policy = data.aws_iam_policy_document.deadletter_queue[0].json +} diff --git a/infrastructure/modules/sqs/sqs_queue_redrive_policy.tf b/infrastructure/modules/sqs/sqs_queue_redrive_policy.tf new file mode 100644 index 0000000..1df9ed2 --- /dev/null +++ b/infrastructure/modules/sqs/sqs_queue_redrive_policy.tf @@ -0,0 +1,9 @@ +resource "aws_sqs_queue_redrive_policy" "redrive_policy" { + count = var.create_dlq ? 1 : 0 + + queue_url = aws_sqs_queue.sqs_queue.url + redrive_policy = jsonencode({ + deadLetterTargetArn = aws_sqs_queue.deadletter_queue[0].arn + maxReceiveCount = 3 + }) +} diff --git a/infrastructure/modules/sqs/variables.tf b/infrastructure/modules/sqs/variables.tf new file mode 100644 index 0000000..9dc55db --- /dev/null +++ b/infrastructure/modules/sqs/variables.tf @@ -0,0 +1,112 @@ +## +# Basic Required Variables for tfscaffold Modules +## + +variable "project" { + type = string + description = "The name of the tfscaffold project" +} + +variable "environment" { + type = string + description = "The name of the tfscaffold environment" +} + +variable "component" { + type = string + description = "The name of the tfscaffold component" +} + +variable "aws_account_id" { + type = string + description = "The AWS Account ID (numeric)" +} + +variable "region" { + type = string + description = "The AWS Region" +} + +## +# tfscaffold variables specific to this module +## + +variable "module" { + type = string + description = "The variable encapsulating the name of this module" + default = "sqs" +} + +variable "default_tags" { + type = map(string) + description = "A map of default tags to apply to all taggable resources within the component" + default = {} +} + +## +# Variables specific to this module +## + +variable "name" { + type = string + description = "Name of the SQS Queue" +} + +variable "sqs_kms_key_arn" { + type = string + description = "ARN of the KMS key to encrypt SQS queue messages" +} + +variable "sns_source_arn" { + type = string + description = "ARN of an sns resource allowed to send to this resource" + default = null +} + +variable "allowed_arns" { + description = "A list of AWS account IDs allowed to access this resource" + type = list(any) + default = null +} + +variable "message_retention_seconds" { + description = "The number of seconds Amazon SQS retains a message. Integer representing seconds, from 60 (1 minute) to 1209600 (14 days)" + type = number + default = null +} + +variable "visibility_timeout_seconds" { + description = "The visibility timeout for the queue. An integer from 0 to 43200 (12 hours)" + type = number + default = 300 +} + +variable "fifo_queue" { + description = "Boolean designating a FIFO queue" + type = bool + default = false +} + +variable "content_based_deduplication" { + description = "Enables content-based deduplication for FIFO queues" + type = bool + default = false +} + +variable "kms_data_key_reuse_period_seconds" { + description = "The length of time, in seconds, for which Amazon SQS can reuse a data key to encrypt or decrypt messages before calling AWS KMS again. An integer representing seconds, between 60 seconds (1 minute) and 86,400 seconds (24 hours)" + type = number + default = 300 +} + +variable "max_message_size" { + description = "The limit of how many bytes a message can contain before Amazon SQS rejects it. An integer from 1024 bytes (1 KiB) up to 262144 bytes (256 KiB)" + type = number + default = 262144 +} + +variable "create_dlq" { + description = "Create a DLQ" + type = bool + default = false +} diff --git a/infrastructure/modules/sqs/versions.tf b/infrastructure/modules/sqs/versions.tf new file mode 100644 index 0000000..251d860 --- /dev/null +++ b/infrastructure/modules/sqs/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + } + + required_version = ">= 1.9.0" +}