Skip to content

Improve alerts, email branding, and add password.javazone.no#67

Merged
Alexanderamiri merged 2 commits into
mainfrom
fix/alert-improvements-and-email
Mar 16, 2026
Merged

Improve alerts, email branding, and add password.javazone.no#67
Alexanderamiri merged 2 commits into
mainfrom
fix/alert-improvements-and-email

Conversation

@Alexanderamiri
Copy link
Copy Markdown
Member

Summary

  • Filter service-linked role noise — Suppress AWSServiceRoleFor* events (ECS ENI provisioning) in slack-alert
  • CI context in team provisioner — Slack notifications now show who triggered the sync (actor, repo, commit, run link)
  • Daily cost spike improvements — $1 minimum threshold to filter noise, usage type + tag breakdown per spiking service, Cost Explorer links
  • Weekly cost report tables — Replace bullet-list mrkdwn with Block Kit tables (Service | Amount | % | WoW delta)
  • Email branding — Subject "Velkommen til JavaBin", footer "Javabrukerforeningen i Norge", salmon #f05350 colors
  • CID-embedded logo — Logo PNG in repo, loaded from Lambda zip at cold start, falls back to external URL
  • password.javazone.no — ALB listener rule + Route53 record routes to password-set Lambda; handler supports both ALB and Function URL events

Test plan

  • terraform plan — verify new resources (ALB target group, listener rule, Route53 record, SSM param update)
  • Trigger a test team provisioner sync and verify Slack shows CI context
  • Verify daily cost check filters small spikes (< $1) and shows usage type detail for real spikes
  • Verify weekly cost report renders Block Kit tables correctly
  • Confirm ECS ENI create/delete events no longer appear in #javabin-infra-alerts
  • Test password.javazone.no resolves and serves the password-set form
  • Verify welcome email renders with salmon branding and embedded logo (no Outlook trust prompt)

Alert improvements:
- Filter service-linked role events (ECS ENI provisioning noise)
- Add CI context (actor/repo/sha/run) to team provisioner Slack notifications
- Daily cost spikes: add $1 min threshold, usage type + tag breakdown, CE links
- Weekly cost report: replace bullet lists with Block Kit tables

Email and password-set:
- Subject/body: "Velkommen til JavaBin", footer: "Javabrukerforeningen i Norge"
- Brand colors: navy #1a1a2e → salmon #f05350 across email + password-set pages
- CID-embed logo PNG to avoid Outlook "trust this email" prompt
- Route password.javazone.no via ALB to password-set Lambda
- Handler supports both ALB and Function URL event formats
Store the javaBin white logo as a PNG in the repo (auditable, viewable).
Terraform uses filebase64() to include it in the Lambda zip as a .b64
text file. Python decodes at cold start with graceful fallback to
external URL if the file can't be loaded.
@github-actions
Copy link
Copy Markdown

Terraform Plan

Changes detected — review required.

Plan output
Acquiring state lock. This may take a few moments...
module.lambdas.data.archive_file.apply_gate: Reading...
module.lambdas.data.archive_file.override_cleanup: Reading...
module.lambdas.data.archive_file.daily_cost_check: Reading...
module.lambdas.data.archive_file.slack_alert: Reading...
module.lambdas.data.archive_file.apply_gate: Read complete after 0s [id=064e560a455ec8b2a30253cd815a820ad002376f]
module.lambdas.data.archive_file.password_set: Reading...
module.lambdas.data.archive_file.compliance_reporter: Reading...
module.lambdas.data.archive_file.override_cleanup: Read complete after 0s [id=08e23a8ca152c50d8321f7b9f15d3ebbdc97849d]
module.lambdas.data.archive_file.daily_cost_check: Read complete after 0s [id=a9f7a33c777fa36100ee8d2cd7653560fede7147]
module.lambdas.data.archive_file.compliance_reporter: Read complete after 0s [id=323449bf04f46a46a9d9c440212010f551146129]
module.lambdas.data.archive_file.team_provisioner: Reading...
module.lambdas.data.archive_file.cost_report: Reading...
module.lambdas.data.archive_file.password_set: Read complete after 0s [id=f04ea69c83442aa220bcd7101d68bb337fa1bcaf]
module.lambdas.data.archive_file.slack_alert: Read complete after 0s [id=4799ed7742244901fc87916fcd2bd8c47cdbd2ff]
module.lambdas.data.archive_file.cost_report: Read complete after 0s [id=2fa40a07c643b7425e8e686432d0060298822c11]
module.lambdas.data.archive_file.team_provisioner: Read complete after 0s [id=bff8f0ea5ef890c23bcc7bc9c1760755d666c841]
module.lambdas.aws_cloudwatch_event_rule.daily_cost_check_schedule: Refreshing state... [id=javabin-daily-cost-check-schedule]
module.lambdas.aws_iam_role.apply_gate: Refreshing state... [id=javabin-apply-gate]
module.lambdas.aws_cloudwatch_event_rule.compliance_reporter_trigger: Refreshing state... [id=javabin-compliance-reporter-trigger]
module.monitoring.aws_cloudwatch_event_rule.iam_changes: Refreshing state... [id=javabin-iam-changes]
module.lambdas.aws_iam_role.password_set: Refreshing state... [id=javabin-password-set]
module.monitoring.aws_cloudwatch_event_rule.config_compliance: Refreshing state... [id=javabin-config-compliance-change]
module.lambdas.aws_cloudwatch_event_rule.override_cleanup_schedule: Refreshing state... [id=javabin-override-cleanup-schedule]
module.lambdas.aws_iam_role.cost_report: Refreshing state... [id=javabin-cost-report]
module.lambdas.aws_cloudwatch_event_rule.securityhub_summary_schedule: Refreshing state... [id=javabin-securityhub-summary-schedule]
module.lambdas.aws_iam_role.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check]
module.lambdas.aws_iam_role.override_cleanup: Refreshing state... [id=javabin-override-cleanup]
module.iam.aws_iam_role.ecs_execution: Refreshing state... [id=javabin-ecs-execution]
module.monitoring.aws_cloudwatch_event_rule.securityhub_findings: Refreshing state... [id=javabin-securityhub-findings]
module.monitoring.aws_dynamodb_table.alert_dedup: Refreshing state... [id=javabin-alert-dedup]
module.iam.data.aws_iam_openid_connect_provider.github: Reading...
module.lambdas.aws_iam_role.slack_alert: Refreshing state... [id=javabin-slack-alert]
module.identity.aws_cognito_user_pool.external: Refreshing state... [id=eu-central-1_gdFOsE4EM]
module.lambdas.aws_cloudwatch_event_rule.cost_report_schedule: Refreshing state... [id=javabin-cost-report-schedule]
module.identity.aws_cognito_user_pool.internal: Refreshing state... [id=eu-central-1_Icikv3dtD]
module.monitoring.aws_s3_bucket.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.monitoring.aws_sns_topic.alerts: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-alerts]
module.monitoring.aws_sns_topic.security: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-security]
module.lambdas.aws_iam_role.team_provisioner: Refreshing state... [id=javabin-team-provisioner]
module.iam.data.aws_iam_openid_connect_provider.github: Read complete after 0s [id=arn:aws:iam::553637109631:oidc-provider/token.actions.githubusercontent.com]
module.monitoring.aws_cloudwatch_event_rule.resource_creation: Refreshing state... [id=javabin-resource-creation]
module.iam.aws_iam_policy.developer_boundary: Refreshing state... [id=arn:aws:iam::553637109631:policy/javabin-developer-boundary]
module.ingress.data.aws_route53_zone.main: Reading...
module.compute.aws_ecs_cluster.main: Refreshing state... [id=arn:aws:ecs:eu-central-1:553637109631:cluster/javabin-platform]
module.lambdas.aws_ssm_parameter.password_set_function_url: Refreshing state... [id=/javabin/platform/password-set-function-url]
module.monitoring.aws_guardduty_detector.main: Refreshing state... [id=f1df02cf279e4b5986ce1e9bcb3af9c5]
module.networking.aws_eip.nat: Refreshing state... [id=eipalloc-0764f0a1a3c80dce1]
module.networking.data.aws_availability_zones.available: Reading...
module.ingress.data.aws_route53_zone.main: Read complete after 0s [id=Z09335963LMV0Z5QB9L45]
module.monitoring.aws_ce_anomaly_monitor.main: Refreshing state... [id=arn:aws:ce::553637109631:anomalymonitor/3609b3f1-c834-444e-a218-02ac6da1cb4d]
module.monitoring.aws_cloudwatch_event_rule.guardduty_findings: Refreshing state... [id=javabin-guardduty-findings]
module.compute.aws_ecr_repository.ci["jvm"]: Refreshing state... [id=javabin-ci-jvm]
module.compute.aws_ecr_repository.ci["platform"]: Refreshing state... [id=javabin-ci-platform]
module.compute.aws_ecr_repository.ci["ts"]: Refreshing state... [id=javabin-ci-ts]
module.ingress.aws_acm_certificate.wildcard: Refreshing state... [id=arn:aws:acm:eu-central-1:553637109631:certificate/9b79f56a-3719-4c62-8970-6f08985a7e5b]
module.monitoring.aws_cloudwatch_event_rule.console_login: Refreshing state... [id=javabin-console-login]
module.monitoring.aws_securityhub_account.main: Refreshing state... [id=553637109631]
module.networking.aws_vpc.main: Refreshing state... [id=vpc-0cd3502de2527a310]
module.networking.data.aws_availability_zones.available: Read complete after 1s [id=eu-central-1]
module.lambdas.aws_iam_role.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter]
module.monitoring.aws_iam_role.config_role: Refreshing state... [id=javabin-config-role]
module.monitoring.aws_cloudwatch_event_rule.resource_modification: Refreshing state... [id=javabin-resource-modification]
module.lambdas.aws_iam_role_policy_attachment.cost_report_logs: Refreshing state... [id=javabin-cost-report-20260307162857662100000006]
module.lambdas.aws_lambda_function.cost_report: Refreshing state... [id=javabin-cost-report]
module.lambdas.aws_iam_role_policy.cost_report: Refreshing state... [id=javabin-cost-report:javabin-cost-report]
module.lambdas.aws_iam_role_policy_attachment.apply_gate_logs: Refreshing state... [id=javabin-apply-gate-20260310000556680800000001]
module.lambdas.aws_iam_role_policy.apply_gate: Refreshing state... [id=javabin-apply-gate:javabin-apply-gate]
module.lambdas.aws_lambda_function.apply_gate: Refreshing state... [id=javabin-apply-gate]
module.lambdas.aws_iam_role_policy_attachment.password_set_logs: Refreshing state... [id=javabin-password-set-20260313225356475100000001]
module.lambdas.aws_iam_role_policy_attachment.daily_cost_check_logs: Refreshing state... [id=javabin-daily-cost-check-20260307162856210400000002]
module.lambdas.aws_lambda_function.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check]
module.lambdas.aws_iam_role_policy.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check:javabin-daily-cost-check]
module.lambdas.aws_iam_role_policy.override_cleanup: Refreshing state... [id=javabin-override-cleanup:javabin-override-cleanup]
module.lambdas.aws_lambda_function.override_cleanup: Refreshing state... [id=javabin-override-cleanup]
module.lambdas.aws_iam_role_policy_attachment.override_cleanup_logs: Refreshing state... [id=javabin-override-cleanup-20260307162858005200000007]
module.iam.aws_iam_role_policy_attachment.ecs_execution_base: Refreshing state... [id=javabin-ecs-execution-20260307162856804400000004]
module.iam.aws_iam_role_policy.ecs_execution_secrets: Refreshing state... [id=javabin-ecs-execution:secrets-read]
module.lambdas.aws_iam_role_policy_attachment.slack_alert_logs: Refreshing state... [id=javabin-slack-alert-20260307162858376500000008]
module.lambdas.aws_iam_role_policy_attachment.team_provisioner_logs: Refreshing state... [id=javabin-team-provisioner-20260307162856464600000003]
module.iam.aws_iam_role.ci_registry: Refreshing state... [id=javabin-ci-registry]
module.iam.aws_iam_role.ci_apply_gate: Refreshing state... [id=javabin-ci-apply-gate]
module.iam.aws_iam_role.ci_deploy["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app]
module.iam.aws_iam_role.ci_infra: Refreshing state... [id=javabin-ci-infra]
module.iam.aws_iam_role.ci_override_approver: Refreshing state... [id=javabin-ci-override-approver]
module.iam.aws_iam_role.ci_infra_plan: Refreshing state... [id=javabin-ci-infra-plan]
module.monitoring.aws_cloudwatch_event_target.securityhub_findings_sns: Refreshing state... [id=javabin-securityhub-findings-send-to-security-sns]
module.monitoring.aws_cloudwatch_event_target.resource_creation_sns: Refreshing state... [id=javabin-resource-creation-send-to-security-sns]
module.monitoring.aws_sns_topic_policy.security: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-security]
module.monitoring.aws_cloudwatch_event_target.config_compliance_sns: Refreshing state... [id=javabin-config-compliance-change-send-to-security-sns]
module.monitoring.aws_cloudwatch_event_target.iam_changes_sns: Refreshing state... [id=javabin-iam-changes-send-to-security-sns]
module.monitoring.aws_sns_topic_policy.alerts: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-alerts]
module.compute.aws_ecs_cluster_capacity_providers.main: Refreshing state... [id=javabin-platform]
module.monitoring.aws_guardduty_detector_feature.runtime_monitoring: Refreshing state... [id=f1df02cf279e4b5986ce1e9bcb3af9c5/RUNTIME_MONITORING]
module.monitoring.aws_cloudwatch_event_target.guardduty_findings_sns: Refreshing state... [id=javabin-guardduty-findings-send-to-security-sns]
module.identity.aws_cognito_user_pool_domain.internal: Refreshing state... [id=javabin-internal]
module.monitoring.aws_ce_anomaly_subscription.alerts: Refreshing state... [id=arn:aws:ce::553637109631:anomalysubscription/f6b079c9-5174-43b7-85f3-dde533995482]
module.monitoring.aws_cloudwatch_event_target.console_login_sns: Refreshing state... [id=javabin-console-login-send-to-security-sns]
module.monitoring.aws_iam_role_policy_attachment.config_role: Refreshing state... [id=javabin-config-role-20260307162900971300000009]
module.monitoring.aws_config_configuration_recorder.main: Refreshing state... [id=javabin-recorder]
module.lambdas.aws_iam_role_policy.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter:javabin-compliance-reporter]
module.lambdas.aws_lambda_function.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter]
module.lambdas.aws_iam_role_policy_attachment.compliance_reporter_logs: Refreshing state... [id=javabin-compliance-reporter-20260307162857302300000005]
module.ingress.aws_route53_record.acm_validation["*.javazone.no"]: Refreshing state... [id=Z09335963LMV0Z5QB9L45__b68529ef50ff68d6cf320ff0e9c5c80a.javazone.no._CNAME]
module.monitoring.aws_cloudwatch_event_target.resource_modification_sns: Refreshing state... [id=javabin-resource-modification-send-to-security-sns]
module.compute.aws_ecr_lifecycle_policy.ci["ts"]: Refreshing state... [id=javabin-ci-ts]
module.compute.aws_ecr_lifecycle_policy.ci["jvm"]: Refreshing state... [id=javabin-ci-jvm]
module.compute.aws_ecr_lifecycle_policy.ci["platform"]: Refreshing state... [id=javabin-ci-platform]
module.monitoring.aws_securityhub_standards_subscription.aws_foundational: Refreshing state... [id=arn:aws:securityhub:eu-central-1:553637109631:subscription/aws-foundational-security-best-practices/v/1.0.0]
module.iam.aws_iam_role_policy.ci_registry: Refreshing state... [id=javabin-ci-registry:registry-operations]
module.iam.aws_iam_role_policy.ci_apply_gate: Refreshing state... [id=javabin-ci-apply-gate:invoke-gate-and-read-plans]
module.iam.aws_iam_role_policy.ci_infra_deny: Refreshing state... [id=javabin-ci-infra:deny-dangerous-operations]
module.iam.aws_iam_role_policy.ci_infra_allow: Refreshing state... [id=javabin-ci-infra:infra-management]
module.monitoring.aws_s3_bucket_policy.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.monitoring.aws_s3_bucket_server_side_encryption_configuration.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.monitoring.aws_s3_bucket_public_access_block.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.lambdas.aws_lambda_permission.override_cleanup_schedule: Refreshing state... [id=AllowEventBridge]
module.lambdas.aws_cloudwatch_event_target.override_cleanup: Refreshing state... [id=javabin-override-cleanup-schedule-invoke-override-cleanup]
module.lambdas.aws_cloudwatch_event_target.cost_report: Refreshing state... [id=javabin-cost-report-schedule-invoke-cost-report]
module.lambdas.aws_lambda_permission.cost_report_schedule: Refreshing state... [id=AllowEventBridge]
module.iam.aws_iam_role_policy.ci_deploy_ecr["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:ecr-push]
module.iam.aws_iam_role_policy.ci_deploy_ecs["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:ecs-deploy]
module.iam.aws_iam_role_policy.ci_deploy_ssm["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:ssm-read-overrides]
module.iam.aws_iam_role_policy.ci_deploy_logs["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:cloudwatch-logs]
module.lambdas.aws_cloudwatch_event_target.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check-schedule-invoke-daily-cost-check]
module.lambdas.aws_lambda_permission.daily_cost_check_schedule: Refreshing state... [id=AllowEventBridge]
module.iam.aws_iam_role_policy.ci_override_approver: Refreshing state... [id=javabin-ci-override-approver:invoke-apply-gate]
module.iam.aws_iam_role_policy.ci_infra_plan_extras: Refreshing state... [id=javabin-ci-infra-plan:plan-specific-writes]
module.iam.aws_iam_role_policy_attachment.ci_infra_plan_readonly: Refreshing state... [id=javabin-ci-infra-plan-20260312151931668600000001]
module.networking.aws_subnet.private_a: Refreshing state... [id=subnet-0329ad20dc025c693]
module.iam.aws_iam_role.ci_app["platform-test-app"]: Refreshing state... [id=javabin-ci-app-platform-test-app]
module.networking.aws_security_group.alb: Refreshing state... [id=sg-061000c0fa68a41b7]
module.networking.aws_security_group.ecs_tasks: Refreshing state... [id=sg-0df9a0a3a22548c62]
module.networking.aws_internet_gateway.main: Refreshing state... [id=igw-07b193bea823a7f69]
module.networking.aws_subnet.public_b: Refreshing state... [id=subnet-0eb818326ee94a266]
module.networking.aws_subnet.public_a: Refreshing state... [id=subnet-0f6bfec917146b856]
module.networking.aws_subnet.private_b: Refreshing state... [id=subnet-09ee21336f809f3c9]
module.ingress.aws_acm_certificate_validation.wildcard: Refreshing state... [id=2026-03-07 16:29:14.551 +0000 UTC]
module.lambdas.aws_iam_role_policy.slack_alert: Refreshing state... [id=javabin-slack-alert:javabin-slack-alert]
module.lambdas.aws_lambda_function.securityhub_summary: Refreshing state... [id=javabin-securityhub-summary]
module.lambdas.aws_lambda_function.slack_alert: Refreshing state... [id=javabin-slack-alert]
module.lambdas.aws_iam_role_policy.team_provisioner: Refreshing state... [id=javabin-team-provisioner:javabin-team-provisioner]
module.lambdas.aws_lambda_function.team_provisioner: Refreshing state... [id=javabin-team-provisioner]
module.monitoring.aws_config_delivery_channel.main: Refreshing state... [id=javabin-config-channel]
module.monitoring.aws_config_config_rule.required_tags: Refreshing state... [id=javabin-required-tags]
module.lambdas.aws_lambda_permission.compliance_reporter_eventbridge: Refreshing state... [id=AllowEventBridge]
module.lambdas.aws_cloudwatch_event_target.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter-trigger-invoke-compliance-reporter]
module.networking.aws_vpc_security_group_ingress_rule.alb_http: Refreshing state... [id=sgr-07c58f16ef7496031]
module.networking.aws_vpc_security_group_ingress_rule.alb_https: Refreshing state... [id=sgr-00b490b07c35193b7]
module.networking.aws_vpc_security_group_egress_rule.alb_all: Refreshing state... [id=sgr-021faee81305c6e28]
module.networking.aws_vpc_security_group_egress_rule.ecs_all: Refreshing state... [id=sgr-0266cfa56e8feab14]
module.networking.aws_vpc_security_group_ingress_rule.ecs_from_alb: Refreshing state... [id=sgr-064d01025000f601e]
module.iam.aws_iam_role_policy.ci_app_deny["platform-test-app"]: Refreshing state... [id=javabin-ci-app-platform-test-app:deny-platform-operations]
module.iam.aws_iam_role_policy.ci_app_allow["platform-test-app"]: Refreshing state... [id=javabin-ci-app-platform-test-app:app-management]
module.networking.aws_route_table.public: Refreshing state... [id=rtb-01c9642f019d36b1f]
module.monitoring.aws_config_configuration_recorder_status.main: Refreshing state... [id=javabin-recorder]
module.networking.aws_nat_gateway.main: Refreshing state... [id=nat-0e9cc9e27cc6598db]
module.ingress.aws_lb.main: Refreshing state... [id=arn:aws:elasticloadbalancing:eu-central-1:553637109631:loadbalancer/app/javabin-platform-alb/bec1dd43ab8341b9]
module.lambdas.aws_lambda_permission.slack_alert_security: Refreshing state... [id=AllowSNSSecurity]
module.lambdas.aws_sns_topic_subscription.slack_alert_alerts: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-alerts:380384a2-0cac-48c9-b2d9-2a0aae6968cd]
module.lambdas.aws_sns_topic_subscription.slack_alert_security: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-security:0bda8a22-7a50-4a9d-9285-6b1fc1f75376]
module.lambdas.aws_lambda_permission.slack_alert_alerts: Refreshing state... [id=AllowSNSAlerts]
module.lambdas.aws_lambda_permission.securityhub_summary_schedule: Refreshing state... [id=AllowEventBridge]
module.lambdas.aws_cloudwatch_event_target.securityhub_summary: Refreshing state... [id=javabin-securityhub-summary-schedule-invoke-securityhub-summary]
module.lambdas.aws_iam_role_policy.password_set: Refreshing state... [id=javabin-password-set:javabin-password-set]
module.networking.aws_route_table_association.public_b: Refreshing state... [id=rtbassoc-0186c3a7f0279e344]
module.lambdas.aws_lambda_function.password_set: Refreshing state... [id=javabin-password-set]
module.networking.aws_route_table_association.public_a: Refreshing state... [id=rtbassoc-07ff2e0bfa1578067]
module.networking.aws_route_table.private: Refreshing state... [id=rtb-0b0b4c643592a7db0]
module.networking.aws_route_table_association.private_b: Refreshing state... [id=rtbassoc-005259f36758e089e]
module.networking.aws_route_table_association.private_a: Refreshing state... [id=rtbassoc-0b9248495de9f7316]
module.lambdas.aws_lambda_permission.password_set_public_invoke: Refreshing state... [id=AllowPublicInvoke]
module.lambdas.aws_lambda_function_url.password_set: Refreshing state... [id=javabin-password-set]
module.lambdas.aws_lambda_permission.password_set_public_url: Refreshing state... [id=FunctionURLAllowPublicAccess]
module.ingress.aws_lb_listener.https: Refreshing state... [id=arn:aws:elasticloadbalancing:eu-central-1:553637109631:listener/app/javabin-platform-alb/bec1dd43ab8341b9/500c9c2b4186bf45]
module.ingress.aws_lb_listener.http_redirect: Refreshing state... [id=arn:aws:elasticloadbalancing:eu-central-1:553637109631:listener/app/javabin-platform-alb/bec1dd43ab8341b9/1d92e19ae75aa59b]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # module.lambdas.aws_lambda_function.cost_report will be updated in-place
  ~ resource "aws_lambda_function" "cost_report" {
        id                             = "javabin-cost-report"
      ~ last_modified                  = "2026-03-07T18:03:35.000+0000" -> (known after apply)
      ~ source_code_hash               = "CvYi/IsV546lVu/14urQfiyZaejqtcyCj7uLX1CbxOc=" -> "tqOEmNCrENsRH68jr/pMXLCtzlzQDVeaRdyLn9y/TKo="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.daily_cost_check will be updated in-place
  ~ resource "aws_lambda_function" "daily_cost_check" {
        id                             = "javabin-daily-cost-check"
      ~ last_modified                  = "2026-03-07T18:02:15.000+0000" -> (known after apply)
      ~ source_code_hash               = "MHpfhvdKnSmjBrIfFHqwX4rMQiWjgzQdzdOFLhSCd+M=" -> "O1jtWocVLFewhv1wjT0tNRZbrReVg5HX2D6pjgkSu+M="
        tags                           = {}
      ~ timeout                        = 30 -> 60
        # (20 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.password_set will be updated in-place
  ~ resource "aws_lambda_function" "password_set" {
        id                             = "javabin-password-set"
      ~ last_modified                  = "2026-03-13T22:54:05.503+0000" -> (known after apply)
      ~ source_code_hash               = "2/h0Ae5IHdTiObH7e8ZKRfT9tc8W/v9Z9cqwRpCwiDg=" -> "cnfbZclmmOihxEavJ9qzl0sWNVkMkSrS38/J9xrY64M="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.securityhub_summary will be updated in-place
  ~ resource "aws_lambda_function" "securityhub_summary" {
        id                             = "javabin-securityhub-summary"
      ~ last_modified                  = "2026-03-13T22:49:57.000+0000" -> (known after apply)
      ~ source_code_hash               = "/3Qlrg5ZCVstsvJW7QbgW9pNt7TSCx6MOExvmF0sO7c=" -> "RTfy+TJq/1kcGZP7T5Sj9Ri9YYvO4gxnO4iK4neALxo="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.slack_alert will be updated in-place
  ~ resource "aws_lambda_function" "slack_alert" {
        id                             = "javabin-slack-alert"
      ~ last_modified                  = "2026-03-13T22:50:03.000+0000" -> (known after apply)
      ~ source_code_hash               = "/3Qlrg5ZCVstsvJW7QbgW9pNt7TSCx6MOExvmF0sO7c=" -> "RTfy+TJq/1kcGZP7T5Sj9Ri9YYvO4gxnO4iK4neALxo="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.team_provisioner will be updated in-place
  ~ resource "aws_lambda_function" "team_provisioner" {
        id                             = "javabin-team-provisioner"
      ~ last_modified                  = "2026-03-13T22:50:09.000+0000" -> (known after apply)
      ~ source_code_hash               = "q2zva9DACViSGKK69pRpZ5zR0CZ8CYepVXN3L8hkzNA=" -> "tfwZJi3BEYFmZVlD3jH52COLMJfFRHrNkRhYYGGgiUA="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_permission.password_set_alb will be created
  + resource "aws_lambda_permission" "password_set_alb" {
      + action              = "lambda:InvokeFunction"
      + function_name       = "javabin-password-set"
      + id                  = (known after apply)
      + principal           = "elasticloadbalancing.amazonaws.com"
      + source_arn          = (known after apply)
      + statement_id        = "AllowALBInvoke"
      + statement_id_prefix = (known after apply)
    }

  # module.lambdas.aws_lb_listener_rule.password_set will be created
  + resource "aws_lb_listener_rule" "password_set" {
      + arn          = (known after apply)
      + id           = (known after apply)
      + listener_arn = "arn:aws:elasticloadbalancing:eu-central-1:553637109631:listener/app/javabin-platform-alb/bec1dd43ab8341b9/500c9c2b4186bf45"
      + priority     = 10
      + tags_all     = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "project"     = "javabin"
          + "team"        = "javabin"
        }

      + action {
          + order            = (known after apply)
          + target_group_arn = (known after apply)
          + type             = "forward"
        }

      + condition {
          + host_header {
              + values = [
                  + "password.javazone.no",
                ]
            }
        }
    }

  # module.lambdas.aws_lb_target_group.password_set will be created
  + resource "aws_lb_target_group" "password_set" {
      + arn                                = (known after apply)
      + arn_suffix                         = (known after apply)
      + connection_termination             = (known after apply)
      + deregistration_delay               = "300"
      + id                                 = (known after apply)
      + ip_address_type                    = (known after apply)
      + lambda_multi_value_headers_enabled = false
      + load_balancer_arns                 = (known after apply)
      + load_balancing_algorithm_type      = (known after apply)
      + load_balancing_anomaly_mitigation  = (known after apply)
      + load_balancing_cross_zone_enabled  = (known after apply)
      + name                               = "javabin-password-set"
      + name_prefix                        = (known after apply)
      + preserve_client_ip                 = (known after apply)
      + protocol_version                   = (known after apply)
      + proxy_protocol_v2                  = false
      + slow_start                         = 0
      + tags_all                           = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "project"     = "javabin"
          + "team"        = "javabin"
        }
      + target_type                        = "lambda"

      + health_check {
          + enabled             = false
          + healthy_threshold   = 3
          + interval            = 30
          + matcher             = (known after apply)
          + path                = (known after apply)
          + port                = "traffic-port"
          + protocol            = "HTTP"
          + timeout             = (known after apply)
          + unhealthy_threshold = 3
        }
    }

  # module.lambdas.aws_lb_target_group_attachment.password_set will be created
  + resource "aws_lb_target_group_attachment" "password_set" {
      + id               = (known after apply)
      + target_group_arn = (known after apply)
      + target_id        = "arn:aws:lambda:eu-central-1:553637109631:function:javabin-password-set"
    }

  # module.lambdas.aws_route53_record.password_set will be created
  + resource "aws_route53_record" "password_set" {
      + allow_overwrite = (known after apply)
      + fqdn            = (known after apply)
      + id              = (known after apply)
      + name            = "password.javazone.no"
      + type            = "A"
      + zone_id         = "Z09335963LMV0Z5QB9L45"

      + alias {
          + evaluate_target_health = true
          + name                   = "javabin-platform-alb-375406315.eu-central-1.elb.amazonaws.com"
          + zone_id                = "Z215JYRZR1TBD5"
        }
    }

  # module.lambdas.aws_ssm_parameter.password_set_function_url will be updated in-place
  ~ resource "aws_ssm_parameter" "password_set_function_url" {
        id             = "/javabin/platform/password-set-function-url"
      + insecure_value = (known after apply)
        name           = "/javabin/platform/password-set-function-url"
        tags           = {}
      ~ value          = (sensitive value)
      ~ version        = 2 -> (known after apply)
        # (5 unchanged attributes hidden)
    }

Plan: 5 to add, 7 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

@github-actions
Copy link
Copy Markdown

LLM Plan Review

Risk: 🟢 LOW

Routine Lambda function updates with code changes and timeout adjustment, plus new ALB integration for password-set Lambda function.

  • [routine] Lambda function code updates: cost_report, daily_cost_check, password_set, securityhub_summary, slack_alert, and team_provisioner all have source_code_hash changes indicating code deployments.
  • [routine] daily_cost_check Lambda timeout increased from 30 to 60 seconds, likely to accommodate longer execution times.
  • [routine] New ALB integration for password-set Lambda: creating target group, listener rule, and Route53 DNS record (password.javazone.no) to expose the function via HTTPS through the existing load balancer.
  • [routine] Lambda permission added for ALB to invoke password_set function, enabling the load balancer integration.
  • [routine] SSM parameter updated for password_set function URL, reflecting the new ALB-based access method.

@Alexanderamiri Alexanderamiri merged commit 486a56a into main Mar 16, 2026
3 checks passed
@Alexanderamiri Alexanderamiri deleted the fix/alert-improvements-and-email branch March 16, 2026 19:33
Alexanderamiri added a commit that referenced this pull request May 9, 2026
## Summary
- **Filter service-linked role noise** — Suppress `AWSServiceRoleFor*`
events (ECS ENI provisioning) in slack-alert
- **CI context in team provisioner** — Slack notifications now show who
triggered the sync (actor, repo, commit, run link)
- **Daily cost spike improvements** — $1 minimum threshold to filter
noise, usage type + tag breakdown per spiking service, Cost Explorer
links
- **Weekly cost report tables** — Replace bullet-list mrkdwn with Block
Kit tables (Service | Amount | % | WoW delta)
- **Email branding** — Subject "Velkommen til JavaBin", footer
"Javabrukerforeningen i Norge", salmon `#f05350` colors
- **CID-embedded logo** — Logo PNG in repo, loaded from Lambda zip at
cold start, falls back to external URL
- **password.javazone.no** — ALB listener rule + Route53 record routes
to password-set Lambda; handler supports both ALB and Function URL
events

## Test plan
- [ ] `terraform plan` — verify new resources (ALB target group,
listener rule, Route53 record, SSM param update)
- [ ] Trigger a test team provisioner sync and verify Slack shows CI
context
- [ ] Verify daily cost check filters small spikes (< $1) and shows
usage type detail for real spikes
- [ ] Verify weekly cost report renders Block Kit tables correctly
- [ ] Confirm ECS ENI create/delete events no longer appear in
#javabin-infra-alerts
- [ ] Test password.javazone.no resolves and serves the password-set
form
- [ ] Verify welcome email renders with salmon branding and embedded
logo (no Outlook trust prompt)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant