Skip to content

Commit 49b24ae

Browse files
committed
Move writing IAM policies to a seperate lambda function
1 parent cc47af5 commit 49b24ae

File tree

4 files changed

+94
-14
lines changed

4 files changed

+94
-14
lines changed

terraform/envs/prod/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ module "frontend" {
8989
source = "../../modules/frontend"
9090
BucketPrefix = local.bucket_prefix
9191
CoreLambdaHost = module.lambdas.core_function_url
92+
IAMLambdaHost = module.lambdas.iam_function_url
9293
OriginVerifyKey = random_password.origin_verify_key.result
9394
ProjectId = var.ProjectId
9495
CoreCertificateArn = var.CoreCertificateArn

terraform/envs/qa/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ module "frontend" {
8282
source = "../../modules/frontend"
8383
BucketPrefix = local.bucket_prefix
8484
CoreLambdaHost = module.lambdas.core_function_url
85+
IAMLambdaHost = module.lambdas.iam_function_url
8586
OriginVerifyKey = random_password.origin_verify_key.result
8687
ProjectId = var.ProjectId
8788
CoreCertificateArn = var.CoreCertificateArn

terraform/modules/frontend/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ variable "CoreLambdaHost" {
88
description = "Host for Lambda Function URL"
99
}
1010

11+
variable "IAMLambdaHost" {
12+
type = string
13+
description = "Host for IAM Lambda Function URL"
14+
}
15+
16+
1117
variable "CorePublicDomain" {
1218
type = string
1319
description = "Core Public Host"

terraform/modules/lambdas/main.tf

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ data "archive_file" "sqs_lambda_code" {
1212

1313
locals {
1414
core_api_lambda_name = "${var.ProjectId}-main-server"
15+
core_api_iam_lambda_name = "${var.ProjectId}-iam-server"
1516
core_sqs_consumer_lambda_name = "${var.ProjectId}-sqs-consumer"
16-
entra_policies = {
17+
iam_policies = {
1718
shared = aws_iam_policy.shared_iam_policy.arn
18-
entra = aws_iam_policy.entra_policy.arn
19+
entra = aws_iam_policy.iam_policy.arn
1920
}
2021
sqs_policies = {
2122
sqs = aws_iam_policy.sqs_policy.arn
@@ -67,17 +68,16 @@ resource "aws_iam_role" "sqs_consumer_role" {
6768
})
6869
}
6970

70-
resource "aws_iam_role" "entra_role" {
71+
resource "aws_iam_role" "iam_role" {
7172
name = "${var.ProjectId}-entra-role"
7273
assume_role_policy = jsonencode({
7374
Version = "2012-10-17"
7475
Statement = [
7576
{
7677
Action = "sts:AssumeRole"
7778
Effect = "Allow"
78-
Sid = "AllowApiRole"
7979
Principal = {
80-
AWS = aws_iam_role.api_role.arn
80+
Service = "lambda.amazonaws.com"
8181
}
8282
},
8383
{
@@ -92,7 +92,7 @@ resource "aws_iam_role" "entra_role" {
9292
})
9393
}
9494

95-
resource "aws_iam_policy" "entra_policy" {
95+
resource "aws_iam_policy" "iam_policy" {
9696
name = "${var.ProjectId}-entra-policy"
9797
policy = jsonencode(({
9898
Version = "2012-10-17"
@@ -104,7 +104,27 @@ resource "aws_iam_policy" "entra_policy" {
104104
"arn:aws:secretsmanager:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:secret:infra-core-api-entra*",
105105
"arn:aws:secretsmanager:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:secret:infra-core-api-ro-entra*"
106106
]
107-
}
107+
},
108+
{
109+
Sid = "DynamoIAMReadWrite",
110+
Action = [
111+
"dynamodb:BatchGetItem",
112+
"dynamodb:BatchWriteItem",
113+
"dynamodb:ConditionCheckItem",
114+
"dynamodb:PutItem",
115+
"dynamodb:DescribeTable",
116+
"dynamodb:DeleteItem",
117+
"dynamodb:GetItem",
118+
"dynamodb:Scan",
119+
"dynamodb:Query",
120+
"dynamodb:UpdateItem"
121+
],
122+
Effect = "Allow",
123+
Resource = [
124+
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-iam-userroles",
125+
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-iam-grouproles",
126+
]
127+
},
108128
]
109129
}))
110130
}
@@ -197,6 +217,21 @@ resource "aws_iam_policy" "shared_iam_policy" {
197217
Effect = "Allow",
198218
Resource = ["*"]
199219
},
220+
{
221+
Sid = "DynamoIAMReadOnly",
222+
Action = [
223+
"dynamodb:BatchGetItem",
224+
"dynamodb:DescribeTable",
225+
"dynamodb:GetItem",
226+
"dynamodb:Scan",
227+
"dynamodb:Query",
228+
],
229+
Effect = "Allow",
230+
Resource = [
231+
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-iam-userroles",
232+
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-iam-grouproles",
233+
]
234+
},
200235
{
201236
Sid = "DynamoDBTableAccess"
202237
Action = [
@@ -220,8 +255,6 @@ resource "aws_iam_policy" "shared_iam_policy" {
220255
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-events-tickets",
221256
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-events-ticketing-metadata",
222257
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-merchstore-metadata",
223-
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-iam-userroles",
224-
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-iam-grouproles",
225258
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-stripe-links",
226259
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-stripe-links/index/*",
227260
"arn:aws:dynamodb:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:table/infra-core-api-membership-provisioning",
@@ -312,9 +345,9 @@ resource "aws_iam_role_policy_attachment" "api_attach" {
312345
policy_arn = each.value
313346
}
314347

315-
resource "aws_iam_role_policy_attachment" "entra_attach" {
316-
for_each = local.entra_policies
317-
role = aws_iam_role.entra_role.name
348+
resource "aws_iam_role_policy_attachment" "iam_attach" {
349+
for_each = local.iam_policies
350+
role = aws_iam_role.iam_role.name
318351
policy_arn = each.value
319352
}
320353
resource "aws_iam_role_policy_attachment" "sqs_attach_shared" {
@@ -323,6 +356,32 @@ resource "aws_iam_role_policy_attachment" "sqs_attach_shared" {
323356
policy_arn = each.value
324357
}
325358

359+
resource "aws_lambda_function" "iam_lambda" {
360+
depends_on = [aws_cloudwatch_log_group.api_logs]
361+
function_name = local.core_api_iam_lambda_name
362+
role = aws_iam_role.iam_role.arn
363+
architectures = ["arm64"]
364+
handler = "lambda.handler"
365+
runtime = "nodejs22.x"
366+
filename = data.archive_file.api_lambda_code.output_path
367+
timeout = 60
368+
memory_size = 2048
369+
source_code_hash = data.archive_file.api_lambda_code.output_sha256
370+
logging_config {
371+
log_format = "json"
372+
log_group = aws_cloudwatch_log_group.api_logs.arn
373+
}
374+
environment {
375+
variables = {
376+
"RunEnvironment" = var.RunEnvironment
377+
"AWS_CRT_NODEJS_BINARY_RELATIVE_PATH" = "node_modules/aws-crt/dist/bin/linux-arm64-glibc/aws-crt-nodejs.node"
378+
ORIGIN_VERIFY_KEY = var.OriginVerifyKey
379+
LinkryKvArn = var.LinkryKvArn
380+
"NODE_OPTIONS" = "--enable-source-maps"
381+
}
382+
}
383+
}
384+
326385
resource "aws_lambda_function" "api_lambda" {
327386
depends_on = [aws_cloudwatch_log_group.api_logs]
328387
function_name = local.core_api_lambda_name
@@ -339,7 +398,6 @@ resource "aws_lambda_function" "api_lambda" {
339398
"RunEnvironment" = var.RunEnvironment
340399
"AWS_CRT_NODEJS_BINARY_RELATIVE_PATH" = "node_modules/aws-crt/dist/bin/linux-arm64-glibc/aws-crt-nodejs.node"
341400
ORIGIN_VERIFY_KEY = var.OriginVerifyKey
342-
EntraRoleArn = aws_iam_role.entra_role.arn
343401
LinkryKvArn = var.LinkryKvArn
344402
"NODE_OPTIONS" = "--enable-source-maps"
345403
}
@@ -365,7 +423,7 @@ resource "aws_lambda_function" "sqs_lambda" {
365423
variables = {
366424
"RunEnvironment" = var.RunEnvironment
367425
"AWS_CRT_NODEJS_BINARY_RELATIVE_PATH" = "node_modules/aws-crt/dist/bin/linux-arm64-glibc/aws-crt-nodejs.node"
368-
EntraRoleArn = aws_iam_role.entra_role.arn
426+
EntraRoleArn = aws_iam_role.iam_role.arn
369427
"NODE_OPTIONS" = "--enable-source-maps"
370428
}
371429
}
@@ -376,13 +434,27 @@ resource "aws_lambda_function_url" "api_lambda_function_url" {
376434
authorization_type = "NONE"
377435
}
378436

437+
438+
resource "aws_lambda_function_url" "iam_lambda_function_url" {
439+
function_name = aws_lambda_function.iam_lambda.function_name
440+
authorization_type = "NONE"
441+
}
442+
443+
379444
output "core_function_url" {
380445
value = replace(replace(aws_lambda_function_url.api_lambda_function_url.function_url, "https://", ""), "/", "")
381446
}
382447

448+
output "iam_function_url" {
449+
value = replace(replace(aws_lambda_function_url.iam_lambda_function_url.function_url, "https://", ""), "/", "")
450+
}
451+
383452
output "core_api_lambda_name" {
384453
value = local.core_api_lambda_name
385454
}
455+
output "core_api_iam_lambda_name" {
456+
value = local.core_api_iam_lambda_name
457+
}
386458

387459
output "core_sqs_consumer_lambda_arn" {
388460
value = aws_lambda_function.sqs_lambda.arn

0 commit comments

Comments
 (0)