diff --git a/terraform/import.tf b/terraform/import.tf index 7ec9f5c..216cae1 100644 --- a/terraform/import.tf +++ b/terraform/import.tf @@ -531,3 +531,54 @@ import { to = aws_cloudwatch_log_group.database[each.key] id = "/aws/rds/instance/incubator-prod-database/${each.key}" } + +# Adopts the two Lambda triggers on the production home-unite-us pool, the role they +# run as, and the four /aws/lambda/* log groups. customMessage and mergeUsers are the +# LIVE production functions despite the naming -- the home-unite-us-* pair is QA's. +# See hackforla/incubator#17. +import { + to = module.home-unite-us.aws_iam_role.lambda_prod + id = "lambda" +} + +import { + to = module.home-unite-us.aws_iam_role_policy_attachment.lambda_execution_prod + id = "lambda/arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + +import { + to = module.home-unite-us.aws_iam_role_policy_attachment.lambda_cognito_prod + id = "lambda/arn:aws:iam::aws:policy/AmazonCognitoPowerUser" +} + +import { + to = module.home-unite-us.aws_lambda_function.cognito_custom_message_prod + id = "customMessage" +} + +import { + to = module.home-unite-us.aws_lambda_function.cognito_merge_users_prod + id = "mergeUsers" +} + +import { + to = module.home-unite-us.aws_lambda_permission.allow_message_execution_from_user_pool_prod + id = "customMessage/AllowMessageExecutionFromUserPool" +} + +import { + to = module.home-unite-us.aws_lambda_permission.allow_merge_execution_from_user_pool_prod + id = "mergeUsers/AllowMergeExecutionFromUserPool" +} + +import { + for_each = toset(["customMessage", "mergeUsers"]) + to = module.home-unite-us.aws_cloudwatch_log_group.lambda_prod[each.key] + id = "/aws/lambda/${each.key}" +} + +import { + for_each = toset(["customMessage", "mergeUsers"]) + to = module.home-unite-us.aws_cloudwatch_log_group.lambda[each.key] + id = "/aws/lambda/home-unite-us-${each.key}" +} diff --git a/terraform/projects/home-unite-us/README.md b/terraform/projects/home-unite-us/README.md index 864764d..925dec2 100644 --- a/terraform/projects/home-unite-us/README.md +++ b/terraform/projects/home-unite-us/README.md @@ -27,6 +27,8 @@ No requirements. | Name | Type | |------|------| +| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.lambda_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | | [aws_cognito_identity_provider.google_client](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_identity_provider) | resource | | [aws_cognito_identity_provider.google_client_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_identity_provider) | resource | | [aws_cognito_user_group.homeuniteus](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_group) | resource | @@ -41,16 +43,23 @@ No requirements. | [aws_iam_role.cognito_idp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.cognito_idp_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.lambda_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role_policy.cognito_sns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_iam_role_policy.cognito_sns_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_iam_role_policy_attachment.lambda_cognito](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.lambda_cognito_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.lambda_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.lambda_execution_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.prod_cognito](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.test-attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_lambda_function.cognito_custom_message](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_function.cognito_custom_message_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | | [aws_lambda_function.cognito_merge_users](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_function.cognito_merge_users_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | | [aws_lambda_permission.allow_merge_execution_from_user_pool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | +| [aws_lambda_permission.allow_merge_execution_from_user_pool_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | | [aws_lambda_permission.allow_message_execution_from_user_pool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | +| [aws_lambda_permission.allow_message_execution_from_user_pool_prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | | [aws_route53_record.apex](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | | [aws_route53_record.qa](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | | [aws_route53_record.www](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | diff --git a/terraform/projects/home-unite-us/cognito-prod.tf b/terraform/projects/home-unite-us/cognito-prod.tf index f8b8a03..0a93448 100644 --- a/terraform/projects/home-unite-us/cognito-prod.tf +++ b/terraform/projects/home-unite-us/cognito-prod.tf @@ -89,14 +89,12 @@ resource "aws_cognito_user_pool" "homeuniteus_prod" { email_sending_account = "COGNITO_DEFAULT" } - // Points at the legacy customMessage/mergeUsers pair by literal ARN. Those two - // functions are not managed by Terraform. This is deliberate: re-pointing the pool - // at the already-managed home-unite-us-* pair is a live change to production - // sign-up, and folding it in here would stop this import from planning clean. - // Tracked as follow-on work -- see hackforla/incubator#166. + // The production triggers are customMessage/mergeUsers, declared below -- NOT the + // home-unite-us-* pair in cognito-qa.tf, despite the naming. The two pairs run + // different packages, so re-pointing this pool would change production sign-up. lambda_config { - custom_message = "arn:aws:lambda:us-west-2:035866691871:function:customMessage" - pre_sign_up = "arn:aws:lambda:us-west-2:035866691871:function:mergeUsers" + custom_message = aws_lambda_function.cognito_custom_message_prod.arn + pre_sign_up = aws_lambda_function.cognito_merge_users_prod.arn } password_policy { @@ -330,3 +328,100 @@ resource "aws_cognito_user_pool_client" "homeuniteus_prod" { resource "aws_secretsmanager_secret" "cognito_client_prod" { name = "homeuniteus-cognito-client" } + +// The two Lambda triggers on the production pool, adopted in place. See +// hackforla/incubator#17. +// +// Each function points at the package that was deployed when it was imported, +// downloaded with `aws lambda get-function` and committed under lambda/prod/. Its hash +// matches the live CodeSha256, so the plan does not propose a code change. Do not point +// these at lambda/customMessage.js or lambda/merge_users.py instead: the source is the +// same today, but rebuilding the zip here would produce a different hash and upload +// new code to production sign-up. +resource "aws_iam_role" "lambda_prod" { + name = "lambda" + assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json + + tags = { + project = local.project_name + } +} + +resource "aws_iam_role_policy_attachment" "lambda_execution_prod" { + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + role = aws_iam_role.lambda_prod.name +} + +resource "aws_iam_role_policy_attachment" "lambda_cognito_prod" { + policy_arn = "arn:aws:iam::aws:policy/AmazonCognitoPowerUser" + role = aws_iam_role.lambda_prod.name +} + +resource "aws_lambda_function" "cognito_custom_message_prod" { + filename = "${path.module}/lambda/prod/customMessage.zip" + source_code_hash = filebase64sha256("${path.module}/lambda/prod/customMessage.zip") + function_name = "customMessage" + role = aws_iam_role.lambda_prod.arn + handler = "customMessage.handler" + architectures = ["x86_64"] + + // nodejs18.x is a deprecated Lambda runtime. Upgrading it is a separate change, not + // part of adopting the function. + runtime = "nodejs18.x" + + tags = { + project = local.project_name + } + + lifecycle { + prevent_destroy = true + } +} + +resource "aws_lambda_function" "cognito_merge_users_prod" { + filename = "${path.module}/lambda/prod/merge_users.zip" + source_code_hash = filebase64sha256("${path.module}/lambda/prod/merge_users.zip") + function_name = "mergeUsers" + role = aws_iam_role.lambda_prod.arn + handler = "merge_users.lambda_handler" + architectures = ["x86_64"] + runtime = "python3.12" + + tags = { + project = local.project_name + } + + lifecycle { + prevent_destroy = true + } +} + +resource "aws_lambda_permission" "allow_message_execution_from_user_pool_prod" { + statement_id = "AllowMessageExecutionFromUserPool" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.cognito_custom_message_prod.function_name + principal = "cognito-idp.amazonaws.com" + source_arn = aws_cognito_user_pool.homeuniteus_prod.arn +} + +resource "aws_lambda_permission" "allow_merge_execution_from_user_pool_prod" { + statement_id = "AllowMergeExecutionFromUserPool" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.cognito_merge_users_prod.function_name + principal = "cognito-idp.amazonaws.com" + source_arn = aws_cognito_user_pool.homeuniteus_prod.arn +} + +// Lambda creates its log group on first invoke, so these existed without ever being +// declared and had no retention at all. 180 days matches the RDS log groups in +// ../../database.tf; applying it deletes everything older. +resource "aws_cloudwatch_log_group" "lambda_prod" { + for_each = toset(["customMessage", "mergeUsers"]) + + name = "/aws/lambda/${each.key}" + retention_in_days = 180 + + tags = { + project = local.project_name + } +} diff --git a/terraform/projects/home-unite-us/cognito-qa.tf b/terraform/projects/home-unite-us/cognito-qa.tf index 7ed83ff..0734175 100644 --- a/terraform/projects/home-unite-us/cognito-qa.tf +++ b/terraform/projects/home-unite-us/cognito-qa.tf @@ -44,6 +44,9 @@ resource "aws_lambda_function" "cognito_custom_message" { source_code_hash = data.archive_file.cognito_custom_message.output_base64sha256 runtime = "nodejs18.x" + tags = { + project = local.project_name + } lifecycle { ignore_changes = [ source_code_hash ] } @@ -66,6 +69,9 @@ resource "aws_lambda_function" "cognito_merge_users" { source_code_hash = data.archive_file.cognito_merge_users.output_base64sha256 runtime = "python3.12" + tags = { + project = local.project_name + } lifecycle { ignore_changes = [ source_code_hash ] } @@ -378,4 +384,18 @@ resource "aws_secretsmanager_secret" "google_secret" { data "aws_secretsmanager_secret_version" "google_secret" { secret_id = aws_secretsmanager_secret.google_secret.id -} \ No newline at end of file +} + +// Lambda creates its log group on first invoke, so these existed without ever being +// declared and had no retention at all. 180 days matches the RDS log groups in +// ../../database.tf. See hackforla/incubator#17. +resource "aws_cloudwatch_log_group" "lambda" { + for_each = toset(["customMessage", "mergeUsers"]) + + name = "/aws/lambda/${local.project_name}-${each.key}" + retention_in_days = 180 + + tags = { + project = local.project_name + } +} diff --git a/terraform/projects/home-unite-us/lambda/prod/customMessage.zip b/terraform/projects/home-unite-us/lambda/prod/customMessage.zip new file mode 100644 index 0000000..ccc6e71 Binary files /dev/null and b/terraform/projects/home-unite-us/lambda/prod/customMessage.zip differ diff --git a/terraform/projects/home-unite-us/lambda/prod/merge_users.zip b/terraform/projects/home-unite-us/lambda/prod/merge_users.zip new file mode 100644 index 0000000..b8490d7 Binary files /dev/null and b/terraform/projects/home-unite-us/lambda/prod/merge_users.zip differ