From 45710e5d6bff1b60bfed240310bdc9d73baaf29c Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Wed, 22 Jan 2025 16:38:53 +0000 Subject: [PATCH 01/38] CDD-2443 Create cognito module using terraform --- terraform/20-app/main.tf | 57 ++++++++++++++++++++++++++ terraform/modules/cognito/main.tf | 43 +++++++++++++++++++ terraform/modules/cognito/outputs.tf | 15 +++++++ terraform/modules/cognito/variables.tf | 33 +++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 terraform/modules/cognito/main.tf create mode 100644 terraform/modules/cognito/outputs.tf create mode 100644 terraform/modules/cognito/variables.tf diff --git a/terraform/20-app/main.tf b/terraform/20-app/main.tf index 2c2e71c9..b9884e9d 100644 --- a/terraform/20-app/main.tf +++ b/terraform/20-app/main.tf @@ -18,6 +18,13 @@ provider "aws" { assume_role { role_arn = "arn:aws:iam::${var.assume_account_id}:role/${var.assume_role_name}" } + + default_tags { + tags = { + project_name = local.project + env = terraform.workspace + } + } } terraform { @@ -28,3 +35,53 @@ terraform { key = "app/state.tfstate" } } + +module "cognito" { + source = "../modules/cognito" + + user_pool_name = "app-${terraform.workspace}-user-pool" + client_name = "app-${terraform.workspace}-client" + user_pool_domain = "app-${terraform.workspace}-auth" + + callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] + logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] +} + +resource "aws_security_group" "app_security_group" { + name = "app-security-group" + description = "Security group for the application" + vpc_id = module.vpc.vpc_id + + ingress { + description = "Allow traffic from app to RDS" + from_port = 5432 + to_port = 5432 + protocol = "tcp" + security_groups = [module.aurora_db_app.security_group_id] + self = false + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + +output "rds_connection_info" { + description = "Connection details for the Aurora RDS cluster" + value = { + endpoint = module.aurora_db_app.cluster_endpoint + port = module.aurora_db_app.cluster_port + db_name = module.aurora_db_app.cluster_database_name + username = module.aurora_db_app.cluster_master_username + password = module.aurora_db_app.cluster_master_password + } + sensitive = true +} + +output "cognito_user_pool_id" { + description = "Cognito User Pool ID" + value = module.cognito.user_pool_id +} \ No newline at end of file diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf new file mode 100644 index 00000000..5c75c201 --- /dev/null +++ b/terraform/modules/cognito/main.tf @@ -0,0 +1,43 @@ +resource "aws_cognito_user_pool" "user_pool" { + name = var.user_pool_name + + password_policy { + minimum_length = 8 + require_lowercase = true + require_numbers = true + require_symbols = false + require_uppercase = true + } + + auto_verified_attributes = ["email"] + + account_recovery_setting { + recovery_mechanism { + name = "verified_email" + priority = 1 + } + } +} + +resource "aws_cognito_user_pool_client" "user_pool_client" { + name = var.client_name + user_pool_id = aws_cognito_user_pool.user_pool.id + + allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_flows_user_pool_client = true + allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] + + callback_urls = var.callback_urls + logout_urls = var.logout_urls + + supported_identity_providers = ["COGNITO"] +} + +resource "aws_cognito_user_pool_domain" "user_pool_domain" { + domain = var.user_pool_domain + user_pool_id = aws_cognito_user_pool.user_pool.id + + lifecycle { + ignore_changes = [domain] + } +} \ No newline at end of file diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf new file mode 100644 index 00000000..dd25709c --- /dev/null +++ b/terraform/modules/cognito/outputs.tf @@ -0,0 +1,15 @@ +output "user_pool_id" { + description = "The ID of the Cognito User Pool" + value = aws_cognito_user_pool.user_pool.id +} + +output "user_pool_client_id" { + description = "The ID of the Cognito User Pool Client" + value = aws_cognito_user_pool_client.user_pool_client.id +} + +output "user_pool_domain" { + description = "The Cognito User Pool domain" + value = aws_cognito_user_pool_domain.user_pool_domain.domain +} + diff --git a/terraform/modules/cognito/variables.tf b/terraform/modules/cognito/variables.tf new file mode 100644 index 00000000..24ddef9b --- /dev/null +++ b/terraform/modules/cognito/variables.tf @@ -0,0 +1,33 @@ +variable "user_pool_name" { + description = "The name of the Cognito User Pool" + type = string +} + +variable "client_name" { + description = "The name of the Cognito User Pool Client" + type = string +} + +variable "user_pool_domain" { + description = "The domain prefix for Cognito User Pool" + type = string + default = null +} + +variable "callback_urls" { + description = "A list of allowed callback URLs for the User Pool Client" + type = list(string) + default = [] +} + +variable "logout_urls" { + description = "A list of allowed logout URLs for the User Pool Client" + type = list(string) + default = [] +} + +variable "tags" { + description = "Tags to apply to all resources" + type = map(string) + default = {} +} \ No newline at end of file From 8e0dd349123901dafea840b5ff666f45bad49da1 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Fri, 24 Jan 2025 14:30:29 +0000 Subject: [PATCH 02/38] CDD-2443 Add identity providers and SNS code --- terraform/20-app/main.tf | 67 +++++++++++++++++-- terraform/modules/cognito/main.tf | 62 ++++++++++++++++-- terraform/modules/cognito/outputs.tf | 34 ++++++++-- terraform/modules/cognito/variables.tf | 89 ++++++++++++++++++++++---- 4 files changed, 224 insertions(+), 28 deletions(-) diff --git a/terraform/20-app/main.tf b/terraform/20-app/main.tf index b9884e9d..12d38fc4 100644 --- a/terraform/20-app/main.tf +++ b/terraform/20-app/main.tf @@ -36,15 +36,65 @@ terraform { } } +resource "aws_iam_role" "cognito_sns_role" { + name = "cognito-sns-role-${terraform.workspace}" + + 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 = "cognito-sms-topic-${terraform.workspace}" +} + +resource "aws_iam_policy" "cognito_sns_policy" { + name = "cognito-sns-policy-${terraform.workspace}" + + 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 user_pool_name = "app-${terraform.workspace}-user-pool" client_name = "app-${terraform.workspace}-client" - user_pool_domain = "app-${terraform.workspace}-auth" + user_pool_domain = "app-${terraform.workspace}-domain" + callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] + logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] - callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] - logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] + nhs_metadata_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/nhs-metadata.xml" + cobr_oidc_client_id = "cobr-client-id" + cobr_oidc_client_secret = "cobr-client-secret" + cobr_oidc_issuer_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/cobr-issuer" + cobr_oidc_attributes_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/attributes" + region = local.region } resource "aws_security_group" "app_security_group" { @@ -83,5 +133,12 @@ output "rds_connection_info" { output "cognito_user_pool_id" { description = "Cognito User Pool ID" - value = module.cognito.user_pool_id -} \ No newline at end of file + value = module.cognito.cognito_user_pool_id + sensitive = true +} + +output "cognito_user_pool_client_id" { + description = "Cognito User Pool Client ID" + value = module.cognito.cognito_user_pool_client_id + sensitive = true +} diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 5c75c201..f0cc9849 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -1,6 +1,17 @@ resource "aws_cognito_user_pool" "user_pool" { name = var.user_pool_name + mfa_configuration = var.enable_mfa ? "ON" : "OFF" + + dynamic "sms_configuration" { + for_each = var.enable_sms ? [1] : [] + + content { + sns_caller_arn = var.sns_role_arn != null ? var.sns_role_arn : "" + external_id = "cognito-sms-external-id" + } + } + password_policy { minimum_length = 8 require_lowercase = true @@ -9,7 +20,7 @@ resource "aws_cognito_user_pool" "user_pool" { require_uppercase = true } - auto_verified_attributes = ["email"] + auto_verified_attributes = var.enable_sms ? ["email", "phone_number"] : ["email"] account_recovery_setting { recovery_mechanism { @@ -20,17 +31,22 @@ resource "aws_cognito_user_pool" "user_pool" { } resource "aws_cognito_user_pool_client" "user_pool_client" { +# depends_on = [ +# aws_cognito_identity_provider.oidc_idp, +# aws_cognito_identity_provider.saml_idp +# ] + name = var.client_name user_pool_id = aws_cognito_user_pool.user_pool.id - allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_flows = ["code", "implicit"] allowed_oauth_flows_user_pool_client = true - allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] + allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] callback_urls = var.callback_urls logout_urls = var.logout_urls - supported_identity_providers = ["COGNITO"] + supported_identity_providers = ["COGNITO"] # but will support:- ["COGNITO", "NHS", "COBR"] } resource "aws_cognito_user_pool_domain" "user_pool_domain" { @@ -40,4 +56,40 @@ resource "aws_cognito_user_pool_domain" "user_pool_domain" { lifecycle { ignore_changes = [domain] } -} \ No newline at end of file +} + +# Commenting out identity providers until details are available +#resource "aws_cognito_identity_provider" "saml_idp" { +# user_pool_id = aws_cognito_user_pool.user_pool.id +# provider_name = "NHS" +# provider_type = "SAML" + +# provider_details = { +# MetadataURL = var.nhs_metadata_url +# IDPSignout = false +# } +#} + +#resource "aws_cognito_identity_provider" "oidc_idp" { +# user_pool_id = aws_cognito_user_pool.user_pool.id +# provider_name = "COBR" +# provider_type = "OIDC" + +# provider_details = { +# authorize_scopes = "openid email" +# client_id = var.cobr_oidc_client_id +# client_secret = var.cobr_oidc_client_secret +# oidc_issuer = var.cobr_oidc_issuer_url +# attributes_request_method = "GET" +# attributes_url = var.cobr_oidc_attributes_url +# attributes_url_add_attributes = "true" +# } +#} + +resource "aws_cognito_user_group" "user_groups" { + for_each = toset(["Admin", "Analyst", "Viewer"]) + name = each.value + user_pool_id = aws_cognito_user_pool.user_pool.id + precedence = lookup(var.group_precedence, each.value, null) + description = "Group for ${each.value} role" +} diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index dd25709c..32f55a54 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -1,15 +1,41 @@ -output "user_pool_id" { +output "cognito_user_pool_id" { description = "The ID of the Cognito User Pool" value = aws_cognito_user_pool.user_pool.id + sensitive = true } -output "user_pool_client_id" { +output "cognito_user_pool_client_id" { description = "The ID of the Cognito User Pool Client" value = aws_cognito_user_pool_client.user_pool_client.id + sensitive = true } -output "user_pool_domain" { - description = "The Cognito User Pool domain" +output "cognito_user_pool_domain" { + description = "The domain prefix for the Cognito User Pool" value = aws_cognito_user_pool_domain.user_pool_domain.domain + sensitive = true } +output "cognito_oauth_authorize_url" { + description = "The Cognito User Pool OAuth authorize URL" + value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/authorize" + sensitive = true +} + +output "cognito_oauth_logout_url" { + description = "The Cognito User Pool OAuth logout URL" + value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/logout" + sensitive = true +} + +output "cognito_oauth_token_url" { + description = "The Cognito User Pool OAuth token URL" + value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/token" + sensitive = true +} + +output "cognito_oauth_userinfo_url" { + description = "The Cognito User Pool OAuth userinfo URL" + value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/userInfo" + sensitive = true +} \ No newline at end of file diff --git a/terraform/modules/cognito/variables.tf b/terraform/modules/cognito/variables.tf index 24ddef9b..3690b2c9 100644 --- a/terraform/modules/cognito/variables.tf +++ b/terraform/modules/cognito/variables.tf @@ -1,33 +1,94 @@ -variable "user_pool_name" { - description = "The name of the Cognito User Pool" +variable "region" { + description = "The AWS region for resources" type = string } -variable "client_name" { - description = "The name of the Cognito User Pool Client" +variable "sns_role_arn" { + description = "ARN of the SNS role for MFA" type = string + default = null + validation { + condition = can(regex("^arn:aws:iam::\\d+:role/.+", var.sns_role_arn)) + error_message = "sns_role_arn must be a valid ARN of an IAM Role." + } } -variable "user_pool_domain" { - description = "The domain prefix for Cognito User Pool" +variable "nhs_metadata_url" { + description = "Metadata URL for NHS SAML IdP" + type = string + default = "https://auth.nhs.gov.uk" +} + +variable "cobr_oidc_client_id" { + description = "Client ID for COBR OIDC IdP" + type = string +} + +variable "cobr_oidc_client_secret" { + description = "Client secret for COBR OIDC IdP" + type = string +} + +variable "cobr_oidc_issuer_url" { + description = "Issuer URL for COBR OIDC IdP" + type = string + default = "https://auth.cobr.gov.uk" +} + +variable "cobr_oidc_attributes_url" { + description = "Attributes URL for COBR OIDC IdP" type = string - default = null } variable "callback_urls" { - description = "A list of allowed callback URLs for the User Pool Client" + description = "List of allowed callback URLs for OAuth flows" type = list(string) default = [] + validation { + condition = alltrue([for url in var.callback_urls : can(regex("^(http|https)://", url))]) + error_message = "Each callback URL must start with http:// or https://" + } } variable "logout_urls" { - description = "A list of allowed logout URLs for the User Pool Client" + description = "List of allowed logout URLs for OAuth flows" type = list(string) default = [] } -variable "tags" { - description = "Tags to apply to all resources" - type = map(string) - default = {} -} \ No newline at end of file +variable "group_precedence" { + description = "Precedence of user groups" + type = map(number) + default = { + Admin = 1 + Analyst = 2 + Viewer = 3 + } +} + +variable "user_pool_name" { + description = "Name of the Cognito User Pool" + type = string +} + +variable "client_name" { + description = "Name of the Cognito User Pool Client" + type = string +} + +variable "user_pool_domain" { + description = "Domain for the Cognito User Pool" + type = string +} + +variable "enable_mfa" { + description = "Enable Multi-Factor Authentication (MFA) for Cognito. If true, MFA will be enforced." + type = bool + default = false +} + +variable "enable_sms" { + description = "Enable SMS functionality for Cognito (e.g. for MFA or auto-verification).. Requires sns_role_arn." + type = bool + default = false +} From 98d46a903d0c1ee1c571c67010d657a0ed14acbb Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Fri, 24 Jan 2025 15:27:38 +0000 Subject: [PATCH 03/38] CDD-2443 Refactor based on PR comments --- terraform/20-app/cognito.tf | 96 ++++++++++++++++++++++++++++++++ terraform/20-app/main.tf | 106 ------------------------------------ 2 files changed, 96 insertions(+), 106 deletions(-) create mode 100644 terraform/20-app/cognito.tf diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf new file mode 100644 index 00000000..dc428c22 --- /dev/null +++ b/terraform/20-app/cognito.tf @@ -0,0 +1,96 @@ +resource "aws_iam_role" "cognito_sns_role" { + name = "cognito-sns-role-${terraform.workspace}" + + 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 = "app-${local.prefix}-cognito-sms-topic" +} + +resource "aws_iam_policy" "cognito_sns_policy" { + name = "app-${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 + user_pool_name = "app-${local.prefix}-user-pool" + client_name = "app-${local.prefix}-client" + user_pool_domain = "app-${local.prefix}-domain" + callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] + logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] + + nhs_metadata_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/nhs-metadata.xml" + cobr_oidc_client_id = "cobr-client-id" + cobr_oidc_client_secret = "cobr-client-secret" + cobr_oidc_issuer_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/cobr-issuer" + cobr_oidc_attributes_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/attributes" + region = local.region +} + +module "app_security_group" { + source = "terraform-aws-modules/security-group/aws" + version = "~> 5.0" + + name = "app-${local.prefix}-security-group" + description = "Security group for the application" + vpc_id = module.vpc.vpc_id + + computed_ingress_with_source_security_group_id = [ + { + rule = "postgresql-tcp" + source_security_group_id = module.aurora_db_app.security_group_id + } + ] + number_of_computed_ingress_with_source_security_group_id = 1 + + egress_rules = ["all-all"] + + tags = { + project_name = local.project + env = terraform.workspace + } +} + +output "cognito_user_pool_id" { + description = "Cognito User Pool ID" + value = module.cognito.cognito_user_pool_id + sensitive = true +} + +output "cognito_user_pool_client_id" { + description = "Cognito User Pool Client ID" + value = module.cognito.cognito_user_pool_client_id + sensitive = true +} \ No newline at end of file diff --git a/terraform/20-app/main.tf b/terraform/20-app/main.tf index 12d38fc4..97c581a1 100644 --- a/terraform/20-app/main.tf +++ b/terraform/20-app/main.tf @@ -36,109 +36,3 @@ terraform { } } -resource "aws_iam_role" "cognito_sns_role" { - name = "cognito-sns-role-${terraform.workspace}" - - 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 = "cognito-sms-topic-${terraform.workspace}" -} - -resource "aws_iam_policy" "cognito_sns_policy" { - name = "cognito-sns-policy-${terraform.workspace}" - - 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 - user_pool_name = "app-${terraform.workspace}-user-pool" - client_name = "app-${terraform.workspace}-client" - user_pool_domain = "app-${terraform.workspace}-domain" - callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] - logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] - - nhs_metadata_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/nhs-metadata.xml" - cobr_oidc_client_id = "cobr-client-id" - cobr_oidc_client_secret = "cobr-client-secret" - cobr_oidc_issuer_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/cobr-issuer" - cobr_oidc_attributes_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/attributes" - region = local.region -} - -resource "aws_security_group" "app_security_group" { - name = "app-security-group" - description = "Security group for the application" - vpc_id = module.vpc.vpc_id - - ingress { - description = "Allow traffic from app to RDS" - from_port = 5432 - to_port = 5432 - protocol = "tcp" - security_groups = [module.aurora_db_app.security_group_id] - self = false - } - - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } -} - -output "rds_connection_info" { - description = "Connection details for the Aurora RDS cluster" - value = { - endpoint = module.aurora_db_app.cluster_endpoint - port = module.aurora_db_app.cluster_port - db_name = module.aurora_db_app.cluster_database_name - username = module.aurora_db_app.cluster_master_username - password = module.aurora_db_app.cluster_master_password - } - sensitive = true -} - -output "cognito_user_pool_id" { - description = "Cognito User Pool ID" - value = module.cognito.cognito_user_pool_id - sensitive = true -} - -output "cognito_user_pool_client_id" { - description = "Cognito User Pool Client ID" - value = module.cognito.cognito_user_pool_client_id - sensitive = true -} From 7cca0f2f87d4e506ea416d02b54f335209a6189e Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Mon, 27 Jan 2025 11:56:23 +0000 Subject: [PATCH 04/38] CDD-2443 Add placeholders until identity providers are known --- terraform/20-app/cognito.tf | 17 ++++-- terraform/modules/cognito/main.tf | 84 ++++++++++++++------------ terraform/modules/cognito/variables.tf | 73 +++++++++++++++------- 3 files changed, 106 insertions(+), 68 deletions(-) diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index dc428c22..ffb49011 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -50,13 +50,18 @@ module "cognito" { user_pool_domain = "app-${local.prefix}-domain" callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] + region = local.region - nhs_metadata_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/nhs-metadata.xml" - cobr_oidc_client_id = "cobr-client-id" - cobr_oidc_client_secret = "cobr-client-secret" - cobr_oidc_issuer_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/cobr-issuer" - cobr_oidc_attributes_url = "https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/attributes" - region = local.region + # Placeholder for SAML metadata URL, used only when SAML is enabled + # we will need to add multiple metadata_urls e.g. cobr_metadata_url and nhs_metadata_url for each provider + metadata_url = "https://example.com/metadata.xml" + + # Placeholder for OIDC configuration, used only when OIDC is enabled + # we will need to add multiple variables e.g. cobr_oidc_client_id and nhs_oidc_client_id for each provider + oidc_client_id = "oidc-client-id" + oidc_client_secret = "oidc-client-secret" + oidc_issuer_url = "https://example.com/issuer" + oidc_attributes_url = "https://example.com/attributes" } module "app_security_group" { diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index f0cc9849..4cbba481 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -31,26 +31,26 @@ resource "aws_cognito_user_pool" "user_pool" { } resource "aws_cognito_user_pool_client" "user_pool_client" { -# depends_on = [ -# aws_cognito_identity_provider.oidc_idp, -# aws_cognito_identity_provider.saml_idp -# ] + depends_on = [ + aws_cognito_identity_provider.oidc_idp, + aws_cognito_identity_provider.saml_idp + ] name = var.client_name user_pool_id = aws_cognito_user_pool.user_pool.id - allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_flows = ["code", "implicit"] allowed_oauth_flows_user_pool_client = true - allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] + allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] callback_urls = var.callback_urls logout_urls = var.logout_urls - supported_identity_providers = ["COGNITO"] # but will support:- ["COGNITO", "NHS", "COBR"] + supported_identity_providers = var.enable_oidc ? ["COGNITO", "TBCSAML", "TBCOIDC"] : ["COGNITO"] } resource "aws_cognito_user_pool_domain" "user_pool_domain" { - domain = var.user_pool_domain + domain = var.user_pool_domain user_pool_id = aws_cognito_user_pool.user_pool.id lifecycle { @@ -58,38 +58,44 @@ resource "aws_cognito_user_pool_domain" "user_pool_domain" { } } -# Commenting out identity providers until details are available -#resource "aws_cognito_identity_provider" "saml_idp" { -# user_pool_id = aws_cognito_user_pool.user_pool.id -# provider_name = "NHS" -# provider_type = "SAML" - -# provider_details = { -# MetadataURL = var.nhs_metadata_url -# IDPSignout = false -# } -#} - -#resource "aws_cognito_identity_provider" "oidc_idp" { -# user_pool_id = aws_cognito_user_pool.user_pool.id -# provider_name = "COBR" -# provider_type = "OIDC" - -# provider_details = { -# authorize_scopes = "openid email" -# client_id = var.cobr_oidc_client_id -# client_secret = var.cobr_oidc_client_secret -# oidc_issuer = var.cobr_oidc_issuer_url -# attributes_request_method = "GET" -# attributes_url = var.cobr_oidc_attributes_url -# attributes_url_add_attributes = "true" -# } -#} +# Stubbed SAML Identity Provider +resource "aws_cognito_identity_provider" "saml_idp" { + count = var.enable_saml ? 1 : 0 + + user_pool_id = aws_cognito_user_pool.user_pool.id + provider_name = "TBCSAML" + provider_type = "SAML" + + provider_details = { + MetadataURL = var.saml_metadata_url != "" ? var.saml_metadata_url : "https://example.com/saml-metadata" + IDPSignout = var.saml_logout_url != "" ? var.saml_logout_url : "https://example.com/logout" + } +} + +# Stubbed OIDC Identity Provider +resource "aws_cognito_identity_provider" "oidc_idp" { + count = var.enable_oidc ? 1 : 0 + + user_pool_id = aws_cognito_user_pool.user_pool.id + provider_name = "TBCOIDC" + provider_type = "OIDC" + + provider_details = { + client_id = var.oidc_client_id != "" ? var.oidc_client_id : "stub-client-id" + client_secret = var.oidc_client_secret != "" ? var.oidc_client_secret : "stub-client-secret" + oidc_issuer = var.oidc_issuer_url != "" ? var.oidc_issuer_url : "https://example.com" + authorize_scopes = "openid email" + attributes_request_method = "GET" + attributes_url = var.oidc_attributes_url != "" ? var.oidc_attributes_url : "https://example.com/attributes" + attributes_url_add_attributes = "true" + } +} resource "aws_cognito_user_group" "user_groups" { for_each = toset(["Admin", "Analyst", "Viewer"]) - name = each.value - user_pool_id = aws_cognito_user_pool.user_pool.id - precedence = lookup(var.group_precedence, each.value, null) - description = "Group for ${each.value} role" + name = each.value + user_pool_id = aws_cognito_user_pool.user_pool.id + precedence = lookup(var.group_precedence, each.value, null) + description = "Group for ${each.value} role" } + diff --git a/terraform/modules/cognito/variables.tf b/terraform/modules/cognito/variables.tf index 3690b2c9..43ef41dd 100644 --- a/terraform/modules/cognito/variables.tf +++ b/terraform/modules/cognito/variables.tf @@ -13,33 +13,12 @@ variable "sns_role_arn" { } } -variable "nhs_metadata_url" { +variable "metadata_url" { description = "Metadata URL for NHS SAML IdP" type = string default = "https://auth.nhs.gov.uk" } -variable "cobr_oidc_client_id" { - description = "Client ID for COBR OIDC IdP" - type = string -} - -variable "cobr_oidc_client_secret" { - description = "Client secret for COBR OIDC IdP" - type = string -} - -variable "cobr_oidc_issuer_url" { - description = "Issuer URL for COBR OIDC IdP" - type = string - default = "https://auth.cobr.gov.uk" -} - -variable "cobr_oidc_attributes_url" { - description = "Attributes URL for COBR OIDC IdP" - type = string -} - variable "callback_urls" { description = "List of allowed callback URLs for OAuth flows" type = list(string) @@ -88,7 +67,55 @@ variable "enable_mfa" { } variable "enable_sms" { - description = "Enable SMS functionality for Cognito (e.g. for MFA or auto-verification).. Requires sns_role_arn." + description = "Enable SMS functionality for Cognito (e.g. for MFA or auto-verification). Requires sns_role_arn." type = bool default = false } + +variable "enable_saml" { + description = "Enable SAML integration" + type = bool + default = false +} + +variable "saml_metadata_url" { + description = "URL for SAML metadata" + type = string + default = "" +} + +variable "saml_logout_url" { + description = "SAML logout URL" + type = string + default = "" +} + +variable "enable_oidc" { + description = "Enable OIDC integration" + type = bool + default = false +} + +variable "oidc_client_id" { + description = "OIDC Client ID" + type = string + default = "" +} + +variable "oidc_client_secret" { + description = "OIDC Client Secret" + type = string + default = "" +} + +variable "oidc_issuer_url" { + description = "OIDC Issuer URL" + type = string + default = "" +} + +variable "oidc_attributes_url" { + description = "OIDC Attributes URL" + type = string + default = "" +} \ No newline at end of file From dd38cb5181d3de72969925ef2b6efcfa4f5d4982 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 28 Jan 2025 10:12:04 +0000 Subject: [PATCH 05/38] CDD-2443 Create user mig pre signup and post auth lambdas --- terraform/20-app/cognito.tf | 2 + terraform/modules/cognito/main.tf | 97 ++++++++++++++++-- terraform/modules/cognito/outputs.tf | 10 +- terraform/modules/cognito/post_auth.js | 4 + .../modules/cognito/post_auth_lambda.zip | Bin 0 -> 270 bytes terraform/modules/cognito/pre_signup.js | 4 + .../modules/cognito/pre_signup_lambda.zip | Bin 0 -> 271 bytes terraform/modules/cognito/user_migration.js | 4 + .../modules/cognito/user_migration_lambda.zip | Bin 0 -> 265 bytes 9 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 terraform/modules/cognito/post_auth.js create mode 100644 terraform/modules/cognito/post_auth_lambda.zip create mode 100644 terraform/modules/cognito/pre_signup.js create mode 100644 terraform/modules/cognito/pre_signup_lambda.zip create mode 100644 terraform/modules/cognito/user_migration.js create mode 100644 terraform/modules/cognito/user_migration_lambda.zip diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index ffb49011..36dcb73f 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -62,6 +62,8 @@ module "cognito" { oidc_client_secret = "oidc-client-secret" oidc_issuer_url = "https://example.com/issuer" oidc_attributes_url = "https://example.com/attributes" + + prefix = local.prefix } module "app_security_group" { diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 4cbba481..f2471f6d 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -3,6 +3,12 @@ resource "aws_cognito_user_pool" "user_pool" { mfa_configuration = var.enable_mfa ? "ON" : "OFF" + lambda_config { + post_authentication = aws_lambda_function.cognito_post_auth_lambda.arn + pre_sign_up = aws_lambda_function.cognito_pre_signup_lambda.arn + user_migration = aws_lambda_function.cognito_user_migration_lambda.arn + } + dynamic "sms_configuration" { for_each = var.enable_sms ? [1] : [] @@ -32,8 +38,8 @@ resource "aws_cognito_user_pool" "user_pool" { resource "aws_cognito_user_pool_client" "user_pool_client" { depends_on = [ - aws_cognito_identity_provider.oidc_idp, - aws_cognito_identity_provider.saml_idp + aws_cognito_identity_provider.cognito_oidc_idp, + aws_cognito_identity_provider.cognito_saml_idp ] name = var.client_name @@ -49,7 +55,7 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { supported_identity_providers = var.enable_oidc ? ["COGNITO", "TBCSAML", "TBCOIDC"] : ["COGNITO"] } -resource "aws_cognito_user_pool_domain" "user_pool_domain" { +resource "aws_cognito_user_pool_domain" "cognito_user_pool_domain" { domain = var.user_pool_domain user_pool_id = aws_cognito_user_pool.user_pool.id @@ -59,7 +65,7 @@ resource "aws_cognito_user_pool_domain" "user_pool_domain" { } # Stubbed SAML Identity Provider -resource "aws_cognito_identity_provider" "saml_idp" { +resource "aws_cognito_identity_provider" "cognito_saml_idp" { count = var.enable_saml ? 1 : 0 user_pool_id = aws_cognito_user_pool.user_pool.id @@ -73,7 +79,7 @@ resource "aws_cognito_identity_provider" "saml_idp" { } # Stubbed OIDC Identity Provider -resource "aws_cognito_identity_provider" "oidc_idp" { +resource "aws_cognito_identity_provider" "cognito_oidc_idp" { count = var.enable_oidc ? 1 : 0 user_pool_id = aws_cognito_user_pool.user_pool.id @@ -91,7 +97,7 @@ resource "aws_cognito_identity_provider" "oidc_idp" { } } -resource "aws_cognito_user_group" "user_groups" { +resource "aws_cognito_user_group" "cognito_user_groups" { for_each = toset(["Admin", "Analyst", "Viewer"]) name = each.value user_pool_id = aws_cognito_user_pool.user_pool.id @@ -99,3 +105,82 @@ resource "aws_cognito_user_group" "user_groups" { description = "Group for ${each.value} role" } +resource "aws_lambda_function" "cognito_post_auth_lambda" { + function_name = "post-auth-lambda-${var.prefix}" + runtime = "nodejs18.x" # Updated runtime + role = aws_iam_role.cognito_lambda_role.arn + + handler = "index.handler" + source_code_hash = filebase64sha256("${path.module}/post_auth_lambda.zip") + filename = "${path.module}/post_auth_lambda.zip" + timeout = 15 +} + +resource "aws_lambda_function" "cognito_pre_signup_lambda" { + function_name = "pre-signup-lambda-${var.prefix}" + runtime = "nodejs18.x" # Updated runtime + role = aws_iam_role.cognito_lambda_role.arn + + handler = "index.handler" + source_code_hash = filebase64sha256("${path.module}/pre_signup_lambda.zip") + filename = "${path.module}/pre_signup_lambda.zip" + timeout = 15 +} + +resource "aws_lambda_function" "cognito_user_migration_lambda" { + function_name = "user-migration-lambda-${var.prefix}" + runtime = "nodejs18.x" # Updated runtime + role = aws_iam_role.cognito_lambda_role.arn + + handler = "index.handler" + source_code_hash = filebase64sha256("${path.module}/user_migration_lambda.zip") + filename = "${path.module}/user_migration_lambda.zip" + timeout = 15 +} + +resource "aws_iam_role" "cognito_lambda_role" { + name = "lambda-execution-role-${var.prefix}" + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Effect = "Allow", + Principal = { + Service = "lambda.amazonaws.com" + }, + Action = "sts:AssumeRole" + } + ] + }) +} + +resource "aws_iam_role_policy" "cognito_lambda_role_policy" { + name = "lambda-execution-policy-${var.prefix}" + role = aws_iam_role.cognito_lambda_role.id + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Effect = "Allow", + Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"], + Resource = "*" + }, + { + Effect = "Allow", + Action = ["cognito-idp:PostAuthentication"], + Resource = "*" + }, + { + Effect = "Allow", + Action = ["cognito-idp:PreSignUp"], + Resource = "*" + } + ] + }) +} + +variable "prefix" { + description = "Prefix for naming resources" + type = string +} diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 32f55a54..838e0f05 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -12,30 +12,30 @@ output "cognito_user_pool_client_id" { output "cognito_user_pool_domain" { description = "The domain prefix for the Cognito User Pool" - value = aws_cognito_user_pool_domain.user_pool_domain.domain + value = aws_cognito_user_pool_domain.cognito_user_pool_domain.domain sensitive = true } output "cognito_oauth_authorize_url" { description = "The Cognito User Pool OAuth authorize URL" - value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/authorize" + value = "https://${aws_cognito_user_pool_domain.cognito_user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/authorize" sensitive = true } output "cognito_oauth_logout_url" { description = "The Cognito User Pool OAuth logout URL" - value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/logout" + value = "https://${aws_cognito_user_pool_domain.cognito_user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/logout" sensitive = true } output "cognito_oauth_token_url" { description = "The Cognito User Pool OAuth token URL" - value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/token" + value = "https://${aws_cognito_user_pool_domain.cognito_user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/token" sensitive = true } output "cognito_oauth_userinfo_url" { description = "The Cognito User Pool OAuth userinfo URL" - value = "https://${aws_cognito_user_pool_domain.user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/userInfo" + value = "https://${aws_cognito_user_pool_domain.cognito_user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/userInfo" sensitive = true } \ No newline at end of file diff --git a/terraform/modules/cognito/post_auth.js b/terraform/modules/cognito/post_auth.js new file mode 100644 index 00000000..0f56c76b --- /dev/null +++ b/terraform/modules/cognito/post_auth.js @@ -0,0 +1,4 @@ +exports.handler = async (event) => { + console.log("Post-auth Lambda invoked"); + return event; +}; \ No newline at end of file diff --git a/terraform/modules/cognito/post_auth_lambda.zip b/terraform/modules/cognito/post_auth_lambda.zip new file mode 100644 index 0000000000000000000000000000000000000000..678bbe5206d22df5638e9bbff4a6651713310627 GIT binary patch literal 270 zcmWIWW@Zs#U|`^2NXWB}QkclTGy%v<17aQq8HR%V;*$8p(vl3ltm4oRP6lS@{^{v1 zKwMhE&A`a=m63q~tlN97#tD5b&1Y=mljCa@t4_)uG+80AMYz%y4JLgXc@6v`pkA&_XxipD~b^eh%OQyKAp4qeM&zmbEs=nD99xb{u z>Cz$_)(w)^Vzypm2=HcPl4Hi@P6?oE85n?WVOY`#VxhX472;|%7YBH=vVqhx0$~u4 JUIyYY003tVR3-ob literal 0 HcmV?d00001 diff --git a/terraform/modules/cognito/pre_signup.js b/terraform/modules/cognito/pre_signup.js new file mode 100644 index 00000000..a23ac2cc --- /dev/null +++ b/terraform/modules/cognito/pre_signup.js @@ -0,0 +1,4 @@ +exports.handler = async (event) => { + console.log("Pre-signup Lambda invoked"); + return event; +}; \ No newline at end of file diff --git a/terraform/modules/cognito/pre_signup_lambda.zip b/terraform/modules/cognito/pre_signup_lambda.zip new file mode 100644 index 0000000000000000000000000000000000000000..24238153e6227307a5bb3eed3ced20eac7e7c8be GIT binary patch literal 271 zcmWIWW@Zs#U|`^2Se<7b)w|JwD;~&82V!0Z8HR$Q)cE4e^t{pny{zKU5Kac>i~ZBn zF9C6B1vdjD%U4DQ2C#P7Gmd-?1_Evm_Xhvjm~@bJmQ`b`_7pz>Q{~G-O7Hyke4Xz8 zTy0j8t>w2y5iz|un*|G+Ev9bZea92uTrkC;LXYgQp^a1!9aQ$ Hh{FH?z7$VJ literal 0 HcmV?d00001 diff --git a/terraform/modules/cognito/user_migration.js b/terraform/modules/cognito/user_migration.js new file mode 100644 index 00000000..40bc7284 --- /dev/null +++ b/terraform/modules/cognito/user_migration.js @@ -0,0 +1,4 @@ +exports.handler = async (event) => { + console.log("User migration Lambda invoked"); + return event; +}; \ No newline at end of file diff --git a/terraform/modules/cognito/user_migration_lambda.zip b/terraform/modules/cognito/user_migration_lambda.zip new file mode 100644 index 0000000000000000000000000000000000000000..205b552f3a3f3c78fbdbdc8c7eb170bfd6a65f6d GIT binary patch literal 265 zcmWIWW@Zs#U|`^2Sf6Vh<@l%iS~8HA4Hl7M$jnPgt#IsgB#Y=n${`h6k)$Y#ucEA3Jo%HJzQ+^`~{m%JjDV`CFrY zO;t%T<5^I2s;Q5E+AD*eAErAZL%P!5Z9cYc?&-DfG^MUCY3lqIuApLB^7w+)f01Kf zlbh0?%-+ABA;6oFNsbwpGbMnIWnch0hha%0h=p)8E5y-g4i4~UWdo^W1VTR`y%fY@ F001IjQz`%e literal 0 HcmV?d00001 From 393d682cf8875a5b522eda463b8418935d4cb518 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Wed, 29 Jan 2025 15:03:31 +0000 Subject: [PATCH 06/38] CDD-2443 Create api gateway --- terraform/20-app/api-gateway.tf | 13 ++ terraform/20-app/cognito.tf | 2 +- terraform/20-app/vars.tf | 6 + .../modules/api-gateway/api_gateway_lambda.js | 11 ++ .../api-gateway/api_gateway_lambda.zip | Bin 0 -> 407 bytes terraform/modules/api-gateway/main.tf | 183 ++++++++++++++++++ terraform/modules/api-gateway/outputs.tf | 27 +++ terraform/modules/api-gateway/vars.tf | 103 ++++++++++ terraform/modules/cognito/main.tf | 14 +- terraform/modules/cognito/outputs.tf | 13 +- .../modules/cognito/{variables.tf => vars.tf} | 0 11 files changed, 363 insertions(+), 9 deletions(-) create mode 100644 terraform/20-app/api-gateway.tf create mode 100644 terraform/modules/api-gateway/api_gateway_lambda.js create mode 100644 terraform/modules/api-gateway/api_gateway_lambda.zip create mode 100644 terraform/modules/api-gateway/main.tf create mode 100644 terraform/modules/api-gateway/outputs.tf create mode 100644 terraform/modules/api-gateway/vars.tf rename terraform/modules/cognito/{variables.tf => vars.tf} (100%) diff --git a/terraform/20-app/api-gateway.tf b/terraform/20-app/api-gateway.tf new file mode 100644 index 00000000..9290dfa9 --- /dev/null +++ b/terraform/20-app/api-gateway.tf @@ -0,0 +1,13 @@ +module "api_gateway" { + source = "../modules/api-gateway" + name = "app-${local.prefix}-api-gateway" + description = "API Gateway for ${local.prefix}" + api_gateway_stage_name = var.api_gateway_stage_name + lambda_role_arn = module.cognito.cognito_lambda_role_arn + cognito_user_pool_arn = module.cognito.cognito_user_pool_arn + region = local.region + resource_path_part = "{proxy+}" + lambda_invoke_arn = module.api_gateway.lambda_alias_arn + lambda_function_arn = module.api_gateway.api_gateway_lambda_arn + prefix = local.prefix +} \ No newline at end of file diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index 36dcb73f..0239fe51 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -1,5 +1,5 @@ resource "aws_iam_role" "cognito_sns_role" { - name = "cognito-sns-role-${terraform.workspace}" + name = "app-${local.prefix}-cognito-sns-role" assume_role_policy = jsonencode({ Version = "2012-10-17", diff --git a/terraform/20-app/vars.tf b/terraform/20-app/vars.tf index 7868ffef..e277a5e1 100644 --- a/terraform/20-app/vars.tf +++ b/terraform/20-app/vars.tf @@ -31,3 +31,9 @@ variable "single_nat_gateway" { } variable "halo_account_type" {} + +variable "api_gateway_stage_name" { + description = "The stage name for API Gateway (e.g. dev or live)" + type = string + default = "dev" +} \ No newline at end of file diff --git a/terraform/modules/api-gateway/api_gateway_lambda.js b/terraform/modules/api-gateway/api_gateway_lambda.js new file mode 100644 index 00000000..753144a0 --- /dev/null +++ b/terraform/modules/api-gateway/api_gateway_lambda.js @@ -0,0 +1,11 @@ +exports.handler = async (event) => { + console.log("Received event:", JSON.stringify(event, null, 2)); + + return { + statusCode: 200, + body: JSON.stringify({ message: "Hello from API Gateway via Lambda!" }), + headers: { + "Content-Type": "application/json" + } + }; +}; \ No newline at end of file diff --git a/terraform/modules/api-gateway/api_gateway_lambda.zip b/terraform/modules/api-gateway/api_gateway_lambda.zip new file mode 100644 index 0000000000000000000000000000000000000000..dd58261d2b80ec654e855a13f1d2e0ad149f68ec GIT binary patch literal 407 zcmWIWW@Zs#U|`^2$P2NFYLMG1cOA$xV`N|uWsqS=EXa&cPb^6-Pppj3Nz6@3Nz}_K z4h`XCVE(XaM*1fpF0J5ZU}X6UR1Y>Lw(qpxVFw=9??1VWSG#d7d}S0kF+kj=g@Muj zLE4>?3rG5nO?C)*df$^-YejnM$?M0b?~CFL{A|1Ft4IRx3g++)3+7oY+pw?AnMru+ zhOXszy!RTc51IJ-y$Xa(>Qv0JjRSj(+8|NK**0)Fe25aVnXHVtw3@@qkU9fI(&)FuX&(rgA zeu006X2!?&KLs}n_61)*{e7XTaplI`y{iqZ96LW?bPU o0Sqw)24D~{ENKL>aD*BwB-GGCEWn$U4Wx+?2%~|t8ps?50Q6&(0RR91 literal 0 HcmV?d00001 diff --git a/terraform/modules/api-gateway/main.tf b/terraform/modules/api-gateway/main.tf new file mode 100644 index 00000000..8293afa1 --- /dev/null +++ b/terraform/modules/api-gateway/main.tf @@ -0,0 +1,183 @@ +data "aws_caller_identity" "current" {} + +resource "aws_lambda_function" "api_gateway_lambda" { + function_name = "app-${var.prefix}-api-gateway-lambda" + runtime = "nodejs18.x" + role = var.lambda_role_arn + handler = "index.handler" + + source_code_hash = filebase64sha256("${path.module}/api_gateway_lambda.zip") + filename = "${path.module}/api_gateway_lambda.zip" + timeout = 15 + publish = true +} + +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 +} + +resource "aws_api_gateway_resource" "proxy" { + rest_api_id = aws_api_gateway_rest_api.api_gateway.id + parent_id = aws_api_gateway_rest_api.api_gateway.root_resource_id + path_part = "{proxy+}" +} + +resource "aws_api_gateway_method" "proxy" { + rest_api_id = aws_api_gateway_rest_api.api_gateway.id + resource_id = aws_api_gateway_resource.proxy.id + http_method = "ANY" + authorization = "COGNITO_USER_POOLS" + authorizer_id = aws_api_gateway_authorizer.cognito.id +} + +resource "aws_api_gateway_authorizer" "cognito" { + name = "app-${var.prefix}-cognito-authorizer" + rest_api_id = aws_api_gateway_rest_api.api_gateway.id + type = "COGNITO_USER_POOLS" + provider_arns = [var.cognito_user_pool_arn] +} + +resource "aws_api_gateway_integration" "proxy_integration" { + rest_api_id = aws_api_gateway_rest_api.api_gateway.id + resource_id = aws_api_gateway_resource.proxy.id + http_method = aws_api_gateway_method.proxy.http_method + integration_http_method = "POST" + type = "AWS_PROXY" + uri = "arn:aws:apigateway:${var.region}:lambda:path/2015-03-31/functions/${lookup({ + "live" = aws_lambda_alias.live.arn, + "dev" = aws_lambda_alias.dev.arn +}, var.lambda_alias, aws_lambda_alias.live.arn)}/invocations" +} + +resource "aws_api_gateway_deployment" "deployment" { + depends_on = [ + aws_api_gateway_method.proxy, + aws_api_gateway_integration.proxy_integration + ] + rest_api_id = aws_api_gateway_rest_api.api_gateway.id + + triggers = { + redeployment = timestamp() + } + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_api_gateway_stage" "stage" { + stage_name = var.api_gateway_stage_name + rest_api_id = aws_api_gateway_rest_api.api_gateway.id + deployment_id = aws_api_gateway_deployment.deployment.id + + description = "Stage for ${var.api_gateway_stage_name}" + variables = { + lambda_alias = var.lambda_alias + } + + lifecycle { + 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 = "app-${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 new file mode 100644 index 00000000..c2787882 --- /dev/null +++ b/terraform/modules/api-gateway/outputs.tf @@ -0,0 +1,27 @@ +output "api_gateway_id" { + description = "The ID of the API Gateway" + value = aws_api_gateway_rest_api.api_gateway.id +} + +output "api_gateway_url" { + description = "The invoke URL of the API Gateway" + value = aws_api_gateway_deployment.deployment.invoke_url +} + +output "api_gateway_stage_name" { + description = "The stage name of the API Gateway deployment" + value = aws_api_gateway_stage.stage.stage_name +} + +output "api_gateway_lambda_invoke_arn" { + description = "The invoke ARN for the API Gateway Lambda function alias" + value = var.lambda_alias == "live" ? aws_lambda_alias.live.arn : aws_lambda_alias.dev.arn +} + +output "lambda_alias_arn" { + description = "The ARN of the selected Lambda alias" + value = lookup({ + "live" = aws_lambda_alias.live.arn, + "dev" = aws_lambda_alias.dev.arn + }, var.lambda_alias, aws_lambda_alias.live.arn) +} \ No newline at end of file diff --git a/terraform/modules/api-gateway/vars.tf b/terraform/modules/api-gateway/vars.tf new file mode 100644 index 00000000..3f551db8 --- /dev/null +++ b/terraform/modules/api-gateway/vars.tf @@ -0,0 +1,103 @@ +variable "name" { + description = "The name of the API Gateway" + type = string + + validation { + condition = length(var.name) > 0 + error_message = "The 'name' variable must be a non-empty string." + } +} + +variable "description" { + description = "The description of the API Gateway" + type = string + default = "API Gateway for the application" + + validation { + condition = length(var.description) > 0 + error_message = "The 'description' variable must be a non-empty string." + } +} + +variable "api_gateway_stage_name" { + description = "The stage name for API Gateway (e.g. dev or live)" + type = string + default = "dev" + + validation { + condition = can(regex("^[a-zA-Z0-9_-]+$", var.api_gateway_stage_name)) + error_message = "The 'stage_name' variable must only contain alphanumeric characters, dashes, or underscores." + } +} + +variable "lambda_function_arn" { + description = "The ARN of the Lambda function to integrate with API Gateway" + type = string + + validation { + condition = can(regex("^arn:aws:lambda:.*:.*:function:.*$", var.lambda_function_arn)) + error_message = "The 'lambda_function_arn' must be a valid Lambda function ARN." + } +} + +variable "cognito_user_pool_arn" { + description = "The ARN of the Cognito User Pool for authorizing requests" + type = string + + validation { + condition = can(regex("^arn:aws:cognito-idp:.*:.*:userpool/.*$", var.cognito_user_pool_arn)) + error_message = "The 'cognito_user_pool_arn' must be a valid Cognito User Pool ARN." + } +} + +variable "region" { + description = "The AWS region for resources" + type = string + + validation { + condition = can(regex("^[a-z]{2}-[a-z]+-[0-9]{1}$", var.region)) + error_message = "The 'region' variable must be a valid AWS region string, e.g. 'eu-west-2'." + } +} + +variable "resource_path_part" { + description = "The resource path part for API Gateway (e.g. 'data' or '{proxy+}')" + type = string + default = "{proxy+}" + + validation { + condition = can(regex("^[a-zA-Z0-9/{}+_-]+$", var.resource_path_part)) + error_message = "The 'resource_path_part' must be a valid path segment containing alphanumeric characters, slashes, curly braces, dashes, or underscores." + } +} + +variable "lambda_invoke_arn" { + description = "The ARN of the Lambda function for API Gateway" + type = string + + validation { + condition = can(regex("^arn:aws:lambda:.*:.*:function:.*$", var.lambda_invoke_arn)) + error_message = "The 'lambda_invoke_arn' must be a valid Lambda function ARN." + } +} + +variable "lambda_role_arn" { + description = "IAM Role ARN for the Lambda function" + type = string + + validation { + condition = can(regex("^arn:aws:iam::\\d{12}:role/.+$", var.lambda_role_arn)) + error_message = "The 'lambda_role_arn' must be a valid IAM Role ARN." + } +} + +variable "lambda_alias" { + description = "The alias for the Lambda function (e.g. live, dev)" + type = string + default = "live" + + validation { + condition = contains(["dev", "live"], var.lambda_alias) + error_message = "Invalid alias provided. Allowed values are 'dev' or 'live'." + } +} \ No newline at end of file diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index f2471f6d..5c1ec30d 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -106,7 +106,7 @@ resource "aws_cognito_user_group" "cognito_user_groups" { } resource "aws_lambda_function" "cognito_post_auth_lambda" { - function_name = "post-auth-lambda-${var.prefix}" + function_name = "app-${var.prefix}-post-auth-lambda" runtime = "nodejs18.x" # Updated runtime role = aws_iam_role.cognito_lambda_role.arn @@ -117,7 +117,7 @@ resource "aws_lambda_function" "cognito_post_auth_lambda" { } resource "aws_lambda_function" "cognito_pre_signup_lambda" { - function_name = "pre-signup-lambda-${var.prefix}" + function_name = "app-${var.prefix}-pre-signup-lambda" runtime = "nodejs18.x" # Updated runtime role = aws_iam_role.cognito_lambda_role.arn @@ -128,7 +128,7 @@ resource "aws_lambda_function" "cognito_pre_signup_lambda" { } resource "aws_lambda_function" "cognito_user_migration_lambda" { - function_name = "user-migration-lambda-${var.prefix}" + function_name = "app-${var.prefix}-user-migration-lambda" runtime = "nodejs18.x" # Updated runtime role = aws_iam_role.cognito_lambda_role.arn @@ -139,7 +139,7 @@ resource "aws_lambda_function" "cognito_user_migration_lambda" { } resource "aws_iam_role" "cognito_lambda_role" { - name = "lambda-execution-role-${var.prefix}" + name = "app-${var.prefix}-lambda-execution-role" assume_role_policy = jsonencode({ Version = "2012-10-17", @@ -156,7 +156,7 @@ resource "aws_iam_role" "cognito_lambda_role" { } resource "aws_iam_role_policy" "cognito_lambda_role_policy" { - name = "lambda-execution-policy-${var.prefix}" + name = "app-${var.prefix}-lambda-execution-policy" role = aws_iam_role.cognito_lambda_role.id policy = jsonencode({ Version = "2012-10-17", @@ -168,12 +168,12 @@ resource "aws_iam_role_policy" "cognito_lambda_role_policy" { }, { Effect = "Allow", - Action = ["cognito-idp:PostAuthentication"], + Action = ["cognito-idp:PostAuthentication", "cognito-idp:PreSignUp"], Resource = "*" }, { Effect = "Allow", - Action = ["cognito-idp:PreSignUp"], + Action = ["lambda:InvokeFunction"], Resource = "*" } ] diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 838e0f05..43efa01b 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -38,4 +38,15 @@ output "cognito_oauth_userinfo_url" { description = "The Cognito User Pool OAuth userinfo URL" value = "https://${aws_cognito_user_pool_domain.cognito_user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/userInfo" sensitive = true -} \ No newline at end of file +} + +output "cognito_user_pool_arn" { + description = "ARN of the Cognito User Pool" + value = aws_cognito_user_pool.user_pool.arn + sensitive = true +} + +output "cognito_lambda_role_arn" { + description = "The ARN of the Cognito Lambda execution role" + value = aws_iam_role.cognito_lambda_role.arn +} diff --git a/terraform/modules/cognito/variables.tf b/terraform/modules/cognito/vars.tf similarity index 100% rename from terraform/modules/cognito/variables.tf rename to terraform/modules/cognito/vars.tf From 49d33a192ae2c20a0e6825488ef889da0de1a602 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Wed, 29 Jan 2025 16:28:21 +0000 Subject: [PATCH 07/38] CDD-2443 Auto generate secret for cognito user pool --- terraform/modules/cognito/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 5c1ec30d..27be9cda 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -44,6 +44,7 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { name = var.client_name user_pool_id = aws_cognito_user_pool.user_pool.id + generate_secret = true allowed_oauth_flows = ["code", "implicit"] allowed_oauth_flows_user_pool_client = true From 83a2ec2337819a7deb4ab83fe61ad199fd4cc46a Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Wed, 29 Jan 2025 16:43:01 +0000 Subject: [PATCH 08/38] CDD-2443 Add output for cognito user pool client secret --- terraform/modules/cognito/outputs.tf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 43efa01b..22353ca9 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -50,3 +50,9 @@ output "cognito_lambda_role_arn" { description = "The ARN of the Cognito Lambda execution role" value = aws_iam_role.cognito_lambda_role.arn } + +output "cognito_user_pool_client_secret" { + description = "The Client Secret for Cognito User Pool Client" + value = aws_cognito_user_pool_client.user_pool_client.client_secret + sensitive = true +} \ No newline at end of file From 92d3fe110bcef3da539cb9ccc68d3ca1dd936f8a Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Thu, 30 Jan 2025 10:22:11 +0000 Subject: [PATCH 09/38] CDD-2443 Restrict oauth flow to code and scope to openid. Tighten cognito lambda role policy --- terraform/modules/cognito/main.tf | 35 ++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 27be9cda..e1a8a9c4 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -1,3 +1,5 @@ +data "aws_caller_identity" "current" {} + resource "aws_cognito_user_pool" "user_pool" { name = var.user_pool_name @@ -46,9 +48,9 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { user_pool_id = aws_cognito_user_pool.user_pool.id generate_secret = true - allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_flows = ["code"] allowed_oauth_flows_user_pool_client = true - allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] + allowed_oauth_scopes = ["openid", "aws.cognito.signin.user.admin"] callback_urls = var.callback_urls logout_urls = var.logout_urls @@ -164,18 +166,35 @@ resource "aws_iam_role_policy" "cognito_lambda_role_policy" { Statement = [ { Effect = "Allow", - Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"], - Resource = "*" + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:GetLogEvents" + ], + Resource = [ + "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/app-${var.prefix}-*:log-stream:*" + ] }, + { Effect = "Allow", - Action = ["cognito-idp:PostAuthentication", "cognito-idp:PreSignUp"], - Resource = "*" + Action = [ + "cognito-idp:PostAuthentication", + "cognito-idp:PreSignUp", + "cognito-idp:AdminCreateUser", + "cognito-idp:AdminUpdateUserAttributes", + "cognito-idp:AdminInitiateAuth" + ], + Resource = aws_cognito_user_pool.user_pool.arn }, + { Effect = "Allow", - Action = ["lambda:InvokeFunction"], - Resource = "*" + Action = "lambda:InvokeFunction", + Resource = "arn:aws:lambda:${var.region}:${data.aws_caller_identity.current.account_id}:function:app-${var.prefix}-*" } ] }) From 466c207baff5a1ba456c6d9b51753a7d58f96dce Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Thu, 30 Jan 2025 10:37:16 +0000 Subject: [PATCH 10/38] CDD-2443 Disable MFA config and remove SMS config block --- terraform/modules/cognito/main.tf | 13 ++----------- terraform/modules/cognito/vars.tf | 12 ------------ 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index e1a8a9c4..8a49eb39 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -3,7 +3,7 @@ data "aws_caller_identity" "current" {} resource "aws_cognito_user_pool" "user_pool" { name = var.user_pool_name - mfa_configuration = var.enable_mfa ? "ON" : "OFF" + mfa_configuration = "OFF" lambda_config { post_authentication = aws_lambda_function.cognito_post_auth_lambda.arn @@ -11,15 +11,6 @@ resource "aws_cognito_user_pool" "user_pool" { user_migration = aws_lambda_function.cognito_user_migration_lambda.arn } - dynamic "sms_configuration" { - for_each = var.enable_sms ? [1] : [] - - content { - sns_caller_arn = var.sns_role_arn != null ? var.sns_role_arn : "" - external_id = "cognito-sms-external-id" - } - } - password_policy { minimum_length = 8 require_lowercase = true @@ -28,7 +19,7 @@ resource "aws_cognito_user_pool" "user_pool" { require_uppercase = true } - auto_verified_attributes = var.enable_sms ? ["email", "phone_number"] : ["email"] + auto_verified_attributes = [] account_recovery_setting { recovery_mechanism { diff --git a/terraform/modules/cognito/vars.tf b/terraform/modules/cognito/vars.tf index 43ef41dd..bb4ccfd2 100644 --- a/terraform/modules/cognito/vars.tf +++ b/terraform/modules/cognito/vars.tf @@ -60,18 +60,6 @@ variable "user_pool_domain" { type = string } -variable "enable_mfa" { - description = "Enable Multi-Factor Authentication (MFA) for Cognito. If true, MFA will be enforced." - type = bool - default = false -} - -variable "enable_sms" { - description = "Enable SMS functionality for Cognito (e.g. for MFA or auto-verification). Requires sns_role_arn." - type = bool - default = false -} - variable "enable_saml" { description = "Enable SAML integration" type = bool From 45a05f1f99b915ea25facc5db55cd987e7e5c526 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Thu, 30 Jan 2025 14:43:30 +0000 Subject: [PATCH 11/38] CDD-2443 Amended naming conventions and added extra lambda logging --- terraform/20-app/api-gateway.tf | 2 +- terraform/20-app/cognito.tf | 14 ++--- terraform/modules/api-gateway/main.tf | 6 +-- terraform/modules/cognito/main.tf | 51 +++++++++++------- terraform/modules/cognito/post_auth.js | 2 +- .../modules/cognito/post_auth_lambda.zip | Bin 270 -> 294 bytes terraform/modules/cognito/pre_signup.js | 2 +- .../modules/cognito/pre_signup_lambda.zip | Bin 271 -> 296 bytes terraform/modules/cognito/user_migration.js | 2 +- .../modules/cognito/user_migration_lambda.zip | Bin 265 -> 305 bytes 10 files changed, 47 insertions(+), 32 deletions(-) diff --git a/terraform/20-app/api-gateway.tf b/terraform/20-app/api-gateway.tf index 9290dfa9..d506b897 100644 --- a/terraform/20-app/api-gateway.tf +++ b/terraform/20-app/api-gateway.tf @@ -1,6 +1,6 @@ module "api_gateway" { source = "../modules/api-gateway" - name = "app-${local.prefix}-api-gateway" + name = "${local.prefix}-api-gateway" description = "API Gateway for ${local.prefix}" api_gateway_stage_name = var.api_gateway_stage_name lambda_role_arn = module.cognito.cognito_lambda_role_arn diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index 0239fe51..f6081fd8 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -1,5 +1,5 @@ resource "aws_iam_role" "cognito_sns_role" { - name = "app-${local.prefix}-cognito-sns-role" + name = "${local.prefix}-cognito-sns-role" assume_role_policy = jsonencode({ Version = "2012-10-17", @@ -16,11 +16,11 @@ resource "aws_iam_role" "cognito_sns_role" { } resource "aws_sns_topic" "cognito_topic" { - name = "app-${local.prefix}-cognito-sms-topic" + name = "${local.prefix}-cognito-sms-topic" } resource "aws_iam_policy" "cognito_sns_policy" { - name = "app-${local.prefix}-cognito-sns-policy" + name = "${local.prefix}-cognito-sns-policy" policy = jsonencode({ Version = "2012-10-17", @@ -45,9 +45,9 @@ module "cognito" { source = "../modules/cognito" sns_role_arn = aws_iam_role.cognito_sns_role.arn - user_pool_name = "app-${local.prefix}-user-pool" - client_name = "app-${local.prefix}-client" - user_pool_domain = "app-${local.prefix}-domain" + user_pool_name = "${local.prefix}-user-pool" + client_name = "${local.prefix}-client" + user_pool_domain = "${local.prefix}-domain" callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] region = local.region @@ -70,7 +70,7 @@ module "app_security_group" { source = "terraform-aws-modules/security-group/aws" version = "~> 5.0" - name = "app-${local.prefix}-security-group" + name = "${local.prefix}-security-group" description = "Security group for the application" vpc_id = module.vpc.vpc_id diff --git a/terraform/modules/api-gateway/main.tf b/terraform/modules/api-gateway/main.tf index 8293afa1..e0f91551 100644 --- a/terraform/modules/api-gateway/main.tf +++ b/terraform/modules/api-gateway/main.tf @@ -1,7 +1,7 @@ data "aws_caller_identity" "current" {} resource "aws_lambda_function" "api_gateway_lambda" { - function_name = "app-${var.prefix}-api-gateway-lambda" + function_name = "${var.prefix}-api-gateway-lambda" runtime = "nodejs18.x" role = var.lambda_role_arn handler = "index.handler" @@ -46,7 +46,7 @@ resource "aws_api_gateway_method" "proxy" { } resource "aws_api_gateway_authorizer" "cognito" { - name = "app-${var.prefix}-cognito-authorizer" + name = "${var.prefix}-cognito-authorizer" rest_api_id = aws_api_gateway_rest_api.api_gateway.id type = "COGNITO_USER_POOLS" provider_arns = [var.cognito_user_pool_arn] @@ -105,7 +105,7 @@ resource "aws_api_gateway_account" "account" { } resource "aws_iam_role" "api_gateway_cloudwatch_role" { - name = "app-${var.prefix}-api-gateway-cloudwatch-role" + name = "${var.prefix}-api-gateway-cloudwatch-role" assume_role_policy = jsonencode({ Version = "2012-10-17", diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 8a49eb39..b7749524 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -100,40 +100,40 @@ resource "aws_cognito_user_group" "cognito_user_groups" { } resource "aws_lambda_function" "cognito_post_auth_lambda" { - function_name = "app-${var.prefix}-post-auth-lambda" - runtime = "nodejs18.x" # Updated runtime + function_name = "${var.prefix}-post-auth-lambda" + runtime = "nodejs18.x" role = aws_iam_role.cognito_lambda_role.arn - handler = "index.handler" + handler = "post_auth.handler" source_code_hash = filebase64sha256("${path.module}/post_auth_lambda.zip") filename = "${path.module}/post_auth_lambda.zip" timeout = 15 } resource "aws_lambda_function" "cognito_pre_signup_lambda" { - function_name = "app-${var.prefix}-pre-signup-lambda" - runtime = "nodejs18.x" # Updated runtime + function_name = "${var.prefix}-pre-signup-lambda" + runtime = "nodejs18.x" role = aws_iam_role.cognito_lambda_role.arn - handler = "index.handler" + handler = "pre_signup.handler" source_code_hash = filebase64sha256("${path.module}/pre_signup_lambda.zip") filename = "${path.module}/pre_signup_lambda.zip" timeout = 15 } resource "aws_lambda_function" "cognito_user_migration_lambda" { - function_name = "app-${var.prefix}-user-migration-lambda" - runtime = "nodejs18.x" # Updated runtime + function_name = "${var.prefix}-user-migration-lambda" + runtime = "nodejs18.x" role = aws_iam_role.cognito_lambda_role.arn - handler = "index.handler" + handler = "user_migration.handler" source_code_hash = filebase64sha256("${path.module}/user_migration_lambda.zip") filename = "${path.module}/user_migration_lambda.zip" timeout = 15 } resource "aws_iam_role" "cognito_lambda_role" { - name = "app-${var.prefix}-lambda-execution-role" + name = "${var.prefix}-lambda-execution-role" assume_role_policy = jsonencode({ Version = "2012-10-17", @@ -150,8 +150,9 @@ resource "aws_iam_role" "cognito_lambda_role" { } resource "aws_iam_role_policy" "cognito_lambda_role_policy" { - name = "app-${var.prefix}-lambda-execution-policy" + name = "${var.prefix}-lambda-execution-policy" role = aws_iam_role.cognito_lambda_role.id + policy = jsonencode({ Version = "2012-10-17", Statement = [ @@ -165,11 +166,8 @@ resource "aws_iam_role_policy" "cognito_lambda_role_policy" { "logs:DescribeLogStreams", "logs:GetLogEvents" ], - Resource = [ - "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/app-${var.prefix}-*:log-stream:*" - ] + Resource = "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.prefix}-*:log-stream:*" }, - { Effect = "Allow", Action = [ @@ -177,20 +175,37 @@ resource "aws_iam_role_policy" "cognito_lambda_role_policy" { "cognito-idp:PreSignUp", "cognito-idp:AdminCreateUser", "cognito-idp:AdminUpdateUserAttributes", - "cognito-idp:AdminInitiateAuth" + "cognito-idp:AdminInitiateAuth", + "cognito-idp:ListUsers", + "cognito-idp:DescribeUserPool", + "cognito-idp:GetUser", + "cognito-idp:UpdateUserPoolClient", + "cognito-idp:AdminGetUser" ], Resource = aws_cognito_user_pool.user_pool.arn }, - { Effect = "Allow", Action = "lambda:InvokeFunction", - Resource = "arn:aws:lambda:${var.region}:${data.aws_caller_identity.current.account_id}:function:app-${var.prefix}-*" + Resource = "arn:aws:lambda:${var.region}:${data.aws_caller_identity.current.account_id}:function:${var.prefix}-*" } ] }) } +resource "aws_iam_role_policy_attachment" "cognito_lambda_basic_exec_attach" { + role = aws_iam_role.cognito_lambda_role.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + +resource "aws_lambda_permission" "allow_cognito" { + statement_id = "AllowCognitoInvoke" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.cognito_pre_signup_lambda.arn + principal = "cognito-idp.amazonaws.com" + source_arn = aws_cognito_user_pool.user_pool.arn +} + variable "prefix" { description = "Prefix for naming resources" type = string diff --git a/terraform/modules/cognito/post_auth.js b/terraform/modules/cognito/post_auth.js index 0f56c76b..01de75cd 100644 --- a/terraform/modules/cognito/post_auth.js +++ b/terraform/modules/cognito/post_auth.js @@ -1,4 +1,4 @@ exports.handler = async (event) => { - console.log("Post-auth Lambda invoked"); + console.log("Post-auth Lambda invoked with event:", JSON.stringify(event)); return event; }; \ No newline at end of file diff --git a/terraform/modules/cognito/post_auth_lambda.zip b/terraform/modules/cognito/post_auth_lambda.zip index 678bbe5206d22df5638e9bbff4a6651713310627..542e3b37e2f5a3d51c3dd3556510732a4fcc0639 100644 GIT binary patch literal 294 zcmWIWW@Zs#U|`^2xK&^mmH4_qwF1cN1Y#Zr8HR%V;*$8p(vl3ltm4oRP6p=c_SxyR zKwMhE&A`a=m63q~tXsFok?W8HkL!0^*B7f;=Q3MdVeVM*fHO&bTXV9~%q>wzc1N$u z|5^F};%mjMn_o{TPIO|Pp`N#J(Zm~B8QVVSB`gy?H|d1x%T=FLZeFv9;IG~j&*bzZ zFi+%x3tv$0{{k!U<&{M literal 270 zcmWIWW@Zs#U|`^2NXWB}QkclTGy%v<17aQq8HR%V;*$8p(vl3ltm4oRP6lS@{^{v1 zKwMhE&A`a=m63q~tlN97#tD5b&1Y=mljCa@t4_)uG+80AMYz%y4JLgXc@6v`pkA&_XxipD~b^eh%OQyKAp4qeM&zmbEs=nD99xb{u z>Cz$_)(w)^Vzypm2=HcPl4Hi@P6?oE85n?WVOY`#VxhX472;|%7YBH=vVqhx0$~u4 JUIyYY003tVR3-ob diff --git a/terraform/modules/cognito/pre_signup.js b/terraform/modules/cognito/pre_signup.js index a23ac2cc..29694bd4 100644 --- a/terraform/modules/cognito/pre_signup.js +++ b/terraform/modules/cognito/pre_signup.js @@ -1,4 +1,4 @@ exports.handler = async (event) => { - console.log("Pre-signup Lambda invoked"); + console.log("Pre-signup Lambda invoked with event:", JSON.stringify(event)); return event; }; \ No newline at end of file diff --git a/terraform/modules/cognito/pre_signup_lambda.zip b/terraform/modules/cognito/pre_signup_lambda.zip index 24238153e6227307a5bb3eed3ced20eac7e7c8be..bd20aa3eb210a6937bf66adb304846571a3232a3 100644 GIT binary patch literal 296 zcmWIWW@Zs#U|`^2I9gyA)%%cnO9hbE1;o4zG7JSpsqw{`>3O9EdRfJxA)E}%f$g)? zLx8xnf}4Sni~ZBn zF9C6B1vdjD%U4DQ2C#P7Gmd-?1_Evm_Xhvjm~@bJmQ`b`_7pz>Q{~G-O7Hyke4Xz8 zTy0j8t>w2y5iz|un*|G+Ev9bZea92uTrkC;LXYgQp^a1!9aQ$ Hh{FH?z7$VJ diff --git a/terraform/modules/cognito/user_migration.js b/terraform/modules/cognito/user_migration.js index 40bc7284..77e45802 100644 --- a/terraform/modules/cognito/user_migration.js +++ b/terraform/modules/cognito/user_migration.js @@ -1,4 +1,4 @@ exports.handler = async (event) => { - console.log("User migration Lambda invoked"); + console.log("User migration Lambda invoked with event:", JSON.stringify(event)); return event; }; \ No newline at end of file diff --git a/terraform/modules/cognito/user_migration_lambda.zip b/terraform/modules/cognito/user_migration_lambda.zip index 205b552f3a3f3c78fbdbdc8c7eb170bfd6a65f6d..b28ab2b48d47eb8166b983c4bd0fef5ef1688937 100644 GIT binary patch literal 305 zcmWIWW@Zs#U|`^2cwS%^m7mw-SqbFz0kI&13`1#gYEgV{W_nR#NoIbYURH5v2qy#c z#P-?glYqFif}4Sn3qnT_kr=)i-SKJrmppVd}&gi zYv;%JLM7*no7V?kDY{(E$0-{1q4F7@)|?4z+sfGAGl^L})Zv`1vQbOFGLXINRd36~ z2kqG(9BfX?GTWT2iuj$ov+?iGlAKMNg-dS#`F|~MuGTH*pU-zadb}^dn~_P58J904 nfPP_M06LOkNh64b#ZRmdKcV?2z?+o~q=69#!-4b>5QhN(_zz~z literal 265 zcmWIWW@Zs#U|`^2Sf6Vh<@l%iS~8HA4Hl7M$jnPgt#IsgB#Y=n${`h6k)$Y#ucEA3Jo%HJzQ+^`~{m%JjDV`CFrY zO;t%T<5^I2s;Q5E+AD*eAErAZL%P!5Z9cYc?&-DfG^MUCY3lqIuApLB^7w+)f01Kf zlbh0?%-+ABA;6oFNsbwpGbMnIWnch0hha%0h=p)8E5y-g4i4~UWdo^W1VTR`y%fY@ F001IjQz`%e From 4d5528037ee8b850daf94fd63cf5047c2c4e834c Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Thu, 30 Jan 2025 15:05:01 +0000 Subject: [PATCH 12/38] CDD-2443 Amended api gateway handler name --- terraform/modules/api-gateway/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/modules/api-gateway/main.tf b/terraform/modules/api-gateway/main.tf index e0f91551..b9132d4d 100644 --- a/terraform/modules/api-gateway/main.tf +++ b/terraform/modules/api-gateway/main.tf @@ -4,7 +4,7 @@ resource "aws_lambda_function" "api_gateway_lambda" { function_name = "${var.prefix}-api-gateway-lambda" runtime = "nodejs18.x" role = var.lambda_role_arn - handler = "index.handler" + handler = "api_gateway_lambda.handler" source_code_hash = filebase64sha256("${path.module}/api_gateway_lambda.zip") filename = "${path.module}/api_gateway_lambda.zip" From 35339d2ef072618cb74ad12d11484e9ab1aa84c1 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Thu, 30 Jan 2025 16:31:29 +0000 Subject: [PATCH 13/38] CDD-2443 Auto confirm user and email for debugging --- terraform/modules/cognito/pre_signup.js | 7 ++++++- terraform/modules/cognito/pre_signup_lambda.zip | Bin 296 -> 366 bytes 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/terraform/modules/cognito/pre_signup.js b/terraform/modules/cognito/pre_signup.js index 29694bd4..faf9bce8 100644 --- a/terraform/modules/cognito/pre_signup.js +++ b/terraform/modules/cognito/pre_signup.js @@ -1,4 +1,9 @@ exports.handler = async (event) => { - console.log("Pre-signup Lambda invoked with event:", JSON.stringify(event)); + console.log("Pre-signup Lambda invoked with event:", JSON.stringify(event, null, 2)); + + // Auto-confirm user and verify email + event.response.autoConfirmUser = true; + event.response.autoVerifyEmail = true; + return event; }; \ No newline at end of file diff --git a/terraform/modules/cognito/pre_signup_lambda.zip b/terraform/modules/cognito/pre_signup_lambda.zip index bd20aa3eb210a6937bf66adb304846571a3232a3..91c42160f9a4412a78987fd11b4c93565d89ccac 100644 GIT binary patch delta 311 zcmZ3%^p2@Mz?+#xgn@y9gW+7WT~ywZAjW+_o+u*&122ONLqSn$d~s%aUTJ||R&i(u zCj+zc%Gv3vKwMhE&A`a=6{rrZy|nLO)?oty*7yIq-2DtKxV}U@cGBECWdfU1Rrupx zU9I(Jyo!>%{_S1Gv$yoT@#g-##giX|uHU(}UL|9}-!tiJGL`sLXQ|hSdz6>GnX8%_ zyFE^}#q3^*jQg7}A8uwz%)2ALb;qm=%DeklbLAiZzW0+OPx&(={j*#$YuA1Vm{vOR z@@?ID$py2&JW5J&_>$>ytGQDpbAhAu?2|G9PIW%n9xqe&>RdYc{G+4N)&C3SEx-SY t{_Sk6EwV`Q!=fuk_x@uH@MdI^W5yN`6K|?9DX*N&$f(H13iK@l0{{i2d_DjG literal 296 zcmWIWW@Zs#U|`^2I9gyA)%%cnO9hbE1;o4zG7JSpsqw{`>3O9EdRfJxA)E}%f$g)? zLx8xnf}4Sn Date: Thu, 30 Jan 2025 16:45:43 +0000 Subject: [PATCH 14/38] CDD-2443 Amend pre signup lambda logging --- terraform/modules/cognito/pre_signup.js | 10 ++++++++-- terraform/modules/cognito/pre_signup_lambda.zip | Bin 366 -> 461 bytes 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/terraform/modules/cognito/pre_signup.js b/terraform/modules/cognito/pre_signup.js index faf9bce8..f4cd8ab7 100644 --- a/terraform/modules/cognito/pre_signup.js +++ b/terraform/modules/cognito/pre_signup.js @@ -1,9 +1,15 @@ exports.handler = async (event) => { console.log("Pre-signup Lambda invoked with event:", JSON.stringify(event, null, 2)); - // Auto-confirm user and verify email + // Check if the email attribute exists before auto-verifying + if (event.request.userAttributes && event.request.userAttributes.email) { + event.response.autoVerifyEmail = true; + } else { + console.log("No email provided. Skipping auto-verification."); + } + + // auto-confirm the user event.response.autoConfirmUser = true; - event.response.autoVerifyEmail = true; return event; }; \ No newline at end of file diff --git a/terraform/modules/cognito/pre_signup_lambda.zip b/terraform/modules/cognito/pre_signup_lambda.zip index 91c42160f9a4412a78987fd11b4c93565d89ccac..1fd67eb02afc759777d181932da3826252c6d62e 100644 GIT binary patch literal 461 zcmWIWW@Zs#U|`^2nAK_*m8o;uSeB82;TsV1GRQC#6s5)&XQtr4`%^j4WS)>cHA-Cpu;`849$%|EiC)(IqqkQ08QWhvv3yD{;~~aw6?-PB{_uPDv!iwv&+Uu# z7Y*aO7X50M#NSn%Q=?8qnw~m;=KfI?UzKY|c5j&z{OQg7j?<3c-(7a+6P!FPkm>fp zpp@f}*aN&7ndF#pg|Y-N^cfg{0m-nW5yV0Zb5=;0qlI^XH!B-RF(VKL1L+iyeg*)) CTC9oSB|iTA-Iz92&yOz^uG- zcDgDMmsW5yFtU6Fssn2;?K_xt*g$~w{l6}EKSK+yFAdsp%7Ej@3%xj%35w@y`{?%Oh$G`9W@Sa!QXIZydfaO6RLNZ6C_Ve6On_6JPqxR)l)XBaPCozWsC4!JLV3&YzoLIT8*7U! z`mpHA(Y^l|1H2iT Date: Mon, 3 Feb 2025 14:37:54 +0000 Subject: [PATCH 15/38] CDD-2443 Remove default tags from main.tf --- terraform/20-app/main.tf | 7 ------- 1 file changed, 7 deletions(-) diff --git a/terraform/20-app/main.tf b/terraform/20-app/main.tf index 97c581a1..b378eda7 100644 --- a/terraform/20-app/main.tf +++ b/terraform/20-app/main.tf @@ -3,13 +3,6 @@ provider "aws" { assume_role { role_arn = "arn:aws:iam::${var.assume_account_id}:role/${var.assume_role_name}" } - - default_tags { - tags = { - project_name = local.project - env = terraform.workspace - } - } } provider "aws" { From 9828355f820a524b8e936bfe3e8701ccc38bf3a9 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Mon, 3 Feb 2025 14:39:22 +0000 Subject: [PATCH 16/38] CDD-2443 Remove default tags from aws main.tf --- terraform/20-app/main.tf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/terraform/20-app/main.tf b/terraform/20-app/main.tf index b378eda7..78ece68d 100644 --- a/terraform/20-app/main.tf +++ b/terraform/20-app/main.tf @@ -3,6 +3,13 @@ provider "aws" { assume_role { role_arn = "arn:aws:iam::${var.assume_account_id}:role/${var.assume_role_name}" } + + default_tags { + tags = { + project_name = local.project + env = terraform.workspace + } + } } provider "aws" { @@ -11,13 +18,6 @@ provider "aws" { assume_role { role_arn = "arn:aws:iam::${var.assume_account_id}:role/${var.assume_role_name}" } - - default_tags { - tags = { - project_name = local.project - env = terraform.workspace - } - } } terraform { From 2c416eb70120aa50b4789a5607fffeed486af680 Mon Sep 17 00:00:00 2001 From: 8lane Date: Mon, 3 Feb 2025 13:22:14 +0000 Subject: [PATCH 17/38] chore: setup env vars --- terraform/20-app/api-keys.tf | 10 +++++++ terraform/20-app/ecs.service.front-end.tf | 22 +++++++++++++- terraform/20-app/secret-manager.tf | 36 +++++++++++++++++++++++ terraform/modules/cognito/outputs.tf | 6 ++++ 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/terraform/20-app/api-keys.tf b/terraform/20-app/api-keys.tf index 0bd84981..2be4ff37 100644 --- a/terraform/20-app/api-keys.tf +++ b/terraform/20-app/api-keys.tf @@ -49,8 +49,18 @@ resource "random_password" "feature_flags_admin_user_password" { special = true } +resource "random_password" "auth_secret" { + length = 32 + min_numeric = 1 + min_lower = 1 + min_upper = 1 + min_special = 1 + special = true +} + locals { feature_flags_x_auth = random_password.feature_flags_x_auth.result feature_flags_client_api_key = "*:production.${random_password.feature_flags_client_api_key.result}" private_api_key = "${random_password.private_api_key_prefix.result}.${random_password.private_api_key_suffix.result}" + auth_secret = random_password.auth_secret.result } diff --git a/terraform/20-app/ecs.service.front-end.tf b/terraform/20-app/ecs.service.front-end.tf index 0176038b..a6270825 100644 --- a/terraform/20-app/ecs.service.front-end.tf +++ b/terraform/20-app/ecs.service.front-end.tf @@ -73,7 +73,11 @@ module "ecs_service_front_end" { { name = "AUTH_ENABLED", value = local.is_auth - } + }, + { + name = "NEXTAUTH_URL" + value = local.urls.front_end + }, ] secrets = [ { @@ -107,6 +111,22 @@ module "ecs_service_front_end" { { name = "ESRI_CLIENT_SECRET" valueFrom = "${aws_secretsmanager_secret.esri_maps_service_credentials.arn}:client_secret::" + }, + { + name = "AUTH_SECRET" + valueFrom = "${aws_secretsmanager_secret.auth_secret.arn}:auth_secret::" + }, + { + name = "AUTH_CLIENT_URL" + valueFrom = "${aws_secretsmanager_secret.cognito_service_credentials.arn}:client_url::" + }, + { + name = "AUTH_CLIENT_ID" + valueFrom = "${aws_secretsmanager_secret.cognito_service_credentials.arn}:client_id::" + }, + { + name = "AUTH_CLIENT_SECRET" + valueFrom = "${aws_secretsmanager_secret.cognito_service_credentials.arn}:client_secret::" } ] } diff --git a/terraform/20-app/secret-manager.tf b/terraform/20-app/secret-manager.tf index 40d93b8c..67e7ac74 100644 --- a/terraform/20-app/secret-manager.tf +++ b/terraform/20-app/secret-manager.tf @@ -140,6 +140,42 @@ resource "aws_secretsmanager_secret_version" "google_analytics_credentials" { }) } +################################################################################ +# Cognito +################################################################################ + +resource "aws_secretsmanager_secret" "cognito_service_credentials" { + name = "${local.prefix}-cognito-service-credentials" + description = "These are the credentials required for AWS Congito service." + kms_key_id = module.kms_secrets_app_engineer.key_id +} + +resource "aws_secretsmanager_secret_version" "cognito_service_credentials" { + secret_id = aws_secretsmanager_secret.cognito_service_credentials.id + secret_string = jsonencode({ + client_url = "" + client_id = "" + client_secret = "" + }) +} + +################################################################################ +# NextAuth +################################################################################ + +resource "aws_secretsmanager_secret" "auth_secret" { + name = "${local.prefix}-auth-secret" + description = "Used to encrypt the NextAuth.js JWT" + kms_key_id = module.kms_secrets_app_operator.key_id +} + +resource "aws_secretsmanager_secret_version" "auth_secret" { + secret_id = aws_secretsmanager_secret.auth_secret.id + secret_string = jsonencode({ + auth_secret = "" + }) +} + ################################################################################ # ESRI maps credentials ################################################################################ diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 22353ca9..98920d45 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -55,4 +55,10 @@ output "cognito_user_pool_client_secret" { description = "The Client Secret for Cognito User Pool Client" value = aws_cognito_user_pool_client.user_pool_client.client_secret sensitive = true +} + +output "cognito_user_pool_issuer_endpoint" { + description = "The Issuer API Endpoint for Cognito User Pool" + value = "https://cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.user_pool.id}" + sensitive = true } \ No newline at end of file From 4a13c4cdb78492334d76a92774a609e145b2e021 Mon Sep 17 00:00:00 2001 From: 8lane Date: Mon, 3 Feb 2025 13:22:36 +0000 Subject: [PATCH 18/38] chore: enable auth --- terraform/20-app/locals.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/20-app/locals.tf b/terraform/20-app/locals.tf index 92222093..7039a78c 100644 --- a/terraform/20-app/locals.tf +++ b/terraform/20-app/locals.tf @@ -11,7 +11,7 @@ locals { use_prod_sizing = contains(["perf", "pen", "prod"], local.environment) add_password_protection = local.environment == "staging" - is_auth = local.environment == "auth" + is_auth = true wke = { account = ["dev", "test", "uat", "prod"] From 56349d358eb415a0c5a6143ff49eb47b4082cad9 Mon Sep 17 00:00:00 2001 From: 8lane Date: Mon, 3 Feb 2025 13:57:12 +0000 Subject: [PATCH 19/38] chore: update callback and logout urls --- .github/workflows/deploy-personal-dev-environment.yml | 7 ++++++- terraform/20-app/cognito.tf | 4 ++-- terraform/20-app/locals.tf | 2 +- terraform/20-app/secret-manager.tf | 8 ++++---- terraform/modules/cognito/outputs.tf | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy-personal-dev-environment.yml b/.github/workflows/deploy-personal-dev-environment.yml index 001a9781..d431de09 100644 --- a/.github/workflows/deploy-personal-dev-environment.yml +++ b/.github/workflows/deploy-personal-dev-environment.yml @@ -201,7 +201,12 @@ jobs: restart_services: name: Restart services runs-on: ubuntu-latest - needs: ["push_frontend_docker_image", "push_backend_docker_image", "push_ingestion_docker_image"] + needs: + [ + "push_frontend_docker_image", + "push_backend_docker_image", + "push_ingestion_docker_image", + ] steps: - uses: actions/checkout@v4 diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index f6081fd8..e6be0159 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -48,8 +48,8 @@ module "cognito" { user_pool_name = "${local.prefix}-user-pool" client_name = "${local.prefix}-client" user_pool_domain = "${local.prefix}-domain" - callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/callback"] - logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/logout"] + callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/api/auth/callback/cognito"] + logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk"] region = local.region # Placeholder for SAML metadata URL, used only when SAML is enabled diff --git a/terraform/20-app/locals.tf b/terraform/20-app/locals.tf index 7039a78c..92222093 100644 --- a/terraform/20-app/locals.tf +++ b/terraform/20-app/locals.tf @@ -11,7 +11,7 @@ locals { use_prod_sizing = contains(["perf", "pen", "prod"], local.environment) add_password_protection = local.environment == "staging" - is_auth = true + is_auth = local.environment == "auth" wke = { account = ["dev", "test", "uat", "prod"] diff --git a/terraform/20-app/secret-manager.tf b/terraform/20-app/secret-manager.tf index 67e7ac74..1b3549fd 100644 --- a/terraform/20-app/secret-manager.tf +++ b/terraform/20-app/secret-manager.tf @@ -153,9 +153,9 @@ resource "aws_secretsmanager_secret" "cognito_service_credentials" { resource "aws_secretsmanager_secret_version" "cognito_service_credentials" { secret_id = aws_secretsmanager_secret.cognito_service_credentials.id secret_string = jsonencode({ - client_url = "" - client_id = "" - client_secret = "" + client_url = module.cognito.cognito_user_pool_issuer_endpoint + client_id = module.cognito.cognito_user_pool_client_id + client_secret = module.cognito.cognito_user_pool_client_secret }) } @@ -172,7 +172,7 @@ resource "aws_secretsmanager_secret" "auth_secret" { resource "aws_secretsmanager_secret_version" "auth_secret" { secret_id = aws_secretsmanager_secret.auth_secret.id secret_string = jsonencode({ - auth_secret = "" + auth_secret = local.auth_secret }) } diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 98920d45..65f22a57 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -61,4 +61,4 @@ output "cognito_user_pool_issuer_endpoint" { description = "The Issuer API Endpoint for Cognito User Pool" value = "https://cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.user_pool.id}" sensitive = true -} \ No newline at end of file +} From 7a3359046eb40825c5cb440f91ff0e5bf89baf2b Mon Sep 17 00:00:00 2001 From: 8lane Date: Mon, 3 Feb 2025 16:42:23 +0000 Subject: [PATCH 20/38] chore: debug --- terraform/20-app/ecs.service.front-end.tf | 6 +++++- terraform/20-app/locals.tf | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/terraform/20-app/ecs.service.front-end.tf b/terraform/20-app/ecs.service.front-end.tf index a6270825..73deabb1 100644 --- a/terraform/20-app/ecs.service.front-end.tf +++ b/terraform/20-app/ecs.service.front-end.tf @@ -74,6 +74,10 @@ module "ecs_service_front_end" { name = "AUTH_ENABLED", value = local.is_auth }, + { + name = "AUTH_DEBUG", + value = local.debug + }, { name = "NEXTAUTH_URL" value = local.urls.front_end @@ -116,7 +120,7 @@ module "ecs_service_front_end" { name = "AUTH_SECRET" valueFrom = "${aws_secretsmanager_secret.auth_secret.arn}:auth_secret::" }, - { + { name = "AUTH_CLIENT_URL" valueFrom = "${aws_secretsmanager_secret.cognito_service_credentials.arn}:client_url::" }, diff --git a/terraform/20-app/locals.tf b/terraform/20-app/locals.tf index 92222093..0bd5c47c 100644 --- a/terraform/20-app/locals.tf +++ b/terraform/20-app/locals.tf @@ -12,6 +12,7 @@ locals { use_prod_sizing = contains(["perf", "pen", "prod"], local.environment) add_password_protection = local.environment == "staging" is_auth = local.environment == "auth" + debug = false wke = { account = ["dev", "test", "uat", "prod"] From 3e7ce748164de73c1bb3e382889209132a196327 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 4 Feb 2025 10:41:43 +0000 Subject: [PATCH 21/38] CDD-2443 Add additional logging for post auth lambda --- terraform/modules/cognito/post_auth.js | 19 +++++++++++++++++- .../modules/cognito/post_auth_lambda.zip | Bin 294 -> 504 bytes 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/terraform/modules/cognito/post_auth.js b/terraform/modules/cognito/post_auth.js index 01de75cd..ff7dffc8 100644 --- a/terraform/modules/cognito/post_auth.js +++ b/terraform/modules/cognito/post_auth.js @@ -1,4 +1,21 @@ exports.handler = async (event) => { - console.log("Post-auth Lambda invoked with event:", JSON.stringify(event)); + console.log("Post-auth Lambda invoked with event:", JSON.stringify(event, null, 2)); + console.log("Trigger source:", event.triggerSource); + console.log("User Pool ID:", event.userPoolId); + console.log("User Name:", event.userName); + + if (event.request.userAttributes) { + console.log("User attributes:", JSON.stringify(event.request.userAttributes, null, 2)); + } else { + console.log("No user attributes provided in the event."); + } + + console.log("Environment variables:", process.env); + + if (event.triggerSource !== 'PostAuthentication_Authentication') { + console.warn("Unexpected trigger source:", event.triggerSource); + } + + console.log("Response being returned:", JSON.stringify(event.response, null, 2)); return event; }; \ No newline at end of file diff --git a/terraform/modules/cognito/post_auth_lambda.zip b/terraform/modules/cognito/post_auth_lambda.zip index 542e3b37e2f5a3d51c3dd3556510732a4fcc0639..9a4f36ef65e68dafc8aca4b0b044c3406fd4761e 100644 GIT binary patch delta 451 zcmZ3+^nG+NxEUB(z5ndlCNaCOQV4Bw7Ss}LH7=Tz zoAq#AvwWuZmHKpH@qj5TocC?!&5S*-C+C$rr@nW4Q&B6Mkia(&$(W?pCrTc94~to9 zjC{kid#38?9oNpiJM}{zcYo6KXG|)gzhsMVcpsB`dA5R!|Ml|JoVgQ2PMkH2@N3)? z6uhHvQRMX>M^7wzV7BI)+TmM^1&``Ic+K`scwbc5+AU!lcKn`N>6TqEkw0r%QhTmr zufg7jr_Wl}ciwo=?k+7+eEjc{dkcHdz5G($Eq^aSih0}I34RTy9tCV%%65Mp`_hY3 z&r~W+I*|ME&)$#Q@2;4A%r^8=#w|mBt;8iBp)Y2yHQHk4wrbbLEo{u z{-b03aLKam-%2k{zZEC(=mrPBYFeLk`TvO4egAD1>;CMUprp>H%Qn}%<){2)jz50i l93@wscUyi_JiwcgNsbv?q)fb_3W|YAj0$WMfI-i|001Si!v_EW literal 294 zcmWIWW@Zs#U|`^2xK&^mmH4_qwF1cN1Y#Zr8HR%V;*$8p(vl3ltm4oRP6p=c_SxyR zKwMhE&A`a=m63q~tXsFok?W8HkL!0^*B7f;=Q3MdVeVM*fHO&bTXV9~%q>wzc1N$u z|5^F};%mjMn_o{TPIO|Pp`N#J(Zm~B8QVVSB`gy?H|d1x%T=FLZeFv9;IG~j&*bzZ zFi+%x3tv$0{{k!U<&{M From 7bd1bb79095baa2520e9af1b7e804c817621aaa4 Mon Sep 17 00:00:00 2001 From: 8lane Date: Tue, 4 Feb 2025 12:10:13 +0000 Subject: [PATCH 22/38] fix: whitelist next-auth cookies in cloudfront --- terraform/20-app/cloud-front.front-end.tf | 44 +++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/terraform/20-app/cloud-front.front-end.tf b/terraform/20-app/cloud-front.front-end.tf index 77f32edb..9213a774 100644 --- a/terraform/20-app/cloud-front.front-end.tf +++ b/terraform/20-app/cloud-front.front-end.tf @@ -66,7 +66,7 @@ module "cloudfront_front_end" { } : {} } - ordered_cache_behavior = [ + ordered_cache_behavior = flatten(concat([ # Behaviour to bypass cloudfront for health check { path_pattern = "api/health" @@ -81,6 +81,21 @@ module "cloudfront_front_end" { viewer_protocol_policy = "redirect-to-https" query_string = false }, + # Behaviour to enable cookie forwarding for auth endpoints + local.is_auth ? [ + { + path_pattern = "/api/auth/*" + allowed_methods = ["HEAD", "DELETE", "POST", "GET", "OPTIONS", "PUT", "PATCH"] + cache_policy_id = local.managed_caching_disabled_policy_id + cached_methods = ["GET", "HEAD"] + compress = true + origin_request_policy_id = aws_cloudfront_origin_request_policy.front_end_auth.id + response_headers_policy_id = aws_cloudfront_response_headers_policy.front_end.id + target_origin_id = "alb" + use_forwarded_values = false + viewer_protocol_policy = "redirect-to-https" + } + ] : [], # Behaviour to bypass CDN for the dynamic alert pages { path_pattern = "/" @@ -142,7 +157,7 @@ module "cloudfront_front_end" { use_forwarded_values = false viewer_protocol_policy = "redirect-to-https" }, - ] + ])) custom_error_response = [ { @@ -180,6 +195,31 @@ resource "aws_cloudfront_origin_request_policy" "front_end" { } } +resource "aws_cloudfront_origin_request_policy" "front_end_auth" { + name = "${local.prefix}-front-end-auth" + + cookies_config { + cookie_behavior = "whitelist" + cookies { + items = [ + "next-auth.session-token", + "__Secure-next-auth.session-token", + "next-auth.csrf-token", + "__Host-next-auth.csrf-token", + "next-auth.callback-url", + "next-auth.state" + ] + } + } + + headers_config { + header_behavior = "allViewer" + } + query_strings_config { + query_string_behavior = "all" + } +} + ################################################################################ # Cache policies ################################################################################ From ea06d4130bb8eb7c9d87bb5b7adab59d6293fc25 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 4 Feb 2025 11:51:07 +0000 Subject: [PATCH 23/38] CDD-2443 Add pre auth lambda --- terraform/modules/cognito/main.tf | 12 ++++++++++++ terraform/modules/cognito/pre_auth.js | 4 ++++ terraform/modules/cognito/pre_auth_lambda.zip | Bin 0 -> 291 bytes 3 files changed, 16 insertions(+) create mode 100644 terraform/modules/cognito/pre_auth.js create mode 100644 terraform/modules/cognito/pre_auth_lambda.zip diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index b7749524..aa06ab60 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -6,6 +6,7 @@ resource "aws_cognito_user_pool" "user_pool" { mfa_configuration = "OFF" lambda_config { + pre_authentication = aws_lambda_function.cognito_pre_auth_lambda.arn post_authentication = aws_lambda_function.cognito_post_auth_lambda.arn pre_sign_up = aws_lambda_function.cognito_pre_signup_lambda.arn user_migration = aws_lambda_function.cognito_user_migration_lambda.arn @@ -99,6 +100,17 @@ resource "aws_cognito_user_group" "cognito_user_groups" { description = "Group for ${each.value} role" } +resource "aws_lambda_function" "cognito_pre_auth_lambda" { + function_name = "${var.prefix}-pre-auth-lambda" + runtime = "nodejs18.x" + role = aws_iam_role.cognito_lambda_role.arn + + handler = "pre_auth.handler" + source_code_hash = filebase64sha256("${path.module}/pre_auth_lambda.zip") + filename = "${path.module}/pre_auth_lambda.zip" + timeout = 15 +} + resource "aws_lambda_function" "cognito_post_auth_lambda" { function_name = "${var.prefix}-post-auth-lambda" runtime = "nodejs18.x" diff --git a/terraform/modules/cognito/pre_auth.js b/terraform/modules/cognito/pre_auth.js new file mode 100644 index 00000000..c5656a71 --- /dev/null +++ b/terraform/modules/cognito/pre_auth.js @@ -0,0 +1,4 @@ +exports.handler = async (event) => { + console.log("Pre-auth Lambda invoked with event:", JSON.stringify(event)); + return event; +}; \ No newline at end of file diff --git a/terraform/modules/cognito/pre_auth_lambda.zip b/terraform/modules/cognito/pre_auth_lambda.zip new file mode 100644 index 0000000000000000000000000000000000000000..4f3b382b693b94c13516c9b0d34afae3114885b8 GIT binary patch literal 291 zcmWIWW@Zs#U|`^2(1~-2+SRFPT@K`R05La%3`0RtYJ6g8NrqllacBr91M}g33)7DR zacKoN10%~>uuSyaq!X$ySAANt<=DZh8;}1A2`Kd! zEoL}xk$<{4cwIudom`Ar@13Kszvy49JE?hd!Jp#Vk00X$ycwC~m~pvY0_X<@2A~re fmNbG`D1Kpu_yx@$0p6@^Af=2z7zm{IfH({Q Date: Tue, 4 Feb 2025 11:57:26 +0000 Subject: [PATCH 24/38] CDD-2443 Add description for lambdas --- terraform/modules/cognito/main.tf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index aa06ab60..16e72ccd 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -109,6 +109,7 @@ resource "aws_lambda_function" "cognito_pre_auth_lambda" { source_code_hash = filebase64sha256("${path.module}/pre_auth_lambda.zip") filename = "${path.module}/pre_auth_lambda.zip" timeout = 15 + description = "Handles pre-authentication events in Cognito" } resource "aws_lambda_function" "cognito_post_auth_lambda" { @@ -120,6 +121,7 @@ resource "aws_lambda_function" "cognito_post_auth_lambda" { source_code_hash = filebase64sha256("${path.module}/post_auth_lambda.zip") filename = "${path.module}/post_auth_lambda.zip" timeout = 15 + description = "Handles post-authentication events in Cognito" } resource "aws_lambda_function" "cognito_pre_signup_lambda" { @@ -131,6 +133,7 @@ resource "aws_lambda_function" "cognito_pre_signup_lambda" { source_code_hash = filebase64sha256("${path.module}/pre_signup_lambda.zip") filename = "${path.module}/pre_signup_lambda.zip" timeout = 15 + description = "Handles pre-signup events in Cognito" } resource "aws_lambda_function" "cognito_user_migration_lambda" { @@ -142,6 +145,7 @@ resource "aws_lambda_function" "cognito_user_migration_lambda" { source_code_hash = filebase64sha256("${path.module}/user_migration_lambda.zip") filename = "${path.module}/user_migration_lambda.zip" timeout = 15 + description = "Handles user migration events in Cognito" } resource "aws_iam_role" "cognito_lambda_role" { From e29233fbb7d3a9b141f62846af3c05bd9656acfd Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 4 Feb 2025 12:06:19 +0000 Subject: [PATCH 25/38] CDD-2443 Add description for api gateway lambda --- terraform/modules/api-gateway/main.tf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/terraform/modules/api-gateway/main.tf b/terraform/modules/api-gateway/main.tf index b9132d4d..ebcb9662 100644 --- a/terraform/modules/api-gateway/main.tf +++ b/terraform/modules/api-gateway/main.tf @@ -7,9 +7,10 @@ resource "aws_lambda_function" "api_gateway_lambda" { 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 + 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" { From c196f66149108dab4334bce6c011e4006b991dcd Mon Sep 17 00:00:00 2001 From: 8lane Date: Tue, 4 Feb 2025 14:05:27 +0000 Subject: [PATCH 26/38] chore: update CF auth headers + Cognito callback urls --- terraform/20-app/cloud-front.front-end.tf | 26 +++++++++++------------ terraform/20-app/cognito.tf | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/terraform/20-app/cloud-front.front-end.tf b/terraform/20-app/cloud-front.front-end.tf index 9213a774..3e126d2d 100644 --- a/terraform/20-app/cloud-front.front-end.tf +++ b/terraform/20-app/cloud-front.front-end.tf @@ -184,7 +184,11 @@ resource "aws_cloudfront_origin_request_policy" "front_end" { cookies_config { cookie_behavior = "whitelist" cookies { - items = ["UKHSAConsentGDPR"] + items = flatten(concat(["UKHSAConsentGDPR", local.is_auth ? [ + "__Host-next-auth.csrf-token", + "__Secure-next-auth.callback-url", + "__Secure-next-auth.session-token", + ] : []])) } } headers_config { @@ -199,21 +203,17 @@ resource "aws_cloudfront_origin_request_policy" "front_end_auth" { name = "${local.prefix}-front-end-auth" cookies_config { - cookie_behavior = "whitelist" - cookies { - items = [ - "next-auth.session-token", - "__Secure-next-auth.session-token", - "next-auth.csrf-token", - "__Host-next-auth.csrf-token", - "next-auth.callback-url", - "next-auth.state" - ] - } + cookie_behavior = "all" } headers_config { - header_behavior = "allViewer" + header_behavior = "whitelist" + headers { + items = [ + "Accept", + "Content-Type", + ] + } } query_strings_config { query_string_behavior = "all" diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index e6be0159..6522523a 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -48,8 +48,8 @@ module "cognito" { user_pool_name = "${local.prefix}-user-pool" client_name = "${local.prefix}-client" user_pool_domain = "${local.prefix}-domain" - callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/api/auth/callback/cognito"] - logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk"] + callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/api/auth/callback/cognito", "http://localhost:3000/api/auth/callback/cognito", "http://localhost:3001/api/auth/callback/cognito"] + logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk", "http://localhost:3000", "http://localhost:3001"] region = local.region # Placeholder for SAML metadata URL, used only when SAML is enabled From 96b1c11deb7a95b60d6d3e18518900aec66df7a0 Mon Sep 17 00:00:00 2001 From: 8lane Date: Tue, 4 Feb 2025 14:13:04 +0000 Subject: [PATCH 27/38] chore: is_dev condition for cognito callbacks --- terraform/20-app/cognito.tf | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index 6522523a..323f117a 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -48,8 +48,14 @@ module "cognito" { user_pool_name = "${local.prefix}-user-pool" client_name = "${local.prefix}-client" user_pool_domain = "${local.prefix}-domain" - callback_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/api/auth/callback/cognito", "http://localhost:3000/api/auth/callback/cognito", "http://localhost:3001/api/auth/callback/cognito"] - logout_urls = ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk", "http://localhost:3000", "http://localhost:3001"] + callback_urls = concat( + ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk/api/auth/callback/cognito"], + local.is_dev ? ["http://localhost:3000/api/auth/callback/cognito", "http://localhost:3001/api/auth/callback/cognito"] : [] + ) + logout_urls = concat( + ["https://${terraform.workspace}.dev.ukhsa-dashboard.data.gov.uk"], + local.is_dev ? ["http://localhost:3000", "http://localhost:3001"] : [] + ) region = local.region # Placeholder for SAML metadata URL, used only when SAML is enabled From aca1ac03c128b600be7e41adeeff81a821eae21c Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 4 Feb 2025 16:43:36 +0000 Subject: [PATCH 28/38] CDD-2443 Changes to token timeouts and lambda role and policy --- terraform/modules/cognito/main.tf | 15 ++++++-- terraform/modules/cognito/post_auth.js | 34 ++++++++++-------- .../modules/cognito/post_auth_lambda.zip | Bin 504 -> 554 bytes 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 16e72ccd..f4b9f2a9 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -44,6 +44,10 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { allowed_oauth_flows_user_pool_client = true allowed_oauth_scopes = ["openid", "aws.cognito.signin.user.admin"] + access_token_validity = 1 # 1 hour + id_token_validity = 1 # 1 hour + refresh_token_validity = 720 # 720 hours (30 days) + callback_urls = var.callback_urls logout_urls = var.logout_urls @@ -180,7 +184,8 @@ resource "aws_iam_role_policy" "cognito_lambda_role_policy" { "logs:PutLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams", - "logs:GetLogEvents" + "logs:GetLogEvents", + "logs:DeleteLogStream" ], Resource = "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.prefix}-*:log-stream:*" }, @@ -198,11 +203,15 @@ resource "aws_iam_role_policy" "cognito_lambda_role_policy" { "cognito-idp:UpdateUserPoolClient", "cognito-idp:AdminGetUser" ], - Resource = aws_cognito_user_pool.user_pool.arn + Resource = "arn:aws:cognito-idp:${var.region}:${data.aws_caller_identity.current.account_id}:userpool/${aws_cognito_user_pool.user_pool.id}" }, { Effect = "Allow", - Action = "lambda:InvokeFunction", + Action = [ + "lambda:InvokeFunction", + "lambda:GetFunction", + "lambda:GetFunctionConfiguration" + ], Resource = "arn:aws:lambda:${var.region}:${data.aws_caller_identity.current.account_id}:function:${var.prefix}-*" } ] diff --git a/terraform/modules/cognito/post_auth.js b/terraform/modules/cognito/post_auth.js index ff7dffc8..f2addb2d 100644 --- a/terraform/modules/cognito/post_auth.js +++ b/terraform/modules/cognito/post_auth.js @@ -1,21 +1,27 @@ exports.handler = async (event) => { console.log("Post-auth Lambda invoked with event:", JSON.stringify(event, null, 2)); - console.log("Trigger source:", event.triggerSource); - console.log("User Pool ID:", event.userPoolId); - console.log("User Name:", event.userName); - if (event.request.userAttributes) { - console.log("User attributes:", JSON.stringify(event.request.userAttributes, null, 2)); - } else { - console.log("No user attributes provided in the event."); - } + try { + console.log("Trigger source:", event.triggerSource); + console.log("User Pool ID:", event.userPoolId); + console.log("User Name:", event.userName); - console.log("Environment variables:", process.env); + if (event.request.userAttributes) { + console.log("User attributes:", JSON.stringify(event.request.userAttributes, null, 2)); + } else { + console.log("No user attributes provided in the event."); + } - if (event.triggerSource !== 'PostAuthentication_Authentication') { - console.warn("Unexpected trigger source:", event.triggerSource); - } + console.log("Environment variables:", process.env); - console.log("Response being returned:", JSON.stringify(event.response, null, 2)); - return event; + if (event.triggerSource !== 'PostAuthentication_Authentication') { + console.warn("Unexpected trigger source:", event.triggerSource); + } + + console.log("Response being returned:", JSON.stringify(event.response, null, 2)); + return event; + } catch (error) { + console.error("Error in Post-auth Lambda:", error); + throw error; + } }; \ No newline at end of file diff --git a/terraform/modules/cognito/post_auth_lambda.zip b/terraform/modules/cognito/post_auth_lambda.zip index 9a4f36ef65e68dafc8aca4b0b044c3406fd4761e..db9f4094adb1eef4396b77c8a86c8b2d24d69830 100644 GIT binary patch literal 554 zcmWIWW@Zs#U|`^2P-$|BlFCbHs9|Jac+AYez{4QJP>^3-5}#OFlA)JX92&yOz}#%R zD7_VkODnh;7+Jmom4bCo4L<01*nns6d+jrN(MvBfyDwAnZ8|Iwzto7zAN&*_G4v0VH*o0$L4Uso{cW4wjA#sWHanhTHAB( z!ub*-IlZkLuP@r5Y18Q|!98Ks6?uunVMbxW`R&3LF}C_O$)2lR)_wOYVp?@#6X%_Z zdnEzd(YMSk|2?Txov9Kt^&+clgy%J>eWgEEwM8zU{3mV3&MQ{UKmT?{8ALUH{-Knw zXm&#_^u)#|Stm=AC;9(~Tu>Nje0pnZtLx*rrdQ`W|2gt)=2hjppFXUpXE?(X=e6rX zz?RQWe!Hd^^80CR&@_9?cRrQaQ-e)30s_u=WY zmYp{qw7W}76d(V)$YmK&;xvko@aSI!>xF^%(D$8ekr2ps`KU}hG z`?u0d({IH|Ji5WbubS2;UH(6!b>DxR#kxQHCMc=%vCTDa`6)k{VAi5DPVaSRwI)7B>OjtZX2)j6fI!q$hy1GXMaLJ;%8K From 07700d918911878360fcc094113c1da6c3aca013 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 11 Feb 2025 13:31:31 +0000 Subject: [PATCH 29/38] CDD-2443 Removal of multi IdP and pre post logging lambdas --- terraform/20-app/cognito.tf | 33 ++-- terraform/modules/cognito/main.tf | 176 ++---------------- terraform/modules/cognito/outputs.tf | 5 - terraform/modules/cognito/post_auth.js | 27 --- .../modules/cognito/post_auth_lambda.zip | Bin 554 -> 0 bytes terraform/modules/cognito/pre_auth.js | 4 - terraform/modules/cognito/pre_auth_lambda.zip | Bin 291 -> 0 bytes terraform/modules/cognito/pre_signup.js | 15 -- .../modules/cognito/pre_signup_lambda.zip | Bin 461 -> 0 bytes terraform/modules/cognito/user_migration.js | 4 - .../modules/cognito/user_migration_lambda.zip | Bin 305 -> 0 bytes terraform/modules/cognito/vars.tf | 47 ++--- 12 files changed, 51 insertions(+), 260 deletions(-) delete mode 100644 terraform/modules/cognito/post_auth.js delete mode 100644 terraform/modules/cognito/post_auth_lambda.zip delete mode 100644 terraform/modules/cognito/pre_auth.js delete mode 100644 terraform/modules/cognito/pre_auth_lambda.zip delete mode 100644 terraform/modules/cognito/pre_signup.js delete mode 100644 terraform/modules/cognito/pre_signup_lambda.zip delete mode 100644 terraform/modules/cognito/user_migration.js delete mode 100644 terraform/modules/cognito/user_migration_lambda.zip diff --git a/terraform/20-app/cognito.tf b/terraform/20-app/cognito.tf index 323f117a..61f83979 100644 --- a/terraform/20-app/cognito.tf +++ b/terraform/20-app/cognito.tf @@ -43,7 +43,6 @@ resource "aws_iam_role_policy_attachment" "cognito_sns_policy_attachment" { module "cognito" { source = "../modules/cognito" - sns_role_arn = aws_iam_role.cognito_sns_role.arn user_pool_name = "${local.prefix}-user-pool" client_name = "${local.prefix}-client" @@ -58,20 +57,32 @@ module "cognito" { ) region = local.region - # Placeholder for SAML metadata URL, used only when SAML is enabled - # we will need to add multiple metadata_urls e.g. cobr_metadata_url and nhs_metadata_url for each provider - metadata_url = "https://example.com/metadata.xml" - - # Placeholder for OIDC configuration, used only when OIDC is enabled - # we will need to add multiple variables e.g. cobr_oidc_client_id and nhs_oidc_client_id for each provider - oidc_client_id = "oidc-client-id" - oidc_client_secret = "oidc-client-secret" - oidc_issuer_url = "https://example.com/issuer" - oidc_attributes_url = "https://example.com/attributes" + ukhsa_oidc_client_id = "ukhsa-oidc-client-id" + ukhsa_oidc_client_secret = "ukhsa-oidc-client-secret" + ukhsa_oidc_issuer_url = "https://example.com/issuer" + ukhsa_oidc_attributes_url = "https://example.com/attributes" + lambda_role_arn = aws_iam_role.cognito_lambda_role.arn 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/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index f4b9f2a9..78749f24 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -5,13 +5,6 @@ resource "aws_cognito_user_pool" "user_pool" { mfa_configuration = "OFF" - lambda_config { - pre_authentication = aws_lambda_function.cognito_pre_auth_lambda.arn - post_authentication = aws_lambda_function.cognito_post_auth_lambda.arn - pre_sign_up = aws_lambda_function.cognito_pre_signup_lambda.arn - user_migration = aws_lambda_function.cognito_user_migration_lambda.arn - } - password_policy { minimum_length = 8 require_lowercase = true @@ -20,7 +13,7 @@ resource "aws_cognito_user_pool" "user_pool" { require_uppercase = true } - auto_verified_attributes = [] + auto_verified_attributes = ["email"] account_recovery_setting { recovery_mechanism { @@ -32,8 +25,7 @@ resource "aws_cognito_user_pool" "user_pool" { resource "aws_cognito_user_pool_client" "user_pool_client" { depends_on = [ - aws_cognito_identity_provider.cognito_oidc_idp, - aws_cognito_identity_provider.cognito_saml_idp + aws_cognito_identity_provider.ukhsa_oidc_idp ] name = var.client_name @@ -42,7 +34,7 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { allowed_oauth_flows = ["code"] allowed_oauth_flows_user_pool_client = true - allowed_oauth_scopes = ["openid", "aws.cognito.signin.user.admin"] + allowed_oauth_scopes = ["openid", "email", "aws.cognito.signin.user.admin"] access_token_validity = 1 # 1 hour id_token_validity = 1 # 1 hour @@ -51,7 +43,7 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { callback_urls = var.callback_urls logout_urls = var.logout_urls - supported_identity_providers = var.enable_oidc ? ["COGNITO", "TBCSAML", "TBCOIDC"] : ["COGNITO"] + supported_identity_providers = var.enable_ukhsa_oidc ? ["COGNITO", "UKHSAOIDC"] : ["COGNITO"] } resource "aws_cognito_user_pool_domain" "cognito_user_pool_domain" { @@ -63,35 +55,19 @@ resource "aws_cognito_user_pool_domain" "cognito_user_pool_domain" { } } -# Stubbed SAML Identity Provider -resource "aws_cognito_identity_provider" "cognito_saml_idp" { - count = var.enable_saml ? 1 : 0 - - user_pool_id = aws_cognito_user_pool.user_pool.id - provider_name = "TBCSAML" - provider_type = "SAML" - - provider_details = { - MetadataURL = var.saml_metadata_url != "" ? var.saml_metadata_url : "https://example.com/saml-metadata" - IDPSignout = var.saml_logout_url != "" ? var.saml_logout_url : "https://example.com/logout" - } -} - -# Stubbed OIDC Identity Provider -resource "aws_cognito_identity_provider" "cognito_oidc_idp" { - count = var.enable_oidc ? 1 : 0 - - user_pool_id = aws_cognito_user_pool.user_pool.id - provider_name = "TBCOIDC" +resource "aws_cognito_identity_provider" "ukhsa_oidc_idp" { + count = var.enable_ukhsa_oidc ? 1 : 0 + user_pool_id = aws_cognito_user_pool.user_pool.id + provider_name = "UKHSAOIDC" provider_type = "OIDC" provider_details = { - client_id = var.oidc_client_id != "" ? var.oidc_client_id : "stub-client-id" - client_secret = var.oidc_client_secret != "" ? var.oidc_client_secret : "stub-client-secret" - oidc_issuer = var.oidc_issuer_url != "" ? var.oidc_issuer_url : "https://example.com" + client_id = var.ukhsa_oidc_client_id + client_secret = var.ukhsa_oidc_client_secret + oidc_issuer = var.ukhsa_oidc_issuer_url authorize_scopes = "openid email" attributes_request_method = "GET" - attributes_url = var.oidc_attributes_url != "" ? var.oidc_attributes_url : "https://example.com/attributes" + attributes_url = var.ukhsa_oidc_attributes_url attributes_url_add_attributes = "true" } } @@ -104,131 +80,9 @@ resource "aws_cognito_user_group" "cognito_user_groups" { description = "Group for ${each.value} role" } -resource "aws_lambda_function" "cognito_pre_auth_lambda" { - function_name = "${var.prefix}-pre-auth-lambda" - runtime = "nodejs18.x" - role = aws_iam_role.cognito_lambda_role.arn - - handler = "pre_auth.handler" - source_code_hash = filebase64sha256("${path.module}/pre_auth_lambda.zip") - filename = "${path.module}/pre_auth_lambda.zip" - timeout = 15 - description = "Handles pre-authentication events in Cognito" -} - -resource "aws_lambda_function" "cognito_post_auth_lambda" { - function_name = "${var.prefix}-post-auth-lambda" - runtime = "nodejs18.x" - role = aws_iam_role.cognito_lambda_role.arn - - handler = "post_auth.handler" - source_code_hash = filebase64sha256("${path.module}/post_auth_lambda.zip") - filename = "${path.module}/post_auth_lambda.zip" - timeout = 15 - description = "Handles post-authentication events in Cognito" -} - -resource "aws_lambda_function" "cognito_pre_signup_lambda" { - function_name = "${var.prefix}-pre-signup-lambda" - runtime = "nodejs18.x" - role = aws_iam_role.cognito_lambda_role.arn - - handler = "pre_signup.handler" - source_code_hash = filebase64sha256("${path.module}/pre_signup_lambda.zip") - filename = "${path.module}/pre_signup_lambda.zip" - timeout = 15 - description = "Handles pre-signup events in Cognito" -} - -resource "aws_lambda_function" "cognito_user_migration_lambda" { - function_name = "${var.prefix}-user-migration-lambda" - runtime = "nodejs18.x" - role = aws_iam_role.cognito_lambda_role.arn - - handler = "user_migration.handler" - source_code_hash = filebase64sha256("${path.module}/user_migration_lambda.zip") - filename = "${path.module}/user_migration_lambda.zip" - timeout = 15 - description = "Handles user migration events in Cognito" -} - -resource "aws_iam_role" "cognito_lambda_role" { - name = "${var.prefix}-lambda-execution-role" - - assume_role_policy = jsonencode({ - Version = "2012-10-17", - Statement = [ - { - Effect = "Allow", - Principal = { - Service = "lambda.amazonaws.com" - }, - Action = "sts:AssumeRole" - } - ] - }) -} - -resource "aws_iam_role_policy" "cognito_lambda_role_policy" { - name = "${var.prefix}-lambda-execution-policy" - role = aws_iam_role.cognito_lambda_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:DeleteLogStream" - ], - Resource = "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.prefix}-*:log-stream:*" - }, - { - Effect = "Allow", - Action = [ - "cognito-idp:PostAuthentication", - "cognito-idp:PreSignUp", - "cognito-idp:AdminCreateUser", - "cognito-idp:AdminUpdateUserAttributes", - "cognito-idp:AdminInitiateAuth", - "cognito-idp:ListUsers", - "cognito-idp:DescribeUserPool", - "cognito-idp:GetUser", - "cognito-idp:UpdateUserPoolClient", - "cognito-idp:AdminGetUser" - ], - Resource = "arn:aws:cognito-idp:${var.region}:${data.aws_caller_identity.current.account_id}:userpool/${aws_cognito_user_pool.user_pool.id}" - }, - { - Effect = "Allow", - Action = [ - "lambda:InvokeFunction", - "lambda:GetFunction", - "lambda:GetFunctionConfiguration" - ], - Resource = "arn:aws:lambda:${var.region}:${data.aws_caller_identity.current.account_id}:function:${var.prefix}-*" - } - ] - }) -} - -resource "aws_iam_role_policy_attachment" "cognito_lambda_basic_exec_attach" { - role = aws_iam_role.cognito_lambda_role.name - policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" -} - -resource "aws_lambda_permission" "allow_cognito" { - statement_id = "AllowCognitoInvoke" - action = "lambda:InvokeFunction" - function_name = aws_lambda_function.cognito_pre_signup_lambda.arn - principal = "cognito-idp.amazonaws.com" - source_arn = aws_cognito_user_pool.user_pool.arn +output "cognito_lambda_role_arn" { + description = "The ARN of the Cognito Lambda execution role" + value = var.lambda_role_arn } variable "prefix" { diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 65f22a57..20022682 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -46,11 +46,6 @@ output "cognito_user_pool_arn" { sensitive = true } -output "cognito_lambda_role_arn" { - description = "The ARN of the Cognito Lambda execution role" - value = aws_iam_role.cognito_lambda_role.arn -} - output "cognito_user_pool_client_secret" { description = "The Client Secret for Cognito User Pool Client" value = aws_cognito_user_pool_client.user_pool_client.client_secret diff --git a/terraform/modules/cognito/post_auth.js b/terraform/modules/cognito/post_auth.js deleted file mode 100644 index f2addb2d..00000000 --- a/terraform/modules/cognito/post_auth.js +++ /dev/null @@ -1,27 +0,0 @@ -exports.handler = async (event) => { - console.log("Post-auth Lambda invoked with event:", JSON.stringify(event, null, 2)); - - try { - console.log("Trigger source:", event.triggerSource); - console.log("User Pool ID:", event.userPoolId); - console.log("User Name:", event.userName); - - if (event.request.userAttributes) { - console.log("User attributes:", JSON.stringify(event.request.userAttributes, null, 2)); - } else { - console.log("No user attributes provided in the event."); - } - - console.log("Environment variables:", process.env); - - if (event.triggerSource !== 'PostAuthentication_Authentication') { - console.warn("Unexpected trigger source:", event.triggerSource); - } - - console.log("Response being returned:", JSON.stringify(event.response, null, 2)); - return event; - } catch (error) { - console.error("Error in Post-auth Lambda:", error); - throw error; - } -}; \ No newline at end of file diff --git a/terraform/modules/cognito/post_auth_lambda.zip b/terraform/modules/cognito/post_auth_lambda.zip deleted file mode 100644 index db9f4094adb1eef4396b77c8a86c8b2d24d69830..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 554 zcmWIWW@Zs#U|`^2P-$|BlFCbHs9|Jac+AYez{4QJP>^3-5}#OFlA)JX92&yOz}#%R zD7_VkODnh;7+Jmom4bCo4L<01*nns6d+jrN(MvBfyDwAnZ8|Iwzto7zAN&*_G4v0VH*o0$L4Uso{cW4wjA#sWHanhTHAB( z!ub*-IlZkLuP@r5Y18Q|!98Ks6?uunVMbxW`R&3LF}C_O$)2lR)_wOYVp?@#6X%_Z zdnEzd(YMSk|2?Txov9Kt^&+clgy%J>eWgEEwM8zU{3mV3&MQ{UKmT?{8ALUH{-Knw zXm&#_^u)#|Stm=AC;9(~Tu>Nje0pnZtLx*rrdQ`W|2gt)=2hjppFXUpXE?(X=e6rX zz?RQWe!Hd^^80CR&@_9?cRrQ { - console.log("Pre-auth Lambda invoked with event:", JSON.stringify(event)); - return event; -}; \ No newline at end of file diff --git a/terraform/modules/cognito/pre_auth_lambda.zip b/terraform/modules/cognito/pre_auth_lambda.zip deleted file mode 100644 index 4f3b382b693b94c13516c9b0d34afae3114885b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 291 zcmWIWW@Zs#U|`^2(1~-2+SRFPT@K`R05La%3`0RtYJ6g8NrqllacBr91M}g33)7DR zacKoN10%~>uuSyaq!X$ySAANt<=DZh8;}1A2`Kd! zEoL}xk$<{4cwIudom`Ar@13Kszvy49JE?hd!Jp#Vk00X$ycwC~m~pvY0_X<@2A~re fmNbG`D1Kpu_yx@$0p6@^Af=2z7zm{IfH({Q { - console.log("Pre-signup Lambda invoked with event:", JSON.stringify(event, null, 2)); - - // Check if the email attribute exists before auto-verifying - if (event.request.userAttributes && event.request.userAttributes.email) { - event.response.autoVerifyEmail = true; - } else { - console.log("No email provided. Skipping auto-verification."); - } - - // auto-confirm the user - event.response.autoConfirmUser = true; - - return event; -}; \ No newline at end of file diff --git a/terraform/modules/cognito/pre_signup_lambda.zip b/terraform/modules/cognito/pre_signup_lambda.zip deleted file mode 100644 index 1fd67eb02afc759777d181932da3826252c6d62e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 461 zcmWIWW@Zs#U|`^2nAK_*m8o;uSeB82;TsV1GRQC#6s5)&XQtr4`%^j4WS)>cHA-Cpu;`849$%|EiC)(IqqkQ08QWhvv3yD{;~~aw6?-PB{_uPDv!iwv&+Uu# z7Y*aO7X50M#NSn%Q=?8qnw~m;=KfI?UzKY|c5j&z{OQg7j?<3c-(7a+6P!FPkm>fp zpp@f}*aN&7ndF#pg|Y-N^cfg{0m-nW5yV0Zb5=;0qlI^XH!B-RF(VKL1L+iyeg*)) CTC { - console.log("User migration Lambda invoked with event:", JSON.stringify(event)); - return event; -}; \ No newline at end of file diff --git a/terraform/modules/cognito/user_migration_lambda.zip b/terraform/modules/cognito/user_migration_lambda.zip deleted file mode 100644 index b28ab2b48d47eb8166b983c4bd0fef5ef1688937..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 305 zcmWIWW@Zs#U|`^2cwS%^m7mw-SqbFz0kI&13`1#gYEgV{W_nR#NoIbYURH5v2qy#c z#P-?glYqFif}4Sn3qnT_kr=)i-SKJrmppVd}&gi zYv;%JLM7*no7V?kDY{(E$0-{1q4F7@)|?4z+sfGAGl^L})Zv`1vQbOFGLXINRd36~ z2kqG(9BfX?GTWT2iuj$ov+?iGlAKMNg-dS#`F|~MuGTH*pU-zadb}^dn~_P58J904 nfPP_M06LOkNh64b#ZRmdKcV?2z?+o~q=69#!-4b>5QhN(_zz~z diff --git a/terraform/modules/cognito/vars.tf b/terraform/modules/cognito/vars.tf index bb4ccfd2..826cbffe 100644 --- a/terraform/modules/cognito/vars.tf +++ b/terraform/modules/cognito/vars.tf @@ -13,12 +13,6 @@ variable "sns_role_arn" { } } -variable "metadata_url" { - description = "Metadata URL for NHS SAML IdP" - type = string - default = "https://auth.nhs.gov.uk" -} - variable "callback_urls" { description = "List of allowed callback URLs for OAuth flows" type = list(string) @@ -60,50 +54,37 @@ variable "user_pool_domain" { type = string } -variable "enable_saml" { - description = "Enable SAML integration" - type = bool - default = false -} - -variable "saml_metadata_url" { - description = "URL for SAML metadata" +variable "ukhsa_oidc_client_id" { + description = "UKHSA OIDC Client ID" type = string default = "" } -variable "saml_logout_url" { - description = "SAML logout URL" +variable "ukhsa_oidc_client_secret" { + description = "UKHSA OIDC Client Secret" type = string default = "" } -variable "enable_oidc" { - description = "Enable OIDC integration" - type = bool - default = false -} - -variable "oidc_client_id" { - description = "OIDC Client ID" +variable "ukhsa_oidc_issuer_url" { + description = "UKHSA OIDC Issuer URL" type = string default = "" } -variable "oidc_client_secret" { - description = "OIDC Client Secret" +variable "ukhsa_oidc_attributes_url" { + description = "UKHSA OIDC Attributes URL" type = string default = "" } -variable "oidc_issuer_url" { - description = "OIDC Issuer URL" - type = string - default = "" +variable "enable_ukhsa_oidc" { + description = "Enable UKHSA OIDC Identity Provider" + type = bool + default = false } -variable "oidc_attributes_url" { - description = "OIDC Attributes URL" +variable "lambda_role_arn" { + description = "The ARN of the Cognito Lambda execution role" type = string - default = "" } \ No newline at end of file From 764940aad8004e771d3fbb7449bea308a27f9733 Mon Sep 17 00:00:00 2001 From: 8lane Date: Tue, 4 Feb 2025 19:14:18 +0000 Subject: [PATCH 30/38] fix: remove lambda triggers and tweak cognito config --- terraform/modules/cognito/main.tf | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 78749f24..9f4a32b9 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -3,6 +3,8 @@ data "aws_caller_identity" "current" {} resource "aws_cognito_user_pool" "user_pool" { name = var.user_pool_name + username_attributes = ["email"] + mfa_configuration = "OFF" password_policy { @@ -36,10 +38,23 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { allowed_oauth_flows_user_pool_client = true allowed_oauth_scopes = ["openid", "email", "aws.cognito.signin.user.admin"] - access_token_validity = 1 # 1 hour - id_token_validity = 1 # 1 hour + access_token_validity = 60 # 1 hour + id_token_validity = 60 # 1 hour refresh_token_validity = 720 # 720 hours (30 days) + token_validity_units { + access_token = "minutes" + id_token = "minutes" + refresh_token = "days" + } + + prevent_user_existence_errors = "ENABLED" + + explicit_auth_flows = [ + "ALLOW_REFRESH_TOKEN_AUTH", + "ALLOW_USER_PASSWORD_AUTH", + ] + callback_urls = var.callback_urls logout_urls = var.logout_urls From 23039678cdbe2f63eaf7da85d4b8fd0b1f388bdd Mon Sep 17 00:00:00 2001 From: 8lane Date: Fri, 7 Feb 2025 16:04:45 +0000 Subject: [PATCH 31/38] fix: authjs upgrades --- terraform/20-app/cloud-front.front-end.tf | 6 +++--- terraform/modules/cognito/main.tf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/terraform/20-app/cloud-front.front-end.tf b/terraform/20-app/cloud-front.front-end.tf index 3e126d2d..078b192a 100644 --- a/terraform/20-app/cloud-front.front-end.tf +++ b/terraform/20-app/cloud-front.front-end.tf @@ -185,9 +185,9 @@ resource "aws_cloudfront_origin_request_policy" "front_end" { cookie_behavior = "whitelist" cookies { items = flatten(concat(["UKHSAConsentGDPR", local.is_auth ? [ - "__Host-next-auth.csrf-token", - "__Secure-next-auth.callback-url", - "__Secure-next-auth.session-token", + "__Secure-authjs.csrf-token", + "__Secure-authjs.csrf-token", + "__Secure-authjs.session-token", ] : []])) } } diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 9f4a32b9..a8272cd0 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -36,7 +36,7 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { allowed_oauth_flows = ["code"] allowed_oauth_flows_user_pool_client = true - allowed_oauth_scopes = ["openid", "email", "aws.cognito.signin.user.admin"] + allowed_oauth_scopes = ["openid", "email", "profile", "aws.cognito.signin.user.admin"] access_token_validity = 60 # 1 hour id_token_validity = 60 # 1 hour From b6f21272800a630a98b600d1fccf096d7e6cd793 Mon Sep 17 00:00:00 2001 From: 8lane Date: Wed, 12 Feb 2025 12:16:17 +0000 Subject: [PATCH 32/38] chore: oauth domain passed to fe & fix expiry units --- terraform/20-app/ecs.service.front-end.tf | 4 ++-- terraform/20-app/locals.tf | 1 - terraform/modules/cognito/main.tf | 12 +++--------- terraform/modules/cognito/outputs.tf | 6 ++++++ 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/terraform/20-app/ecs.service.front-end.tf b/terraform/20-app/ecs.service.front-end.tf index 73deabb1..30ad6cc3 100644 --- a/terraform/20-app/ecs.service.front-end.tf +++ b/terraform/20-app/ecs.service.front-end.tf @@ -75,8 +75,8 @@ module "ecs_service_front_end" { value = local.is_auth }, { - name = "AUTH_DEBUG", - value = local.debug + name = "AUTH_DOMAIN" + value = module.cognito.cognito_oauth_url }, { name = "NEXTAUTH_URL" diff --git a/terraform/20-app/locals.tf b/terraform/20-app/locals.tf index 0bd5c47c..92222093 100644 --- a/terraform/20-app/locals.tf +++ b/terraform/20-app/locals.tf @@ -12,7 +12,6 @@ locals { use_prod_sizing = contains(["perf", "pen", "prod"], local.environment) add_password_protection = local.environment == "staging" is_auth = local.environment == "auth" - debug = false wke = { account = ["dev", "test", "uat", "prod"] diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index a8272cd0..2443d5e5 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -38,16 +38,10 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { allowed_oauth_flows_user_pool_client = true allowed_oauth_scopes = ["openid", "email", "profile", "aws.cognito.signin.user.admin"] - access_token_validity = 60 # 1 hour - id_token_validity = 60 # 1 hour + access_token_validity = 1 # 1 hour + id_token_validity = 1 # 1 hour refresh_token_validity = 720 # 720 hours (30 days) - - token_validity_units { - access_token = "minutes" - id_token = "minutes" - refresh_token = "days" - } - + prevent_user_existence_errors = "ENABLED" explicit_auth_flows = [ diff --git a/terraform/modules/cognito/outputs.tf b/terraform/modules/cognito/outputs.tf index 20022682..12d4b9a0 100644 --- a/terraform/modules/cognito/outputs.tf +++ b/terraform/modules/cognito/outputs.tf @@ -16,6 +16,12 @@ output "cognito_user_pool_domain" { sensitive = true } +output "cognito_oauth_url" { + description = "The Cognito User Pool OAuth URL" + value = "https://${aws_cognito_user_pool_domain.cognito_user_pool_domain.domain}.auth.${var.region}.amazoncognito.com" + sensitive = true +} + output "cognito_oauth_authorize_url" { description = "The Cognito User Pool OAuth authorize URL" value = "https://${aws_cognito_user_pool_domain.cognito_user_pool_domain.domain}.auth.${var.region}.amazoncognito.com/oauth2/authorize" From 48ae0f2e6b601eaac9d8447f6e5daf6d567f1d82 Mon Sep 17 00:00:00 2001 From: 8lane Date: Wed, 12 Feb 2025 12:33:25 +0000 Subject: [PATCH 33/38] chore: additional auth.js cookies --- terraform/20-app/cloud-front.front-end.tf | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/terraform/20-app/cloud-front.front-end.tf b/terraform/20-app/cloud-front.front-end.tf index 078b192a..99247c79 100644 --- a/terraform/20-app/cloud-front.front-end.tf +++ b/terraform/20-app/cloud-front.front-end.tf @@ -185,9 +185,13 @@ resource "aws_cloudfront_origin_request_policy" "front_end" { cookie_behavior = "whitelist" cookies { items = flatten(concat(["UKHSAConsentGDPR", local.is_auth ? [ - "__Secure-authjs.csrf-token", - "__Secure-authjs.csrf-token", - "__Secure-authjs.session-token", + "__Secure-authjs.csrf-token", # CSRF token required for authentication flows + "__Secure-authjs.session-token", # Main session token + "__Secure-authjs.session-token.0", # Split session token (if size exceeds 4KB) + "__Secure-authjs.session-token.1", # Additional split session token + "__Secure-authjs.session-token.2", # Additional split session token + "__Secure-authjs.session-token.3", # Additional split session token + "__Secure-authjs.session-token.4", # Additional split session token (safety margin) ] : []])) } } From 58d62b9c969286910379f591ff9ee4529dab2900 Mon Sep 17 00:00:00 2001 From: 8lane Date: Wed, 12 Feb 2025 13:02:55 +0000 Subject: [PATCH 34/38] chore: callback url --- terraform/20-app/cloud-front.front-end.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/terraform/20-app/cloud-front.front-end.tf b/terraform/20-app/cloud-front.front-end.tf index 99247c79..f455b69b 100644 --- a/terraform/20-app/cloud-front.front-end.tf +++ b/terraform/20-app/cloud-front.front-end.tf @@ -185,6 +185,7 @@ resource "aws_cloudfront_origin_request_policy" "front_end" { cookie_behavior = "whitelist" cookies { items = flatten(concat(["UKHSAConsentGDPR", local.is_auth ? [ + "__Secure-authjs.callback-url", # Stores the redirect destination after authentication "__Secure-authjs.csrf-token", # CSRF token required for authentication flows "__Secure-authjs.session-token", # Main session token "__Secure-authjs.session-token.0", # Split session token (if size exceeds 4KB) From 7a822319a32f2842a6368be7e7eb07293eb682d7 Mon Sep 17 00:00:00 2001 From: 8lane Date: Thu, 13 Feb 2025 17:25:42 +0000 Subject: [PATCH 35/38] chore: allowlist set-cookie and change expiry units --- terraform/20-app/cloud-front.front-end.tf | 2 ++ terraform/modules/cognito/main.tf | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/terraform/20-app/cloud-front.front-end.tf b/terraform/20-app/cloud-front.front-end.tf index f455b69b..3dd6cf1b 100644 --- a/terraform/20-app/cloud-front.front-end.tf +++ b/terraform/20-app/cloud-front.front-end.tf @@ -217,9 +217,11 @@ resource "aws_cloudfront_origin_request_policy" "front_end_auth" { items = [ "Accept", "Content-Type", + "Set-Cookie", ] } } + query_strings_config { query_string_behavior = "all" } diff --git a/terraform/modules/cognito/main.tf b/terraform/modules/cognito/main.tf index 2443d5e5..489b77f7 100644 --- a/terraform/modules/cognito/main.tf +++ b/terraform/modules/cognito/main.tf @@ -38,9 +38,15 @@ resource "aws_cognito_user_pool_client" "user_pool_client" { allowed_oauth_flows_user_pool_client = true allowed_oauth_scopes = ["openid", "email", "profile", "aws.cognito.signin.user.admin"] - access_token_validity = 1 # 1 hour - id_token_validity = 1 # 1 hour - refresh_token_validity = 720 # 720 hours (30 days) + access_token_validity = 60 # 60 minutes + id_token_validity = 60 # 60 minutes + refresh_token_validity = 30 # 30 days + + token_validity_units { + access_token = "minutes" + id_token = "minutes" + refresh_token = "days" + } prevent_user_existence_errors = "ENABLED" From f652c608b0e20faacd355a2a3904e4a51da151cb Mon Sep 17 00:00:00 2001 From: 8lane Date: Fri, 14 Feb 2025 17:37:49 +0000 Subject: [PATCH 36/38] chore: add missing delete secret keys --- scripts/_secrets.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/_secrets.sh b/scripts/_secrets.sh index 9b9c358b..d5fca887 100644 --- a/scripts/_secrets.sh +++ b/scripts/_secrets.sh @@ -56,7 +56,9 @@ function _delete_all_secrets() { "uhd-${env}-feature-flags-api-keys" "uhd-${env}-esri-api-key" "uhd-${env}-esri-maps-service-credentials" - "uhd-${env}-slack-webhook-url") + "uhd-${env}-slack-webhook-url" + "uhd-${env}-cognito-service-credentials" + "uhd-${env}-auth-secret") for ((i=1; i<=${#secret_ids[@]}; ++i)); do _delete_secret "${secret_ids[i]}" From 9bb37474e6785d93ccfa60a6c3abcc295d6bb203 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Tue, 18 Feb 2025 16:46:12 +0000 Subject: [PATCH 37/38] 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 +} From 03694f1aea35ff92269ab8e5bd639b4be0065f43 Mon Sep 17 00:00:00 2001 From: Christian Martin Date: Wed, 19 Feb 2025 09:34:33 +0000 Subject: [PATCH 38/38] CDD-2443 Pin SNS module to version 6.1.2 --- terraform/20-app/sns.cognito.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/20-app/sns.cognito.tf b/terraform/20-app/sns.cognito.tf index 369f102a..36ce0137 100644 --- a/terraform/20-app/sns.cognito.tf +++ b/terraform/20-app/sns.cognito.tf @@ -1,6 +1,6 @@ module "cognito_sns" { source = "terraform-aws-modules/sns/aws" - version = "~> 5.0" + version = "6.1.2" name = "${local.prefix}-cognito-topic"