locals { project = "meal-order-manager" account_id = "011934824531" # Lambda execution roles under /tf-managed/ carry the per-workload ceiling # (PLAT-52). githubdeploy-meal-order-manager-weekly-menu must not. boundary_arn = "arn:aws:iam::${local.account_id}:policy/seahaven-lambda-execution-boundary-meal-order-manager" form_bucket_name = "${local.project}-form-${local.account_id}" reports_bucket_name = "${local.project}-reports-${local.account_id}" artifacts_bucket_name = "${local.project}-artifacts-${local.account_id}" table_name = "${local.project}-orders" # Pre-DNS: use the CloudFront domain. After cutover (attach_custom_domain), # use the public custom domain. form_url = var.attach_custom_domain ? "https://${var.domain_name}" : "https://${aws_cloudfront_distribution.form.domain_name}" ssm_prefix = "/${local.project}" slack_channel_param = "${local.ssm_prefix}/slack-channel-id" # google-client-id is created and rotated out-of-band. Terraform reads it # (data.tf) but never owns it. google_client_id_param = "${local.ssm_prefix}/google-client-id" portal_cognito_issuer_param = "${local.ssm_prefix}/portal-cognito-issuer" portal_cognito_audience_param = "${local.ssm_prefix}/portal-cognito-audience" # shared/slack.py resolves the token by NAME, while the IAM grant is scoped to # the ARN in var.slack_bot_secret_arn. Both must refer to the same secret. slack_bot_secret_name = "${local.project}/slack-bot-token" ssm_parameter_arn_wildcard = "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.ssm_prefix}/*" # Directory names under functions/, which build_packages.sh mirrors into # terraform/build/functions/. function_packages = toset([ "admin_authorizer", "aggregate_orders", "close_form", "slack_notifier", "submit_order", "sync_roster", ]) # SAM Globals.Function.Environment.Variables — every function receives these. common_env = { TABLE_NAME = local.table_name REPORTS_BUCKET = local.reports_bucket_name SLACK_CHANNEL_PARAM = local.slack_channel_param FORM_URL = local.form_url SLACK_BOT_SM_NAME = local.slack_bot_secret_name } # AWS managed CachingDisabled / AllViewerExceptHostHeader. Authenticated # portal calls must not be cached and must not send the viewer Host to the # HTTP API (Forbidden). api_cache_policy_id = "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" api_origin_request_policy_id = "b689b0a8-53d0-40ab-baf2-68738e2966ac" cloudfront_all_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] # HTTP API routes, all integrated with submit-order. `authorizer` selects the # authorization mode; `permission_source` is the method/path suffix of the # per-route lambda:InvokeFunction grant (path parameters become `*`). api_routes = { submit_order = { route_key = "POST /api/submit-order" authorizer = "NONE" permission_source = "POST/api/submit-order" } menu = { route_key = "GET /api/menu/{week}" authorizer = "NONE" permission_source = "GET/api/menu/*" } my_orders = { route_key = "GET /api/orders/{week}" authorizer = "NONE" permission_source = "GET/api/orders/*" } form_status = { route_key = "GET /api/form-status/{week}" authorizer = "NONE" permission_source = "GET/api/form-status/*" } roster = { route_key = "GET /api/roster" authorizer = "NONE" permission_source = "GET/api/roster" } publish_settings = { route_key = "GET /api/publish/settings" authorizer = "AWS_IAM" permission_source = "GET/api/publish/settings" } publish_menu = { route_key = "POST /api/publish/menu" authorizer = "AWS_IAM" permission_source = "POST/api/publish/menu" } admin_orders_get = { route_key = "GET /api/admin/orders" authorizer = "CUSTOM" permission_source = "GET/api/admin/orders" } admin_orders_put = { route_key = "PUT /api/admin/orders" authorizer = "CUSTOM" permission_source = "PUT/api/admin/orders" } admin_orders_delete = { route_key = "DELETE /api/admin/orders" authorizer = "CUSTOM" permission_source = "DELETE/api/admin/orders" } admin_summary_pdf = { route_key = "GET /api/admin/summary-pdf" authorizer = "CUSTOM" permission_source = "GET/api/admin/summary-pdf" } } }