Skip to content

feat(auth): ask Google for the account chooser at sign-in - #258

Merged
Alexanderamiri merged 4 commits into
mainfrom
feat/select-account
Oct 30, 2026
Merged

Alexanderamiri merged 4 commits into
mainfrom
feat/select-account

Conversation

@Alexanderamiri

@Alexanderamiri Alexanderamiri commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Why

Heroes whose browser is signed in to a personal Google account cannot switch to their @java.no account at sign-in (javaBin/platform#157). The platform now asks apps on the internal pool to send prompt=select_account (COGNITO_EXTRA_AUTH_PARAMS, javaBin/platform#170).

What

extraQueryParams: { prompt: "select_account" } on the oidc-client-ts UserManager, so it goes with every signinRedirect to Cognito's /oauth2/authorize.

How verified

  • pnpm lint and pnpm typecheck pass.
  • Live: Cognito's classic hosted UI answers /oauth2/authorize?...&prompt=select_account exactly as it does without the parameter (302 to the IdP), so this is safe to merge before the platform change.

Rollout

Safe to merge any time. It takes effect once the platform's internal pool domain is on managed login (javaBin/platform#171) and the pool signs in with the Google provider (javaBin/platform#172). Sign-in behaviour does not change before then.

🤖 Generated with Claude Code

Update: also send identity_provider

Probing the platform's managed login (javaBin/platform#174) showed that Cognito forwards prompt=select_account to Google only when the request also sets identity_provider. With prompt alone, Cognito still goes straight to the client's only IdP but drops the prompt.

Alexanderamiri and others added 2 commits October 29, 2026 22:49
Send prompt=select_account with the authorize redirect, so a browser signed
in to a personal Google account can switch to the @java.no account instead
of being refused. Cognito forwards it to Google once the internal pool's
domain is on managed login; until then it is ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Terraform Plan

🚧 Changes detected — Plan: 5 to add, 1 to change, 0 to destroy.

Plan output

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.network.aws_security_group.tasks will be created
  + resource "aws_security_group" "tasks" {
      + arn                    = (known after apply)
      + description            = "ECS tasks of cupcake-cupcake; peer rules are managed by javabin-app-peers-sync"
      + egress                 = (known after apply)
      + id                     = (known after apply)
      + ingress                = (known after apply)
      + name                   = "cupcake-cupcake-tasks"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = true
      + tags                   = {
          + "Name"            = "cupcake-cupcake-tasks"
          + "javabin-network" = "app"
        }
      + tags_all               = {
          + "Name"            = "cupcake-cupcake-tasks"
          + "environment"     = "production"
          + "javabin-network" = "app"
          + "managed-by"      = "terraform"
          + "repo"            = "javaBin/frosting"
          + "service"         = "cupcake"
          + "team"            = "cupcake"
        }
      + vpc_id                 = "vpc-0cd3502de2527a310"
    }

  # module.network.aws_service_discovery_service.this will be created
  + resource "aws_service_discovery_service" "this" {
      + arn           = (known after apply)
      + force_destroy = true
      + id            = (known after apply)
      + name          = "cupcake-cupcake"
      + namespace_id  = (known after apply)
      + tags_all      = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + type          = (known after apply)

      + dns_config {
          + namespace_id   = "ns-4qfb7mei2fit4q4b"
          + routing_policy = "MULTIVALUE"

          + dns_records {
              + ttl  = 10
              + type = "A"
            }
        }

      + health_check_custom_config {
          + failure_threshold = 1
        }
    }

  # module.network.aws_ssm_parameter.network will be created
  + resource "aws_ssm_parameter" "network" {
      + arn            = (known after apply)
      + data_type      = (known after apply)
      + description    = "App-to-app request for cupcake-cupcake — read by the platform app-peers-sync Lambda"
      + has_value_wo   = (known after apply)
      + id             = (known after apply)
      + insecure_value = (known after apply)
      + key_id         = (known after apply)
      + name           = "/javabin/apps/cupcake/cupcake/network"
      + tags_all       = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + tier           = (known after apply)
      + type           = "String"
      + value          = (sensitive value)
      + version        = (known after apply)
    }

  # module.network.aws_vpc_security_group_egress_rule.all will be created
  + resource "aws_vpc_security_group_egress_rule" "all" {
      + arn                    = (known after apply)
      + cidr_ipv4              = "0.0.0.0/0"
      + description            = "All outbound"
      + id                     = (known after apply)
      + ip_protocol            = "-1"
      + security_group_id      = (known after apply)
      + security_group_rule_id = (known after apply)
      + tags_all               = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
    }

  # module.network.aws_vpc_security_group_ingress_rule.alb[0] will be created
  + resource "aws_vpc_security_group_ingress_rule" "alb" {
      + arn                          = (known after apply)
      + description                  = "ALB to the app port"
      + from_port                    = 3000
      + id                           = (known after apply)
      + ip_protocol                  = "tcp"
      + referenced_security_group_id = "sg-061000c0fa68a41b7"
      + security_group_id            = (known after apply)
      + security_group_rule_id       = (known after apply)
      + tags_all                     = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + to_port                      = 3000
    }

  # module.service.aws_ecs_service.this will be updated in-place
  ~ resource "aws_ecs_service" "this" {
        id                                 = "arn:aws:ecs:eu-central-1:553637109631:service/javabin-platform/cupcake-cupcake"
        name                               = "cupcake-cupcake"
        tags                               = {}
        # (17 unchanged attributes hidden)

      ~ network_configuration {
          ~ security_groups  = [
              - "sg-0df9a0a3a22548c62",
            ] -> (known after apply)
            # (2 unchanged attributes hidden)
        }

      + service_registries {
          + registry_arn = (known after apply)
        }

        # (3 unchanged blocks hidden)
    }

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

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

Saved the plan to: tfplan

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

LLM Review

Risk: 🟡 MEDIUM

Creates 5 networking/discovery resources for the cupcake-cupcake app (security group, ingress/egress rules, Cloud Map service, SSM parameter) and updates the ECS service to replace its security group with a new one, with 0 destroys.

  • 🔒 [security] The ECS service's network_configuration drops security group sg-0df9a0a3a22548c62 and (after apply) will use the new cupcake-cupcake-tasks SG. Confirm the old SG is not referenced by other resources or peer rules, and that the new SG is the intended replacement, since the task's effective network access changes on apply.
  • 🔒 [security] New SG has an all-outbound rule (0.0.0.0/0, protocol -1) and one ingress rule allowing TCP 3000 only from the ALB security group sg-061000c0fa68a41b7. No internet-open ingress is added. Peer ingress rules are managed externally by javabin-app-peers-sync, so ingress from other apps will be added outside this plan.
  • 🔒 [security] SSM parameter /javabin/apps/cupcake/cupcake/network is a plain String whose value is sensitive; it is consumed by the platform app-peers-sync Lambda. Value is network routing info rather than a secret, but confirm it does not contain credentials.
  • 💰 [cost] No new billable resources of significant cost (no NAT gateway, RDS, or load balancer). Cloud Map service and SSM standard parameter have negligible cost.
  • ✅ [routine] Cloud Map service with force_destroy=true and A-record MULTIVALUE DNS config in namespace ns-4qfb7mei2fit4q4b; the ECS service gains a service_registries block pointing to it. Routine service-discovery wiring, no destruction.

Alexanderamiri and others added 2 commits October 30, 2026 09:43
Cognito managed login forwards prompt=select_account to Google only when the
authorize request also names the IdP (identity_provider); without it the
prompt is dropped. Read the IdP from the platform's COGNITO_IDENTITY_PROVIDER
(aliased to NUXT_PUBLIC_OIDC_IDENTITY_PROVIDER) and send it when set. It is
GoogleSAML today and becomes Google at the platform cutover, with no code
change. Empty locally, where the request behaves as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Terraform Plan

🚧 Changes detected — Plan: 6 to add, 1 to change, 1 to destroy.

Plan output

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

Terraform will perform the following actions:

  # module.network.aws_security_group.tasks will be created
  + resource "aws_security_group" "tasks" {
      + arn                    = (known after apply)
      + description            = "ECS tasks of cupcake-cupcake; peer rules are managed by javabin-app-peers-sync"
      + egress                 = (known after apply)
      + id                     = (known after apply)
      + ingress                = (known after apply)
      + name                   = "cupcake-cupcake-tasks"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = true
      + tags                   = {
          + "Name"            = "cupcake-cupcake-tasks"
          + "javabin-network" = "app"
        }
      + tags_all               = {
          + "Name"            = "cupcake-cupcake-tasks"
          + "environment"     = "production"
          + "javabin-network" = "app"
          + "managed-by"      = "terraform"
          + "repo"            = "javaBin/frosting"
          + "service"         = "cupcake"
          + "team"            = "cupcake"
        }
      + vpc_id                 = "vpc-0cd3502de2527a310"
    }

  # module.network.aws_service_discovery_service.this will be created
  + resource "aws_service_discovery_service" "this" {
      + arn           = (known after apply)
      + force_destroy = true
      + id            = (known after apply)
      + name          = "cupcake-cupcake"
      + namespace_id  = (known after apply)
      + tags_all      = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + type          = (known after apply)

      + dns_config {
          + namespace_id   = "ns-4qfb7mei2fit4q4b"
          + routing_policy = "MULTIVALUE"

          + dns_records {
              + ttl  = 10
              + type = "A"
            }
        }

      + health_check_custom_config {
          + failure_threshold = 1
        }
    }

  # module.network.aws_ssm_parameter.network will be created
  + resource "aws_ssm_parameter" "network" {
      + arn            = (known after apply)
      + data_type      = (known after apply)
      + description    = "App-to-app request for cupcake-cupcake — read by the platform app-peers-sync Lambda"
      + has_value_wo   = (known after apply)
      + id             = (known after apply)
      + insecure_value = (known after apply)
      + key_id         = (known after apply)
      + name           = "/javabin/apps/cupcake/cupcake/network"
      + tags_all       = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + tier           = (known after apply)
      + type           = "String"
      + value          = (sensitive value)
      + version        = (known after apply)
    }

  # module.network.aws_vpc_security_group_egress_rule.all will be created
  + resource "aws_vpc_security_group_egress_rule" "all" {
      + arn                    = (known after apply)
      + cidr_ipv4              = "0.0.0.0/0"
      + description            = "All outbound"
      + id                     = (known after apply)
      + ip_protocol            = "-1"
      + security_group_id      = (known after apply)
      + security_group_rule_id = (known after apply)
      + tags_all               = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
    }

  # module.network.aws_vpc_security_group_ingress_rule.alb[0] will be created
  + resource "aws_vpc_security_group_ingress_rule" "alb" {
      + arn                          = (known after apply)
      + description                  = "ALB to the app port"
      + from_port                    = 3000
      + id                           = (known after apply)
      + ip_protocol                  = "tcp"
      + referenced_security_group_id = "sg-061000c0fa68a41b7"
      + security_group_id            = (known after apply)
      + security_group_rule_id       = (known after apply)
      + tags_all                     = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + to_port                      = 3000
    }

  # module.service.aws_ecs_service.this will be updated in-place
  ~ resource "aws_ecs_service" "this" {
        id                                 = "arn:aws:ecs:eu-central-1:553637109631:service/javabin-platform/cupcake-cupcake"
        name                               = "cupcake-cupcake"
        tags                               = {}
      ~ task_definition                    = "arn:aws:ecs:eu-central-1:553637109631:task-definition/cupcake-cupcake:3" -> (known after apply)
        # (16 unchanged attributes hidden)

      ~ network_configuration {
          ~ security_groups  = [
              - "sg-0df9a0a3a22548c62",
            ] -> (known after apply)
            # (2 unchanged attributes hidden)
        }

      + service_registries {
          + registry_arn = (known after apply)
        }

        # (3 unchanged blocks hidden)
    }

  # module.service.aws_ecs_task_definition.this must be replaced
-/+ resource "aws_ecs_task_definition" "this" {
      ~ arn                      = "arn:aws:ecs:eu-central-1:553637109631:task-definition/cupcake-cupcake:3" -> (known after apply)
      ~ arn_without_revision     = "arn:aws:ecs:eu-central-1:553637109631:task-definition/cupcake-cupcake" -> (known after apply)
      ~ container_definitions    = jsonencode(
          ~ [
              ~ {
                  ~ environment            = [
                        {
                            name  = "COGNITO_DOMAIN"
                            value = "javabin-internal.auth.eu-central-1.amazoncognito.com"
                        },
                      + {
                          + name  = "COGNITO_EXTRA_AUTH_PARAMS"
                          + value = "prompt=select_account"
                        },
                        {
                            name  = "COGNITO_GROUPS"
                            value = "helter"
                        },
                        # (6 unchanged elements hidden)
                    ]
                    name                   = "cupcake"
                  ~ portMappings           = [
                      ~ {
                          - hostPort      = 3000
                            # (2 unchanged attributes hidden)
                        },
                    ]
                  ~ secrets                = [
                        # (2 unchanged elements hidden)
                        {
                            name      = "NUXT_PUBLIC_OIDC_CLIENT_ID"
                            valueFrom = "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/apps/cupcake/cupcake/cognito-client-id"
                        },
                      + {
                          + name      = "NUXT_PUBLIC_OIDC_IDENTITY_PROVIDER"
                          + valueFrom = "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/apps/cupcake/cupcake/cognito-client-identity-provider"
                        },
                    ]
                  - systemControls         = []
                  - volumesFrom            = []
                    # (6 unchanged attributes hidden)
                },
            ] # forces replacement
        )
      ~ enable_fault_injection   = false -> (known after apply)
      ~ id                       = "cupcake-cupcake" -> (known after apply)
      ~ revision                 = 3 -> (known after apply)
      - tags                     = {} -> null
        # (10 unchanged attributes hidden)

      - volume {
          - configure_at_launch = false -> null
          - name                = "tmp" -> null
        }
      + volume {
          + configure_at_launch = (known after apply)
          + name                = "tmp"
        }
    }

Plan: 6 to add, 1 to change, 1 to destroy.

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

Saved the plan to: tfplan

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

LLM Review

Risk: 🟡 MEDIUM

Plan creates 6 networking/service-discovery/SSM resources for cupcake-cupcake, updates the ECS service in place to detach its old security group and register with service discovery, and replaces the task definition (revision 3) to add Cognito/OIDC env vars and secrets; no databases or public exposure are involved, but the task definition replacement and SG change need attention during apply.

  • ✅ [routine] New task definition replaces revision 3 with new env vars COGNITO_EXTRA_AUTH_PARAMS (prompt=select_account) and secrets NUXT_PUBLIC_OIDC_IDENTITY_PROVIDER, plus a volume block recreated with the same name 'tmp'. The replacement is driven by container_definitions changes (marked 'forces replacement'). Expected for an app config change; confirm the new secret SSM parameter path exists before apply, since ECS will fail to start tasks if a secret cannot be resolved.
  • 💥 [destruction] The aws_ecs_task_definition is destroyed and recreated. Task definitions are immutable and are not really deleted in AWS (they are deregistered), so there is no data loss, but the ECS service must be pointed at the new revision. Also the hostPort 3000 mapping is removed from portMappings, which is usually harmless with awsvpc networking, but verify the container still listens on 3000 and the ALB target group port matches.
  • 🔒 [security] The ECS service's network_configuration drops security group sg-0df9a0a3a22548c62 and the plan relies on the new cupcake-cupcake-tasks SG (created in this plan). Make sure the old SG is not needed by other traffic (e.g., existing DB access rules that reference it) and that the new SG's ingress only allows the ALB on port 3000 (it does: ingress from sg-061000c0fa68a41b7 on tcp 3000) and all egress 0.0.0.0/0. Peer rules are managed externally by javabin-app-peers-sync, so ingress from other apps will be added outside this plan.
  • 🔒 [security] New SSM parameter /javabin/apps/cupcake/cupcake/network is created with a value marked sensitive and is read by an external platform Lambda (app-peers-sync). Verify the value contains no secrets beyond what the platform expects, and that the Lambda's IAM access is scoped to this path.
  • ✅ [routine] New service discovery service (cloud map, namespace ns-4qfb7mei2fit4q4b, A records, TTL 10, force_destroy true) is attached to the ECS service via service_registries. Adds minimal cost (Cloud Map charges per discovered instance/query). No NAT gateways, load balancers, or RDS instances are created, so no significant new billable infrastructure.

Alexanderamiri added a commit to javaBin/platform that referenced this pull request Oct 30, 2026
… prompt (#176)

## Why
The probe client (#174) showed that Cognito managed login forwards
`prompt=select_account` to Google **only when the request also sends
`identity_provider`**. `auth-doctor.py` always adds `identity_provider`,
so an app that sends only `prompt` passed but would get no account
chooser after the Google cutover (#175).

## What
- New `chooser` check (WARN only): an app that renames auth variables
via `auth.env` but doesn't alias `COGNITO_IDENTITY_PROVIDER` almost
certainly doesn't send it. Apps that read the platform variables
directly aren't flagged, since the doctor can't see their code.
- The authorize warning and the docstring explain the
`identity_provider` requirement.

## How verified
- `python3 -m unittest discover -s scripts/tests`: 133 tests, OK. There
are 4 new tests: aliased without IdP warns, aliased with IdP passes, no
aliases passes, and the probe names the IdP.
- `python3 -m unittest discover -s terraform/lambda-src/tests`: 219
tests, OK.
- Live against the current pool:
  - frosting's `app.yaml` on main gets `WARN chooser`.
- The `app.yaml` from javaBin/frosting#258, which aliases
`COGNITO_IDENTITY_PROVIDER`, passes with no warning.

## Rollout
Script only, with no Terraform changes. App deploys pick it up from
platform `main`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Terraform Plan

🚧 Changes detected — Plan: 6 to add, 1 to change, 1 to destroy.

Plan output
Acquiring state lock. This may take a few moments...

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

Terraform will perform the following actions:

  # module.network.aws_security_group.tasks will be created
  + resource "aws_security_group" "tasks" {
      + arn                    = (known after apply)
      + description            = "ECS tasks of cupcake-cupcake; peer rules are managed by javabin-app-peers-sync"
      + egress                 = (known after apply)
      + id                     = (known after apply)
      + ingress                = (known after apply)
      + name                   = "cupcake-cupcake-tasks"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = true
      + tags                   = {
          + "Name"            = "cupcake-cupcake-tasks"
          + "javabin-network" = "app"
        }
      + tags_all               = {
          + "Name"            = "cupcake-cupcake-tasks"
          + "environment"     = "production"
          + "javabin-network" = "app"
          + "managed-by"      = "terraform"
          + "repo"            = "javaBin/frosting"
          + "service"         = "cupcake"
          + "team"            = "cupcake"
        }
      + vpc_id                 = "vpc-0cd3502de2527a310"
    }

  # module.network.aws_service_discovery_service.this will be created
  + resource "aws_service_discovery_service" "this" {
      + arn           = (known after apply)
      + force_destroy = true
      + id            = (known after apply)
      + name          = "cupcake-cupcake"
      + namespace_id  = (known after apply)
      + tags_all      = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + type          = (known after apply)

      + dns_config {
          + namespace_id   = "ns-4qfb7mei2fit4q4b"
          + routing_policy = "MULTIVALUE"

          + dns_records {
              + ttl  = 10
              + type = "A"
            }
        }

      + health_check_custom_config {
          + failure_threshold = 1
        }
    }

  # module.network.aws_ssm_parameter.network will be created
  + resource "aws_ssm_parameter" "network" {
      + arn            = (known after apply)
      + data_type      = (known after apply)
      + description    = "App-to-app request for cupcake-cupcake — read by the platform app-peers-sync Lambda"
      + has_value_wo   = (known after apply)
      + id             = (known after apply)
      + insecure_value = (known after apply)
      + key_id         = (known after apply)
      + name           = "/javabin/apps/cupcake/cupcake/network"
      + tags_all       = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + tier           = (known after apply)
      + type           = "String"
      + value          = (sensitive value)
      + version        = (known after apply)
    }

  # module.network.aws_vpc_security_group_egress_rule.all will be created
  + resource "aws_vpc_security_group_egress_rule" "all" {
      + arn                    = (known after apply)
      + cidr_ipv4              = "0.0.0.0/0"
      + description            = "All outbound"
      + id                     = (known after apply)
      + ip_protocol            = "-1"
      + security_group_id      = (known after apply)
      + security_group_rule_id = (known after apply)
      + tags_all               = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
    }

  # module.network.aws_vpc_security_group_ingress_rule.alb[0] will be created
  + resource "aws_vpc_security_group_ingress_rule" "alb" {
      + arn                          = (known after apply)
      + description                  = "ALB to the app port"
      + from_port                    = 3000
      + id                           = (known after apply)
      + ip_protocol                  = "tcp"
      + referenced_security_group_id = "sg-061000c0fa68a41b7"
      + security_group_id            = (known after apply)
      + security_group_rule_id       = (known after apply)
      + tags_all                     = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/frosting"
          + "service"     = "cupcake"
          + "team"        = "cupcake"
        }
      + to_port                      = 3000
    }

  # module.service.aws_ecs_service.this will be updated in-place
  ~ resource "aws_ecs_service" "this" {
        id                                 = "arn:aws:ecs:eu-central-1:553637109631:service/javabin-platform/cupcake-cupcake"
        name                               = "cupcake-cupcake"
        tags                               = {}
      ~ task_definition                    = "arn:aws:ecs:eu-central-1:553637109631:task-definition/cupcake-cupcake:3" -> (known after apply)
        # (16 unchanged attributes hidden)

      ~ network_configuration {
          ~ security_groups  = [
              - "sg-0df9a0a3a22548c62",
            ] -> (known after apply)
            # (2 unchanged attributes hidden)
        }

      + service_registries {
          + registry_arn = (known after apply)
        }

        # (3 unchanged blocks hidden)
    }

  # module.service.aws_ecs_task_definition.this must be replaced
-/+ resource "aws_ecs_task_definition" "this" {
      ~ arn                      = "arn:aws:ecs:eu-central-1:553637109631:task-definition/cupcake-cupcake:3" -> (known after apply)
      ~ arn_without_revision     = "arn:aws:ecs:eu-central-1:553637109631:task-definition/cupcake-cupcake" -> (known after apply)
      ~ container_definitions    = jsonencode(
          ~ [
              ~ {
                  ~ environment            = [
                        {
                            name  = "COGNITO_DOMAIN"
                            value = "javabin-internal.auth.eu-central-1.amazoncognito.com"
                        },
                      + {
                          + name  = "COGNITO_EXTRA_AUTH_PARAMS"
                          + value = "prompt=select_account"
                        },
                        {
                            name  = "COGNITO_GROUPS"
                            value = "helter"
                        },
                        # (6 unchanged elements hidden)
                    ]
                    name                   = "cupcake"
                  ~ portMappings           = [
                      ~ {
                          - hostPort      = 3000
                            # (2 unchanged attributes hidden)
                        },
                    ]
                  ~ secrets                = [
                        # (2 unchanged elements hidden)
                        {
                            name      = "NUXT_PUBLIC_OIDC_CLIENT_ID"
                            valueFrom = "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/apps/cupcake/cupcake/cognito-client-id"
                        },
                      + {
                          + name      = "NUXT_PUBLIC_OIDC_IDENTITY_PROVIDER"
                          + valueFrom = "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/apps/cupcake/cupcake/cognito-client-identity-provider"
                        },
                    ]
                  - systemControls         = []
                  - volumesFrom            = []
                    # (6 unchanged attributes hidden)
                },
            ] # forces replacement
        )
      ~ enable_fault_injection   = false -> (known after apply)
      ~ id                       = "cupcake-cupcake" -> (known after apply)
      ~ revision                 = 3 -> (known after apply)
      - tags                     = {} -> null
        # (10 unchanged attributes hidden)

      - volume {
          - configure_at_launch = false -> null
          - name                = "tmp" -> null
        }
      + volume {
          + configure_at_launch = (known after apply)
          + name                = "tmp"
        }
    }

Plan: 6 to add, 1 to change, 1 to destroy.

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

Saved the plan to: tfplan

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

LLM Review

Risk: 🟡 MEDIUM

Plan creates 6 networking/service-discovery/SSM resources for the cupcake app, updates its ECS service in place, and replaces its ECS task definition (1 destroy), with no database or internet-exposed security group changes.

  • 💥 [destruction] aws_ecs_task_definition.this is destroyed and recreated (-/+) because container_definitions changes force replacement. The old revision is deregistered and a new one created. The ECS service then points at a new revision, so this causes a rolling deployment. Confirm the task definition change is intended and that deployment ordering is acceptable for a production service.
  • 💥 [destruction] aws_ecs_service.this is updated in place. Its network_configuration drops security group sg-0df9a0a3a22548c62 (known after apply, likely replaced by the new tasks security group), and it adds a service_registries block for Cloud Map. Verify the old security group is not still needed by other resources and that the service does not lose connectivity during the switch.
  • 🔒 [security] New aws_security_group.tasks is created with an ingress rule allowing TCP 3000 only from the ALB security group sg-061000c0fa68a41b7, and an all-outbound egress rule to 0.0.0.0/0. Peer rules are managed externally by javabin-app-peers-sync, so inbound app-to-app rules will be added outside this plan. Those external rules should be reviewed separately.
  • 🔒 [security] Task definition adds COGNITO_EXTRA_AUTH_PARAMS=prompt=select_account and an NUXT_PUBLIC_OIDC_IDENTITY_PROVIDER secret from SSM. The task definition also removes hostPort 3000 from the port mapping (awsvpc mode, so this is typically harmless). Auth-related changes should be reviewed for correctness.
  • ✅ [routine] New SSM parameter /javabin/apps/cupcake/cupcake/network (String, value sensitive) and a Cloud Map service in namespace ns-4qfb7mei2fit4q4b are created. The SSM value is consumed by the platform app-peers-sync Lambda. No meaningful incremental cost; no NAT gateways, load balancers, or databases are added.

@Alexanderamiri
Alexanderamiri merged commit d86986d into main Oct 30, 2026
10 checks passed
@Alexanderamiri
Alexanderamiri deleted the feat/select-account branch October 30, 2026 09:32
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