Skip to content

Commit 2c84f08

Browse files
authored
feat: add SQS queue & grant FastAPI Lambda access (#6)
1 parent ba17731 commit 2c84f08

File tree

9 files changed

+197
-2
lines changed

9 files changed

+197
-2
lines changed

infra/env/dev/api-gateway/terragrunt.hcl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ include {
33
}
44

55
dependencies {
6-
paths = ["../network"]
6+
paths = ["../network", "../sqs"]
77
}
88

99
dependency "network" {
@@ -16,9 +16,21 @@ dependency "network" {
1616
}
1717
}
1818

19+
dependency "sqs" {
20+
config_path = "../sqs"
21+
22+
mock_outputs_allowed_terraform_commands = ["init", "fmt", "validate", "plan", "show"]
23+
mock_outputs = {
24+
message_queue_arn = ""
25+
message_queue_url = ""
26+
}
27+
}
28+
1929
inputs = {
2030
lambda_subnet_ids = dependency.network.outputs.lambda_subnet_ids
2131
lambda_security_group_id = dependency.network.outputs.lambda_security_group_id
32+
message_queue_arn = dependency.sqs.outputs.message_queue_arn
33+
message_queue_url = dependency.sqs.outputs.message_queue_url
2234
}
2335

2436
terraform {

infra/env/dev/sqs/terragrunt.hcl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
include {
2+
path = find_in_parent_folders()
3+
}
4+
5+
inputs = {
6+
lambda_producer_function_name = "FastAPI"
7+
max_receive_count = 5
8+
}
9+
10+
terraform {
11+
source = "../../../modules//sqs"
12+
}

infra/modules/api-gateway/lambda.tf

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ resource "aws_lambda_function" "api_lambda" {
1818
mode = "PassThrough"
1919
}
2020

21+
environment {
22+
variables = {
23+
message_queue_url = var.message_queue_url
24+
}
25+
}
26+
2127
tags = {
2228
Name = "${var.project_name}-function"
2329
Project = var.project_name
@@ -35,6 +41,32 @@ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
3541
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
3642
}
3743

44+
resource "aws_iam_role_policy_attachment" "lambda_sqs_producer_policy_attachment" {
45+
role = aws_iam_role.api_lambda_role.name
46+
policy_arn = aws_iam_policy.lambda_sqs_producer_policy.arn
47+
}
48+
49+
resource "aws_iam_policy" "lambda_sqs_producer_policy" {
50+
name = "LambdaSqsProducer"
51+
description = "IAM policy for creating messages in an SQS queue"
52+
path = "/"
53+
policy = data.aws_iam_policy_document.lambda_sqs_producer_policy.json
54+
}
55+
56+
data "aws_iam_policy_document" "lambda_sqs_producer_policy" {
57+
statement {
58+
effect = "Allow"
59+
actions = [
60+
"sqs:GetQueueAttributes",
61+
"sqs:GetQueueUrl",
62+
"sqs:SendMessage*"
63+
]
64+
resources = [
65+
var.message_queue_arn
66+
]
67+
}
68+
}
69+
3870
data "aws_iam_policy_document" "lambda_assume_policy" {
3971
statement {
4072
effect = "Allow"

infra/modules/api-gateway/variables.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,13 @@ variable "lambda_security_group_id" {
77
description = "Lambda's security group ID"
88
type = string
99
}
10+
11+
variable "message_queue_arn" {
12+
description = "ARN of the SQS to send messages to"
13+
type = string
14+
}
15+
16+
variable "message_queue_url" {
17+
description = "URL of the SQS to send messages to"
18+
type = string
19+
}

infra/modules/network/vpc.tf

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ resource "aws_security_group_rule" "vpc_endpoints_from_lambda" {
6666
}
6767

6868
resource "aws_security_group_rule" "lambda_to_vpc_endpoints" {
69-
description = "Security group rule for egress to "
69+
description = "Security group rule for egress to VPC endpoints"
7070
type = "egress"
7171
from_port = 443
7272
to_port = 443
@@ -127,3 +127,18 @@ resource "aws_vpc_endpoint" "monitoring" {
127127
]
128128
subnet_ids = aws_subnet.api_subnet.*.id
129129
}
130+
131+
#
132+
# PrivateLink endpoint to SQS
133+
#
134+
135+
resource "aws_vpc_endpoint" "sqs" {
136+
vpc_id = aws_vpc.api_vpc.id
137+
vpc_endpoint_type = "Interface"
138+
service_name = "com.amazonaws.${var.region}.sqs"
139+
private_dns_enabled = true
140+
security_group_ids = [
141+
aws_security_group.vpc_endpoints.id,
142+
]
143+
subnet_ids = aws_subnet.api_subnet.*.id
144+
}

infra/modules/sqs/data.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data "aws_caller_identity" "current" {}

infra/modules/sqs/output.tf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
output "message_queue_arn" {
2+
value = aws_sqs_queue.message_queue.arn
3+
}
4+
5+
output "message_queue_url" {
6+
value = aws_sqs_queue.message_queue.url
7+
}

infra/modules/sqs/sqs.tf

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
locals {
2+
account_id = data.aws_caller_identity.current.account_id
3+
}
4+
5+
resource "aws_sqs_queue" "message_queue" {
6+
name = "message-queue"
7+
max_message_size = 1024
8+
message_retention_seconds = 86400 # 1 day
9+
kms_master_key_id = "alias/aws/sqs"
10+
11+
redrive_policy = jsonencode({
12+
deadLetterTargetArn = aws_sqs_queue.message_deadletter_queue.arn
13+
maxReceiveCount = var.max_receive_count
14+
})
15+
16+
tags = {
17+
Name = "${var.project_name}-message-queue"
18+
Project = var.project_name
19+
Billing = var.project_team
20+
}
21+
}
22+
23+
# Only allow this account to send messages to the queue
24+
resource "aws_sqs_queue_policy" "message_queue_policy" {
25+
queue_url = aws_sqs_queue.message_queue.id
26+
policy = data.aws_iam_policy_document.message_queue_policy.json
27+
}
28+
29+
data "aws_iam_policy_document" "message_queue_policy" {
30+
statement {
31+
effect = "Allow"
32+
actions = [
33+
"sqs:GetQueueAttributes",
34+
"sqs:GetQueueUrl",
35+
"sqs:SendMessage*"
36+
]
37+
resources = [
38+
aws_sqs_queue.message_queue.arn
39+
]
40+
principals {
41+
type = "Service"
42+
identifiers = ["lambda.amazonaws.com"]
43+
}
44+
condition {
45+
test = "ArnLike"
46+
variable = "aws:SourceArn"
47+
48+
values = [
49+
"arn:aws:lambda:${var.region}:${local.account_id}:function:${var.lambda_producer_function_name}*"
50+
]
51+
}
52+
}
53+
}
54+
55+
resource "aws_sqs_queue" "message_deadletter_queue" {
56+
name = "message-deadletter-queue"
57+
max_message_size = 1024
58+
message_retention_seconds = 604800 # 1 week
59+
kms_master_key_id = "alias/aws/sqs"
60+
61+
tags = {
62+
Name = "${var.project_name}-message-deadletter-queue"
63+
Project = var.project_name
64+
Billing = var.project_team
65+
}
66+
}
67+
68+
# Only allow the message queue to send messages to the deadletter queue
69+
resource "aws_sqs_queue_policy" "message_deadletter_queue_policy" {
70+
queue_url = aws_sqs_queue.message_deadletter_queue.id
71+
policy = data.aws_iam_policy_document.message_deadletter_queue_policy.json
72+
}
73+
74+
data "aws_iam_policy_document" "message_deadletter_queue_policy" {
75+
statement {
76+
effect = "Allow"
77+
actions = [
78+
"sqs:GetQueueAttributes",
79+
"sqs:GetQueueUrl",
80+
"sqs:SendMessage*"
81+
]
82+
resources = [
83+
aws_sqs_queue.message_deadletter_queue.arn
84+
]
85+
principals {
86+
type = "Service"
87+
identifiers = ["sqs.amazonaws.com"]
88+
}
89+
condition {
90+
test = "ArnEquals"
91+
variable = "aws:SourceArn"
92+
values = [
93+
aws_sqs_queue.message_queue.arn
94+
]
95+
}
96+
}
97+
}

infra/modules/sqs/variables.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
variable "lambda_producer_function_name" {
2+
description = "Name of the Lambda function that produces messages for the SQS queue"
3+
type = string
4+
}
5+
6+
variable "max_receive_count" {
7+
description = "Max number of times a message can be processed without deletion before sent to the deadletter queue"
8+
type = number
9+
}

0 commit comments

Comments
 (0)