From 9bb37474e6785d93ccfa60a6c3abcc295d6bb203 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 18 Feb 2025 16:46:12 +0000 Subject: [PATCH] CDD-2443 Action PR comments --- terraform/20-app/cognito.tf | 60 ------------ terraform/20-app/outputs.tf | 1 + terraform/20-app/sns.cognito.tf | 69 ++++++++++++++ terraform/20-app/vars.tf | 6 ++ terraform/modules/api-gateway/iam.tf | 61 ++++++++++++ terraform/modules/api-gateway/lambda.tf | 37 ++++++++ terraform/modules/api-gateway/main.tf | 114 ----------------------- terraform/modules/api-gateway/outputs.tf | 5 + terraform/modules/api-gateway/vars.tf | 9 ++ terraform/modules/cognito/main.tf | 10 -- terraform/modules/cognito/outputs.tf | 5 + terraform/modules/cognito/vars.tf | 7 +- 12 files changed, 199 insertions(+), 185 deletions(-) create mode 100644 terraform/20-app/sns.cognito.tf create mode 100644 terraform/modules/api-gateway/iam.tf create mode 100644 terraform/modules/api-gateway/lambda.tf diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index 61f83979..184d4840 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -1,46 +1,3 @@ -resource "aws_iam_role" "cognito_sns_role" { - name = "${local.prefix}-cognito-sns-role" - - assume_role_policy = jsonencode({ - Version = "2012-10-17", - Statement = [ - { - Effect = "Allow", - Principal = { - Service = "cognito-idp.amazonaws.com" - }, - Action = "sts:AssumeRole" - } - ] - }) -} - -resource "aws_sns_topic" "cognito_topic" { - name = "${local.prefix}-cognito-sms-topic" -} - -resource "aws_iam_policy" "cognito_sns_policy" { - name = "${local.prefix}-cognito-sns-policy" - - policy = jsonencode({ - Version = "2012-10-17", - Statement = [ - { - Effect = "Allow", - Action = [ - "sns:Publish" - ], - Resource = aws_sns_topic.cognito_topic.arn - } - ] - }) -} - -resource "aws_iam_role_policy_attachment" "cognito_sns_policy_attachment" { - role = aws_iam_role.cognito_sns_role.name - policy_arn = aws_iam_policy.cognito_sns_policy.arn -} - module "cognito" { source = "../modules/cognito" sns_role_arn = aws_iam_role.cognito_sns_role.arn @@ -66,23 +23,6 @@ module "cognito" { prefix = local.prefix } -resource "aws_iam_role" "cognito_lambda_role" { - name = "${local.prefix}-lambda-execution-role" - - assume_role_policy = jsonencode({ - Version = "2012-10-17", - Statement = [ - { - Effect = "Allow", - Principal = { - Service = "lambda.amazonaws.com" - }, - Action = "sts:AssumeRole" - } - ] - }) -} - module "app_security_group" { source = "terraform-aws-modules/security-group/aws" version = "~> 5.0" diff --git a/terraform/20-app/outputs.tf b/terraform/20-app/outputs.tf index be4ba397..20f7cdb2 100644 --- a/terraform/20-app/outputs.tf +++ b/terraform/20-app/outputs.tf @@ -84,3 +84,4 @@ output "lambda" { ingestion_lambda_arn = module.lambda_ingestion.lambda_function_arn } } + diff --git a/terraform/20-app/sns.cognito.tf b/terraform/20-app/sns.cognito.tf new file mode 100644 index 00000000..369f102a --- /dev/null +++ b/terraform/20-app/sns.cognito.tf @@ -0,0 +1,69 @@ +module "cognito_sns" { + source = "terraform-aws-modules/sns/aws" + version = "~> 5.0" + + name = "${local.prefix}-cognito-topic" + + subscriptions = [ + { + protocol = "email" + endpoint = var.cognito_admin_email + } + ] +} + +resource "aws_iam_role" "cognito_sns_role" { + name = "${local.prefix}-cognito-sns-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Effect = "Allow", + Principal = { + Service = "cognito-idp.amazonaws.com" + }, + Action = "sts:AssumeRole" + } + ] + }) +} + +resource "aws_iam_policy" "cognito_sns_policy" { + name = "${local.prefix}-cognito-sns-policy" + description = "Allows Cognito to publish messages to the SNS topic" + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Sid = "AllowCognitoToPublish", + Effect = "Allow", + Action = ["sns:Publish"], + Resource = module.cognito_sns.topic_arn + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "cognito_sns_policy_attachment" { + role = aws_iam_role.cognito_sns_role.id + policy_arn = aws_iam_policy.cognito_sns_policy.arn +} + +resource "aws_iam_role" "cognito_lambda_role" { + name = "${local.prefix}-lambda-execution-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Effect = "Allow", + Principal = { + Service = "lambda.amazonaws.com" + }, + Action = "sts:AssumeRole" + } + ] + }) +} \ No newline at end of file diff --git a/terraform/20-app/vars.tf b/terraform/20-app/vars.tf index e277a5e1..815d2dec 100644 --- a/terraform/20-app/vars.tf +++ b/terraform/20-app/vars.tf @@ -36,4 +36,10 @@ variable "api_gateway_stage_name" { description = "The stage name for API Gateway (e.g. dev or live)" type = string default = "dev" +} + +variable "cognito_admin_email" { + description = "Admin email address for Cognito SNS notifications" + type = string + default = "Afaan.Ashiq@ukhsa.gov.uk" } \ No newline at end of file diff --git a/terraform/modules/api-gateway/iam.tf b/terraform/modules/api-gateway/iam.tf new file mode 100644 index 00000000..c2afe1d6 --- /dev/null +++ b/terraform/modules/api-gateway/iam.tf @@ -0,0 +1,61 @@ +resource "aws_api_gateway_account" "account" { + cloudwatch_role_arn = aws_iam_role.api_gateway_cloudwatch_role.arn + + depends_on = [ + aws_iam_role.api_gateway_cloudwatch_role, + aws_iam_role_policy.api_gateway_cloudwatch_policy + ] +} + +resource "aws_iam_role" "api_gateway_cloudwatch_role" { + name = "${var.prefix}-api-gateway-cloudwatch-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Effect = "Allow", + Principal = { + Service = "apigateway.amazonaws.com" + }, + Action = "sts:AssumeRole" + } + ] + }) +} + +resource "aws_iam_role_policy" "api_gateway_cloudwatch_policy" { + role = aws_iam_role.api_gateway_cloudwatch_role.id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Effect = "Allow", + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:GetLogEvents", + "logs:FilterLogEvents" + ], + Resource = [ + "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/*" + ] + }, + { + Effect = "Allow", + Action = [ + "apigateway:GET", + "apigateway:PUT", + "apigateway:POST", + "apigateway:DELETE", + "apigateway:PATCH" + ], + Resource = aws_api_gateway_rest_api.api_gateway.execution_arn + } + ] + }) +} \ No newline at end of file diff --git a/terraform/modules/api-gateway/lambda.tf b/terraform/modules/api-gateway/lambda.tf new file mode 100644 index 00000000..d37497d5 --- /dev/null +++ b/terraform/modules/api-gateway/lambda.tf @@ -0,0 +1,37 @@ +resource "aws_lambda_function" "api_gateway_lambda" { + function_name = "${var.prefix}-api-gateway-lambda" + runtime = "nodejs18.x" + role = var.lambda_role_arn + handler = "api_gateway_lambda.handler" + + source_code_hash = filebase64sha256("${path.module}/api_gateway_lambda.zip") + filename = "${path.module}/api_gateway_lambda.zip" + timeout = 15 + publish = true + description = "Handles API Gateway requests for the ${var.prefix} service" +} + +resource "aws_lambda_alias" "live" { + name = "live" + description = "Alias pointing to the live version of the Lambda function" + function_name = aws_lambda_function.api_gateway_lambda.arn + function_version = "$LATEST" +} + +resource "aws_lambda_alias" "dev" { + name = "dev" + description = "Alias pointing to the dev version of the Lambda function" + function_name = aws_lambda_function.api_gateway_lambda.arn + function_version = "$LATEST" +} + +resource "aws_lambda_permission" "allow_api_gateway" { + statement_id = "AllowAPIGatewayInvoke" + action = "lambda:InvokeFunction" + function_name = lookup({ + "live" = aws_lambda_alias.live.arn, + "dev" = aws_lambda_alias.dev.arn + }, var.lambda_alias, aws_lambda_alias.live.arn) + principal = "apigateway.amazonaws.com" + source_arn = "arn:aws:execute-api:${var.region}:${data.aws_caller_identity.current.account_id}:${aws_api_gateway_rest_api.api_gateway.id}/*/*/*" +} \ No newline at end of file diff --git a/terraform/modules/api-gateway/main.tf b/terraform/modules/api-gateway/main.tf index ebcb9662..2a6791bf 100644 --- a/terraform/modules/api-gateway/main.tf +++ b/terraform/modules/api-gateway/main.tf @@ -1,32 +1,5 @@ data "aws_caller_identity" "current" {} -resource "aws_lambda_function" "api_gateway_lambda" { - function_name = "${var.prefix}-api-gateway-lambda" - runtime = "nodejs18.x" - role = var.lambda_role_arn - handler = "api_gateway_lambda.handler" - - source_code_hash = filebase64sha256("${path.module}/api_gateway_lambda.zip") - filename = "${path.module}/api_gateway_lambda.zip" - timeout = 15 - publish = true - description = "Handles API Gateway requests for the ${var.prefix} service" -} - -resource "aws_lambda_alias" "live" { - name = "live" - description = "Alias pointing to the live version of the Lambda function" - function_name = aws_lambda_function.api_gateway_lambda.arn - function_version = "$LATEST" -} - -resource "aws_lambda_alias" "dev" { - name = "dev" - description = "Alias pointing to the dev version of the Lambda function" - function_name = aws_lambda_function.api_gateway_lambda.arn - function_version = "$LATEST" -} - resource "aws_api_gateway_rest_api" "api_gateway" { name = var.name description = var.description @@ -95,90 +68,3 @@ resource "aws_api_gateway_stage" "stage" { prevent_destroy = false } } - -resource "aws_api_gateway_account" "account" { - cloudwatch_role_arn = aws_iam_role.api_gateway_cloudwatch_role.arn - - depends_on = [ - aws_iam_role.api_gateway_cloudwatch_role, - aws_iam_role_policy.api_gateway_cloudwatch_policy - ] -} - -resource "aws_iam_role" "api_gateway_cloudwatch_role" { - name = "${var.prefix}-api-gateway-cloudwatch-role" - - assume_role_policy = jsonencode({ - Version = "2012-10-17", - Statement = [ - { - Effect = "Allow", - Principal = { - Service = "apigateway.amazonaws.com" - }, - Action = "sts:AssumeRole" - } - ] - }) -} - -resource "aws_iam_role_policy" "api_gateway_cloudwatch_policy" { - role = aws_iam_role.api_gateway_cloudwatch_role.id - - policy = jsonencode({ - Version = "2012-10-17", - Statement = [ - { - Effect = "Allow", - Action = [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:GetLogEvents", - "logs:FilterLogEvents" - ], - Resource = [ - "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/*" - ] - }, - { - Effect = "Allow", - Action = [ - "apigateway:GET", - "apigateway:PUT", - "apigateway:POST", - "apigateway:DELETE", - "apigateway:PATCH" - ], - Resource = aws_api_gateway_rest_api.api_gateway.execution_arn - } - ] - }) -} - -resource "aws_lambda_permission" "allow_api_gateway" { - statement_id = "AllowAPIGatewayInvoke" - action = "lambda:InvokeFunction" - function_name = lookup({ - "live" = aws_lambda_alias.live.arn, - "dev" = aws_lambda_alias.dev.arn - }, var.lambda_alias, aws_lambda_alias.live.arn) - principal = "apigateway.amazonaws.com" - source_arn = "arn:aws:execute-api:${var.region}:${data.aws_caller_identity.current.account_id}:${aws_api_gateway_rest_api.api_gateway.id}/*/*/*" -} - -output "api_gateway_lambda_arn" { - description = "The ARN of the API Gateway Lambda function" - value = aws_lambda_function.api_gateway_lambda.arn -} - -variable "prefix" { - description = "Prefix for naming resources" - type = string - validation { - condition = can(regex("^[a-zA-Z0-9_-]+$", var.prefix)) - error_message = "Prefix must only contain letters, numbers, hyphens, or underscores." - } -} diff --git a/terraform/modules/api-gateway/outputs.tf b/terraform/modules/api-gateway/outputs.tf index c2787882..02c241b0 100644 --- a/terraform/modules/api-gateway/outputs.tf +++ b/terraform/modules/api-gateway/outputs.tf @@ -24,4 +24,9 @@ output "lambda_alias_arn" { "live" = aws_lambda_alias.live.arn, "dev" = aws_lambda_alias.dev.arn }, var.lambda_alias, aws_lambda_alias.live.arn) +} + +output "api_gateway_lambda_arn" { + description = "The ARN of the API Gateway Lambda function" + value = aws_lambda_function.api_gateway_lambda.arn } \ No newline at end of file diff --git a/terraform/modules/api-gateway/vars.tf b/terraform/modules/api-gateway/vars.tf index 3f551db8..89b0ac5d 100644 --- a/terraform/modules/api-gateway/vars.tf +++ b/terraform/modules/api-gateway/vars.tf @@ -100,4 +100,13 @@ variable "lambda_alias" { condition = contains(["dev", "live"], var.lambda_alias) error_message = "Invalid alias provided. Allowed values are 'dev' or 'live'." } +} + +variable "prefix" { + description = "Prefix for naming resources" + type = string + validation { + condition = can(regex("^[a-zA-Z0-9_-]+$", var.prefix)) + error_message = "Prefix must only contain letters, numbers, hyphens, or underscores." + } } \ No newline at end of file diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 489b77f7..e4b6d33c 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -94,13 +94,3 @@ resource "aws_cognito_user_group" "cognito_user_groups" { precedence = lookup(var.group_precedence, each.value, null) description = "Group for ${each.value} role" } - -output "cognito_lambda_role_arn" { - description = "The ARN of the Cognito Lambda execution role" - value = var.lambda_role_arn -} - -variable "prefix" { - description = "Prefix for naming resources" - type = string -} diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 12d4b9a0..c4dd7b05 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -63,3 +63,8 @@ output "cognito_user_pool_issuer_endpoint" { value = "https://cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.user_pool.id}" sensitive = true } + +output "cognito_lambda_role_arn" { + description = "The ARN of the Cognito Lambda execution role" + value = var.lambda_role_arn +} diff --git a/terraform/modules/cognito/vars.tf b/terraform/modules/cognito/vars.tf index 826cbffe..ed3d82cc 100644 --- a/terraform/modules/cognito/vars.tf +++ b/terraform/modules/cognito/vars.tf @@ -87,4 +87,9 @@ variable "enable_ukhsa_oidc" { variable "lambda_role_arn" { description = "The ARN of the Cognito Lambda execution role" type = string -} \ No newline at end of file +} + +variable "prefix" { + description = "Prefix for naming resources" + type = string +}