From 39dc203993e1ff79a3c208e05c26bf57625fa5b4 Mon Sep 17 00:00:00 2001 From: Alex English Date: Sun, 27 Sep 2026 14:03:32 -0700 Subject: [PATCH 1/2] Import home-unite-us production Cognito Lambdas --- terraform/import.tf | 51 ++++++++ .../projects/home-unite-us/cognito-prod.tf | 109 ++++++++++++++++-- .../projects/home-unite-us/cognito-qa.tf | 22 +++- .../lambda/prod/customMessage.zip | Bin 0 -> 996 bytes .../home-unite-us/lambda/prod/merge_users.zip | Bin 0 -> 846 bytes 5 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 terraform/projects/home-unite-us/lambda/prod/customMessage.zip create mode 100644 terraform/projects/home-unite-us/lambda/prod/merge_users.zip 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/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 0000000000000000000000000000000000000000..ccc6e71bfec90dbe142d1e3cd7ac439225d12346 GIT binary patch literal 996 zcmWIWW@Zs#-~d7f2E{HQ0S5v=R&r@^Nq(+xYH@L5da7Pl@te@IMYqia_LVPtzaj9h zmE8;d%lj35%T4yFw3ir_UiI@cWYO_-dD6rxwkgEbxVCp+-25fXL0eS2v+f?5`BHI* zN6eeL2%T@Y*PEOYw>XfRs6yj zloO?0yep30x3Q9Y^Y+;H@D4-P+X6rbiK&Th$afpha! z~A+n;_h6sKL$ zYPfgvuvK_f;l}(`XMak_tmpEnTDoE8G7dLGhpdj@e*gOfZGP{HI<~hvoRzD6gTv~} zqHB7#D=aaYS5aVh=6LJ{Fa4-DGNsdsx!DfueSc*zF|Iv6!v1;FGeu61-qrvCU&$Y< z{)v>#mi*II|M%l^*8@wh^l;s9&=ZSjPdo7-BEs$KlHW5F)@$H zD_qvwB~xw zy#1HVT~ff@m-<_2?d|AH)|4G-?%urTwr1ZJUDbBcN;!Gs%~jc77ue$pPeG^l4X4-qbQQI_s%bMy{%R==3r8lgVaR@rURW`l*jjpL-^yg(iGmpMp zVfOXg)U-ujzSG56A75Gcwl-(y&Crew8>N3qFl`KN+qbMWZO=Q0zZOCtZ~X}Fz96%D z-k0RYas Bv;hDB literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b8490d782e3df004634d0bd0d142df6e74233d98 GIT binary patch literal 846 zcmWIWW@Zs#-~d7f2E{HQ0SA0QR&HuhdTM-WacWVqUP0xYP{-`YRs#FjKgqW}Q((Vz zVPCoSkAsW*!>b~>?%wt0aNBtN<(5rTraoEb{jxq@<><6GOLBJG-CUe+clOM8&t+-L zx3s!1eo|8OtjiIxe=L(A!IFlKG6y*XF#xc;oZ_8+Rs#L>v~& z-Btdq!i0CiB@{;`}jTOr>q-HQq9Lsp{^#(O1AGdQC-e-cGfBf*DRW5f8UD z$<#dRni|7#<+|eBwc%@;HyobwI43Enr&J@yqLbsokHxN!f69D|&o<4C>OSUbv(5WW z)!%cjuX*R?JiL|mdg)EhO_JI-Y)Yl1(>5LL$Xf7_=M=ln{5gJo5+@wihBEK*e|1+Y zAWd2A2fLo|(zFL>SYtR2h#O6Na&5EJjmfnfi#uLyD0<^7f4=S4{4GzCIyyK1S(SI; z*+t} z)?U%9dl-31%B}tCUG9TEMg?nUTt2_yD+dR=xXhL3q0XBGRObK6Ub$lGx3&{~#t)nK zy_om^g5{*>pi4`iu3w(`E^%eVyYM2}w3GK1%02mF_oZo*_WdM@#xKvmnH;}uedqhC ztEzR|9)-;F7qxx0V@JMuf5a{O*EK0`Pk)cH=i}#7IAY(hpQZnyV$-1qAMJ~$e9~rM z`2Rn^o1MdD4)2TuObiTBzyu%Q&B!Fej7a^+a-h@?14|k~EY!RZ;LXYg5@iHJ8zB7$ IXeI*#09^ix)c^nh literal 0 HcmV?d00001 From b0df9ad8fa5df916cce9fe0945238a2b8a732714 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 27 Sep 2026 21:04:41 +0000 Subject: [PATCH 2/2] terraform-docs: automated updates to Terraform modules README.md [skip ci] --- terraform/projects/home-unite-us/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) 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 |