Skip to content

fix(ci): review app plans in a platform Lambda instead of with team roles - #137

Merged
Alexanderamiri merged 8 commits into
mainfrom
fix/app-plan-review
Oct 23, 2026
Merged

Alexanderamiri merged 8 commits into
mainfrom
fix/app-plan-review

Conversation

@Alexanderamiri

Copy link
Copy Markdown
Member

Fixes #136. Stacked on #134 (it reuses that PR's GitHub OIDC verification). The base is fix/team-isolation, so the diff shows only this change; merge #134 first and GitHub retargets this to main.

Why

  • Every review fails. App tf-plan ran review-plan.py with javabin-ci-team-<team>, and the developer boundary's DenySecSvcs denies bedrock:Invoke*/Converse*. Every app review returned FAILED, so every app apply needed a board override. That's what cupcake and frosting hit.
  • The Slack alert can't work either. The HIGH-risk alert read /javabin/slack/*, which DenyPlatSSM also denies.
  • A plan job could set its own verdict. The job wrote risk.json itself, with team credentials, so it could mark its own plan LOW.

What changed

Option 1 from the issue:

  • New Lambda javabin-plan-review:
    • verifies the job's GitHub OIDC token (aud javabin-plan-review), so the plan must be the repo's own
    • reviews plan-output.txt with the same scripts/review-plan.py as platform CI, bundled into the zip; the Bedrock call is now injectable
    • retries transient errors up to 3 times with backoff
    • writes risk.json and review.json, and posts HIGH/FAILED to the override channel on pushes to main
    • returns the markdown for the PR comment
  • tf-plan: re-assumes javabin-ci-app-broker via OIDC, which may now invoke the Lambda, and calls scripts/invoke-plan-review.sh. The job no longer uploads risk.json or sends the Slack alert itself.
  • Team roles: an explicit Deny on s3:PutObject/DeleteObject for */risk.json, */review.json and */override.json in the plan bucket.
  • Bedrock stays out of team roles. The developer boundary is unchanged.

On the issue's second point: a review that can't run after retries is still FAILED and blocked. The PR comment now says the review could not run and to re-run the workflow, instead of looking like a risk verdict.

Checks

  • Lambda tests (23) pass. The new ones cover LOW/MEDIUM verdict written, retry then success, persistent failure → FAILED, another repo's plan refused, bad token refused.
  • terraform validate and actionlint pass.

After merge and apply, re-run frosting and cupcake. tf-apply should get a real verdict.

🤖 Generated with Claude Code

Alexanderamiri and others added 6 commits October 23, 2026 16:09
- The shared javabin-ecs-execution role could read every /javabin/apps/*
  parameter and every team could pass it, so any team could mount another
  team's secrets in its own task definition. Each registered team now gets
  javabin-ecs-exec-{team}, reading only its own path; the developer
  boundary only lets a team pass its own. The shared role keeps image pull
  and logs only.
- DenyShared did not cover ec2:AuthorizeSecurityGroup*/RevokeSecurityGroup*,
  so any team CI role could open every app to every other or remove the
  ALB rule on the shared ECS tasks SG (confirmed with the IAM simulator).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Both Lambdas took the repo from the request payload, and the gate's sign
action (approve a HIGH-risk plan) was open to any caller. Code running in
an app's platform job (a Terraform external data source, say) could claim
another repo's team credentials or sign its own override.

Callers now send a GitHub OIDC token; the Lambdas verify it against
GitHub's JWKS (RS256 via openssl, no new dependencies) and read the repo
from its signed claims. check also requires the plan to be the repo's own,
and sign requires a token from approve-override.yml in javaBin/platform in
the override-approval environment, recording the token's actor. The
override workflow passes inputs via env instead of interpolating them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sync-registered-teams listed every GitHub org team, so non-app teams like
owners and developer got AWS CI and deploy roles. Use teams/*.yaml in
javaBin/registry, the documented source of truth.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Moved to its own PR: switching to registry teams destroys the roles of 21
non-app org teams (148 resources), which plans HIGH and needs a board
override. The security fixes here should not wait on that.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The previous revert also undid the CLAUDE.md entries for the execution
roles, the OIDC token script and the broker fix.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…oles

App tf-plan ran the LLM review with the team CI role, which the developer
boundary denies Bedrock, so every app review FAILED and every apply needed
a board override (#136). The HIGH-risk Slack alert read /javabin/slack/*,
also denied, and the job wrote risk.json itself with team credentials.

tf-plan now invokes javabin-plan-review through the broker OIDC role. The
Lambda verifies the job's GitHub OIDC token, reviews the repo's own plan
text with the same review-plan.py as platform CI (retrying transient
errors), writes risk.json/review.json and sends the Slack alert. Team roles
are denied writing risk.json, review.json and override.json, so a plan job
cannot set its own verdict.

Fixes #136

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Alexanderamiri
Alexanderamiri requested a review from a team as a code owner October 23, 2026 14:41
@github-actions

Copy link
Copy Markdown

Terraform Plan

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

Plan output
aws_ssm_parameter.atlassian_org_id: Refreshing state... [id=/javabin/platform/atlassian-org-id]
aws_ssm_parameter.atlassian_api_key: Refreshing state... [id=/javabin/platform/atlassian-api-key]

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

Terraform will perform the following actions:

  # module.iam.aws_iam_policy.developer_boundary will be updated in-place
  ~ resource "aws_iam_policy" "developer_boundary" {
        id               = "arn:aws:iam::553637109631:policy/javabin-developer-boundary"
        name             = "javabin-developer-boundary"
      ~ policy           = jsonencode(
          ~ {
              ~ Statement = [
                    # (9 unchanged elements hidden)
                    {
                        Action      = "*"
                        Condition   = {
                            Null            = {
                                "aws:ResourceTag/team" = "false"
                            }
                            StringNotEquals = {
                                "aws:ResourceTag/team" = [
                                    "${aws:PrincipalTag/team}",
                                    "shared",
                                ]
                            }
                        }
                        Effect      = "Deny"
                        NotResource = [
                            "arn:aws:s3:::javabin-terraform-state-553637109631",
                            "arn:aws:s3:::javabin-terraform-state-553637109631/*",
                            "arn:aws:dynamodb:eu-central-1:553637109631:table/javabin-terraform-app-locks",
                            "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631",
                            "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631/*",
                        ]
                        Sid         = "DenyXTeam"
                    },
                  ~ {
                      ~ Action    = [
                            # (15 unchanged elements hidden)
                            "sns:SetTopicAttributes",
                          + "ec2:AuthorizeSecurityGroup*",
                          + "ec2:RevokeSecurityGroup*",
                        ]
                        # (4 unchanged attributes hidden)
                    },
                    {
                        Action    = [
                            "ec2:DeleteTags",
                            "ec2:CreateTags",
                            "ecs:TagResource",
                            "ecs:UntagResource",
                            "elasticloadbalancing:AddTags",
                            "elasticloadbalancing:RemoveTags",
                            "iam:TagRole",
                            "iam:UntagRole",
                            "sns:TagResource",
                            "sns:UntagResource",
                        ]
                        Condition = {
                            StringEquals = {
                                "aws:ResourceTag/team" = [
                                    "shared",
                                    "platform",
                                ]
                            }
                        }
                        Effect    = "Deny"
                        Resource  = "*"
                        Sid       = "DenyTagStrip"
                    },
                    {
                        Action   = [
                            "ssm:GetParameter*",
                            "ssm:GetParametersByPath",
                        ]
                        Effect   = "Deny"
                        Resource = [
                            "arn:aws:ssm:*:*:parameter/javabin/platform/*",
                            "arn:aws:ssm:*:*:parameter/javabin/slack/*",
                            "arn:aws:ssm:*:*:parameter/javabin/platform-overrides/*",
                        ]
                        Sid      = "DenyPlatSSM"
                    },
                  ~ {
                      ~ NotResource = [
                            "arn:aws:iam::*:role/${aws:PrincipalTag/team}-*",
                          - "arn:aws:iam::*:role/javabin-ecs-execution",
                          + "arn:aws:iam::*:role/javabin-ecs-exec-${aws:PrincipalTag/team}",
                        ]
                        # (3 unchanged attributes hidden)
                    },
                    {
                        Action      = [
                            "logs:GetLogEvents",
                            "logs:FilterLogEvents",
                            "logs:StartQuery",
                            "logs:GetQueryResults",
                        ]
                        Effect      = "Deny"
                        NotResource = [
                            "arn:aws:logs:*:*:log-group:/ecs/${aws:PrincipalTag/team}/*",
                            "arn:aws:logs:*:*:log-group:/ecs/${aws:PrincipalTag/team}/*:*",
                        ]
                        Sid         = "DenyXLogs"
                    },
                    # (3 unchanged elements hidden)
                ]
                # (1 unchanged attribute hidden)
            }
        )
        tags             = {
            "Name" = "javabin-developer-boundary"
        }
        # (6 unchanged attributes hidden)
    }

  # module.iam.aws_iam_role.ecs_exec_team["cake"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-cake"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-cake"
          + "for-team" = "cake"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-cake"
          + "environment" = "production"
          + "for-team"    = "cake"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["commandchimps"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-commandchimps"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-commandchimps"
          + "for-team" = "commandchimps"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-commandchimps"
          + "environment" = "production"
          + "for-team"    = "commandchimps"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["cupcake"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-cupcake"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-cupcake"
          + "for-team" = "cupcake"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-cupcake"
          + "environment" = "production"
          + "for-team"    = "cupcake"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["developer"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-developer"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-developer"
          + "for-team" = "developer"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-developer"
          + "environment" = "production"
          + "for-team"    = "developer"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["java-no"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-java-no"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-java-no"
          + "for-team" = "java-no"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-java-no"
          + "environment" = "production"
          + "for-team"    = "java-no"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["javazone-no"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-javazone-no"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-javazone-no"
          + "for-team" = "javazone-no"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-javazone-no"
          + "environment" = "production"
          + "for-team"    = "javazone-no"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["javazone-work"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-javazone-work"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-javazone-work"
          + "for-team" = "javazone-work"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-javazone-work"
          + "environment" = "production"
          + "for-team"    = "javazone-work"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["jzwatch"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-jzwatch"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-jzwatch"
          + "for-team" = "jzwatch"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-jzwatch"
          + "environment" = "production"
          + "for-team"    = "jzwatch"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["owners"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-owners"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-owners"
          + "for-team" = "owners"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-owners"
          + "environment" = "production"
          + "for-team"    = "owners"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["partnermanagement"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-partnermanagement"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-partnermanagement"
          + "for-team" = "partnermanagement"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-partnermanagement"
          + "environment" = "production"
          + "for-team"    = "partnermanagement"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-apps"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-apps"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-apps"
          + "for-team" = "team-apps"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-apps"
          + "environment" = "production"
          + "for-team"    = "team-apps"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-cibus"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-cibus"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-cibus"
          + "for-team" = "team-cibus"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-cibus"
          + "environment" = "production"
          + "for-team"    = "team-cibus"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-cibus2"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-cibus2"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-cibus2"
          + "for-team" = "team-cibus2"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-cibus2"
          + "environment" = "production"
          + "for-team"    = "team-cibus2"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-ems"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-ems"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-ems"
          + "for-team" = "team-ems"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-ems"
          + "environment" = "production"
          + "for-team"    = "team-ems"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-incogito"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-incogito"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-incogito"
          + "for-team" = "team-incogito"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-incogito"
          + "environment" = "production"
          + "for-team"    = "team-incogito"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-javazone-badge"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-javazone-badge"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-javazone-badge"
          + "for-team" = "team-javazone-badge"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-javazone-badge"
          + "environment" = "production"
          + "for-team"    = "team-javazone-badge"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-javazone-video"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-javazone-video"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-javazone-video"
          + "for-team" = "team-javazone-video"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-javazone-video"
          + "environment" = "production"
          + "for-team"    = "team-javazone-video"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-jz-text-adventure"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-jz-text-adventure"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-jz-text-adventure"
          + "for-team" = "team-jz-text-adventure"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-jz-text-adventure"
          + "environment" = "production"
          + "for-team"    = "team-jz-text-adventure"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-portal"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-portal"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-portal"
          + "for-team" = "team-portal"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-portal"
          + "environment" = "production"
          + "for-team"    = "team-portal"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-scala-training-code"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-scala-training-code"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-scala-training-code"
          + "for-team" = "team-scala-training-code"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-scala-training-code"
          + "environment" = "production"
          + "for-team"    = "team-scala-training-code"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-submitit"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-submitit"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-submitit"
          + "for-team" = "team-submitit"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-submitit"
          + "environment" = "production"
          + "for-team"    = "team-submitit"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["teammoosehead"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-teammoosehead"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-teammoosehead"
          + "for-team" = "teammoosehead"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-teammoosehead"
          + "environment" = "production"
          + "for-team"    = "teammoosehead"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["teamteknologihuset"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-teamteknologihuset"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-teamteknologihuset"
          + "for-team" = "teamteknologihuset"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-teamteknologihuset"
          + "environment" = "production"
          + "for-team"    = "teamteknologihuset"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["testteam"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-testteam"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-testteam"
          + "for-team" = "testteam"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-testteam"
          + "environment" = "production"
          + "for-team"    = "testteam"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_app_broker will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_app_broker" {
        id     = "javabin-ci-app-broker:invoke-ci-broker-only"
        name   = "invoke-ci-broker-only"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = "lambda:InvokeFunction"
                      - Effect   = "Allow"
                      - Resource = "arn:aws:lambda:eu-central-1:553637109631:function:javabin-ci-broker"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["cake"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-cake:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "cake"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/cake-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["commandchimps"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-commandchimps:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "commandchimps"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/commandchimps-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["cupcake"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-cupcake:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "cupcake"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/cupcake-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["developer"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-developer:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "developer"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/developer-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["java-no"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-java-no:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "java-no"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/java-no-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["javazone-no"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-javazone-no:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "javazone-no"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/javazone-no-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["javazone-work"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-javazone-work:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "javazone-work"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/javazone-work-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["jzwatch"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-jzwatch:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                 

LLM Review

Risk: 🔴 HIGH

Plan updates the developer permissions boundary (adds EC2 security group authorize/revoke actions and changes the ECS execution role exemption) and creates a large batch of per-team ECS execution IAM roles; the visible output is truncated, so the full plan has not been reviewed.

  • 🔒 [security] The developer permissions boundary (javabin-developer-boundary) is modified to add ec2:AuthorizeSecurityGroup* and ec2:RevokeSecurityGroup* to an allow list. Developers can then change security group rules, which could open ingress to the internet. Confirm the boundary's Deny statements cover this, or remove these actions.
  • 🔒 [security] The boundary's NotResource exemption for the ECS execution role changes from javabin-ecs-execution to javabin-ecs-exec-${aws:PrincipalTag/team}. Verify the new per-team role naming does not let a team reach roles belonging to other teams, and that the ${aws:PrincipalTag/team} substitution is safe for the team values in use.
  • 🔒 [security] About 30+ new aws_iam_role.ecs_exec_team roles are created. Each has the org permissions boundary attached, which is good. However, their tags set team = "shared" while for-team varies, so review whether tag-based access controls (aws:ResourceTag/team) grant these roles unintended access.
  • ✅ [routine] No resources are destroyed in the visible portion of the plan. The IAM role creations are additive and carry no direct cost.
  • ✅ [routine] The output was truncated after the ecs_exec_team creations. Remaining changes (ECS, ALB, or other resources) cannot be assessed, so the review is incomplete. Re-run the review with the full plan output.

Review feedback on #137:
- boto3's default retries could spend the whole Lambda timeout on one slow
  Bedrock call, leaving no risk.json, and the gate then refuses even a
  board override. Bound each call (90s, no SDK retries), stop retrying
  when time runs short, and write risk.json as FAILED before reviewing.
- A failed invoke now yields a FAILED review and PR comment instead of
  failing the job.
- Docs: the plan text is uploaded by the job, so the review catches
  mistakes rather than forged plans.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Terraform Plan

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

Plan output
Acquiring state lock. This may take a few moments...
aws_ssm_parameter.atlassian_org_id: Refreshing state... [id=/javabin/platform/atlassian-org-id]
aws_ssm_parameter.atlassian_api_key: Refreshing state... [id=/javabin/platform/atlassian-api-key]

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

Terraform will perform the following actions:

  # module.iam.aws_iam_policy.developer_boundary will be updated in-place
  ~ resource "aws_iam_policy" "developer_boundary" {
        id               = "arn:aws:iam::553637109631:policy/javabin-developer-boundary"
        name             = "javabin-developer-boundary"
      ~ policy           = jsonencode(
          ~ {
              ~ Statement = [
                    # (9 unchanged elements hidden)
                    {
                        Action      = "*"
                        Condition   = {
                            Null            = {
                                "aws:ResourceTag/team" = "false"
                            }
                            StringNotEquals = {
                                "aws:ResourceTag/team" = [
                                    "${aws:PrincipalTag/team}",
                                    "shared",
                                ]
                            }
                        }
                        Effect      = "Deny"
                        NotResource = [
                            "arn:aws:s3:::javabin-terraform-state-553637109631",
                            "arn:aws:s3:::javabin-terraform-state-553637109631/*",
                            "arn:aws:dynamodb:eu-central-1:553637109631:table/javabin-terraform-app-locks",
                            "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631",
                            "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631/*",
                        ]
                        Sid         = "DenyXTeam"
                    },
                  ~ {
                      ~ Action    = [
                            # (15 unchanged elements hidden)
                            "sns:SetTopicAttributes",
                          + "ec2:AuthorizeSecurityGroup*",
                          + "ec2:RevokeSecurityGroup*",
                        ]
                        # (4 unchanged attributes hidden)
                    },
                    {
                        Action    = [
                            "ec2:DeleteTags",
                            "ec2:CreateTags",
                            "ecs:TagResource",
                            "ecs:UntagResource",
                            "elasticloadbalancing:AddTags",
                            "elasticloadbalancing:RemoveTags",
                            "iam:TagRole",
                            "iam:UntagRole",
                            "sns:TagResource",
                            "sns:UntagResource",
                        ]
                        Condition = {
                            StringEquals = {
                                "aws:ResourceTag/team" = [
                                    "shared",
                                    "platform",
                                ]
                            }
                        }
                        Effect    = "Deny"
                        Resource  = "*"
                        Sid       = "DenyTagStrip"
                    },
                    {
                        Action   = [
                            "ssm:GetParameter*",
                            "ssm:GetParametersByPath",
                        ]
                        Effect   = "Deny"
                        Resource = [
                            "arn:aws:ssm:*:*:parameter/javabin/platform/*",
                            "arn:aws:ssm:*:*:parameter/javabin/slack/*",
                            "arn:aws:ssm:*:*:parameter/javabin/platform-overrides/*",
                        ]
                        Sid      = "DenyPlatSSM"
                    },
                  ~ {
                      ~ NotResource = [
                            "arn:aws:iam::*:role/${aws:PrincipalTag/team}-*",
                          - "arn:aws:iam::*:role/javabin-ecs-execution",
                          + "arn:aws:iam::*:role/javabin-ecs-exec-${aws:PrincipalTag/team}",
                        ]
                        # (3 unchanged attributes hidden)
                    },
                    {
                        Action      = [
                            "logs:GetLogEvents",
                            "logs:FilterLogEvents",
                            "logs:StartQuery",
                            "logs:GetQueryResults",
                        ]
                        Effect      = "Deny"
                        NotResource = [
                            "arn:aws:logs:*:*:log-group:/ecs/${aws:PrincipalTag/team}/*",
                            "arn:aws:logs:*:*:log-group:/ecs/${aws:PrincipalTag/team}/*:*",
                        ]
                        Sid         = "DenyXLogs"
                    },
                    # (3 unchanged elements hidden)
                ]
                # (1 unchanged attribute hidden)
            }
        )
        tags             = {
            "Name" = "javabin-developer-boundary"
        }
        # (6 unchanged attributes hidden)
    }

  # module.iam.aws_iam_role.ecs_exec_team["cake"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-cake"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-cake"
          + "for-team" = "cake"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-cake"
          + "environment" = "production"
          + "for-team"    = "cake"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["commandchimps"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-commandchimps"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-commandchimps"
          + "for-team" = "commandchimps"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-commandchimps"
          + "environment" = "production"
          + "for-team"    = "commandchimps"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["cupcake"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-cupcake"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-cupcake"
          + "for-team" = "cupcake"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-cupcake"
          + "environment" = "production"
          + "for-team"    = "cupcake"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["developer"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-developer"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-developer"
          + "for-team" = "developer"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-developer"
          + "environment" = "production"
          + "for-team"    = "developer"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["java-no"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-java-no"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-java-no"
          + "for-team" = "java-no"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-java-no"
          + "environment" = "production"
          + "for-team"    = "java-no"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["javazone-no"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-javazone-no"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-javazone-no"
          + "for-team" = "javazone-no"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-javazone-no"
          + "environment" = "production"
          + "for-team"    = "javazone-no"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["javazone-work"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-javazone-work"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-javazone-work"
          + "for-team" = "javazone-work"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-javazone-work"
          + "environment" = "production"
          + "for-team"    = "javazone-work"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["jzwatch"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-jzwatch"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-jzwatch"
          + "for-team" = "jzwatch"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-jzwatch"
          + "environment" = "production"
          + "for-team"    = "jzwatch"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["owners"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-owners"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-owners"
          + "for-team" = "owners"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-owners"
          + "environment" = "production"
          + "for-team"    = "owners"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["partnermanagement"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-partnermanagement"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-partnermanagement"
          + "for-team" = "partnermanagement"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-partnermanagement"
          + "environment" = "production"
          + "for-team"    = "partnermanagement"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-apps"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-apps"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-apps"
          + "for-team" = "team-apps"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-apps"
          + "environment" = "production"
          + "for-team"    = "team-apps"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-cibus"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-cibus"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-cibus"
          + "for-team" = "team-cibus"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-cibus"
          + "environment" = "production"
          + "for-team"    = "team-cibus"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-cibus2"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-cibus2"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-cibus2"
          + "for-team" = "team-cibus2"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-cibus2"
          + "environment" = "production"
          + "for-team"    = "team-cibus2"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-ems"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-ems"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-ems"
          + "for-team" = "team-ems"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-ems"
          + "environment" = "production"
          + "for-team"    = "team-ems"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-incogito"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-incogito"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-incogito"
          + "for-team" = "team-incogito"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-incogito"
          + "environment" = "production"
          + "for-team"    = "team-incogito"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-javazone-badge"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-javazone-badge"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-javazone-badge"
          + "for-team" = "team-javazone-badge"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-javazone-badge"
          + "environment" = "production"
          + "for-team"    = "team-javazone-badge"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-javazone-video"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-javazone-video"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-javazone-video"
          + "for-team" = "team-javazone-video"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-javazone-video"
          + "environment" = "production"
          + "for-team"    = "team-javazone-video"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-jz-text-adventure"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-jz-text-adventure"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-jz-text-adventure"
          + "for-team" = "team-jz-text-adventure"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-jz-text-adventure"
          + "environment" = "production"
          + "for-team"    = "team-jz-text-adventure"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-portal"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-portal"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-portal"
          + "for-team" = "team-portal"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-portal"
          + "environment" = "production"
          + "for-team"    = "team-portal"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-scala-training-code"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-scala-training-code"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-scala-training-code"
          + "for-team" = "team-scala-training-code"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-scala-training-code"
          + "environment" = "production"
          + "for-team"    = "team-scala-training-code"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-submitit"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-submitit"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-submitit"
          + "for-team" = "team-submitit"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-submitit"
          + "environment" = "production"
          + "for-team"    = "team-submitit"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["teammoosehead"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-teammoosehead"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-teammoosehead"
          + "for-team" = "teammoosehead"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-teammoosehead"
          + "environment" = "production"
          + "for-team"    = "teammoosehead"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["teamteknologihuset"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-teamteknologihuset"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-teamteknologihuset"
          + "for-team" = "teamteknologihuset"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-teamteknologihuset"
          + "environment" = "production"
          + "for-team"    = "teamteknologihuset"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["testteam"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-testteam"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-testteam"
          + "for-team" = "testteam"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-testteam"
          + "environment" = "production"
          + "for-team"    = "testteam"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_app_broker will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_app_broker" {
        id     = "javabin-ci-app-broker:invoke-ci-broker-only"
        name   = "invoke-ci-broker-only"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = "lambda:InvokeFunction"
                      - Effect   = "Allow"
                      - Resource = "arn:aws:lambda:eu-central-1:553637109631:function:javabin-ci-broker"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["cake"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-cake:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "cake"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/cake-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["commandchimps"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-commandchimps:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "commandchimps"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/commandchimps-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["cupcake"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-cupcake:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "cupcake"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/cupcake-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["developer"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-developer:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "developer"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/developer-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["java-no"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-java-no:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "java-no"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/java-no-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["javazone-no"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-javazone-no:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "javazone-no"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/javazone-no-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["javazone-work"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-javazone-work:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "javazone-work"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/javazone-work-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["jzwatch"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-jzwatch:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
             

LLM Review

Risk: 🔴 HIGH

Plan creates many per-team ECS execution roles and modifies the developer permissions boundary, which adds ec2:AuthorizeSecurityGroup*/RevokeSecurityGroup* permissions and changes the ECS execution role exemption; the output is truncated so the full plan (including any destroys and remaining changes) could not be reviewed.

  • 🔒 [security] The developer permissions boundary (javabin-developer-boundary) is modified to add ec2:AuthorizeSecurityGroup* and ec2:RevokeSecurityGroup* to an allow list. Developers' effective permissions could now include editing security group rules, which could open ingress to the internet. This needs verification against the intent of the boundary and whether these actions are scoped to team-tagged resources.
  • 🔒 [security] The boundary's NotResource exemption changes from arn:aws:iam:::role/javabin-ecs-execution to arn:aws:iam:::role/javabin-ecs-exec-${aws:PrincipalTag/team}. Per-team ECS execution roles are being created, and the exemption now depends on the principal's team tag. Check that the old shared execution role is no longer needed and that the templated name cannot be spoofed via tag values.
  • 🔒 [security] Each new javabin-ecs-exec- role is tagged team=shared and uses the org permissions boundary. The role names are derived from team names, so verify that the trust policy and attached policies are scoped to each team's resources only.
  • 💥 [destruction] The plan output is truncated before the end. Any destroy or replace actions in the remaining resources (for example, the old javabin-ecs-execution role being removed) are not visible and must be checked before approval.
  • ✅ [routine] Creation of about 20 IAM roles, one per team, plus policy updates. No direct cost impact. Overall risk is rated HIGH because of the security-group permission expansion in the developer boundary; if the full plan confirms that change is scoped and intended, the risk could be lowered to MEDIUM.

Alexanderamiri added a commit that referenced this pull request Oct 23, 2026
…es (#134)

Closes three of the isolation holes found while exploring app-to-app
support. All of them matter before cupcake stores real credentials. Its
sleepingpill credentials can read every talk submission.

## Why
1. **Cross-team secret access.** The shared `javabin-ecs-execution` role
could read every `/javabin/apps/*` parameter, and every team was allowed
to pass it. Any team could mount another team's secrets, or since #132
their Cognito client secrets, in its own task definition.
2. **Shared security group editable by teams.** `DenyShared` blocked
`ec2:Delete*`/`Modify*` but not
`ec2:AuthorizeSecurityGroupIngress`/`Revoke*`. The IAM policy simulator
confirms `javabin-ci-team-testteam` may edit `javabin-ecs-tasks-sg`. Any
team could open every app to every other app, or remove the ALB rule and
take all apps offline.
3. **Broker and gate trusted the payload.** `ci-broker` and `apply-gate`
took the repo from the request. The gate's `sign` action (approve a
HIGH-risk plan) accepted any caller. Code running in an app's platform
job (a Terraform `external` data source, say) could claim another repo's
team credentials or sign its own override.

## What changed
- **Execution roles:** per-team `javabin-ecs-exec-{team}`, reading only
`/javabin/apps/{team}/*`. They are tagged `team=shared`, so teams can't
edit them. `platform-data` takes `team` and returns that role. The
boundary's `DenyPassRole` only allows
`javabin-ecs-exec-${PrincipalTag/team}`. The shared role loses its
secrets policy.
- **Boundary:** `DenyShared` now covers `ec2:AuthorizeSecurityGroup*`,
`ec2:RevokeSecurityGroup*` and `iam:UpdateAssumeRolePolicy`. Without the
last one, a team could make another team's execution role trust its own
CI role. Size goes up about 110 bytes, to roughly 5,835 of 6,144.
- **Broker and gate:** callers send a GitHub OIDC token
(`scripts/github-oidc-token.sh`). The Lambdas verify it against GitHub's
JWKS (`shared/github_oidc.py`, RS256 verified in plain Python, no
dependencies or binaries) and take the repo from its signed `repository`
claim.
- `check` also requires the plan key to be under
`plans/javaBin/<repo>/`.
- `sign` requires a token from `approve-override.yml` in
javaBin/platform, in the `override-approval` environment. The approver
is the token's `actor`.
- **approve-override.yml:** passes inputs through env instead of
interpolating them into shell.

Switching team roles to registry teams was split out into #135, because
it destroys unused roles and plans HIGH. Until that merges, execution
roles are created for every GitHub org team, like the CI roles today.

## Not in this PR
- `service-rds` still allows ingress from the shared tasks SG, so team
databases share a network path (password still required). Fixing that
needs per-app SGs; recorded in CLAUDE.md. cupcake has no database.
- Team roles can still write other repos' objects in the plan bucket.
#137 denies writing `risk.json`/`review.json`/`override.json`.
Overwriting another repo's `tfplan` only makes its apply fail the SHA256
check, so it's a nuisance, not an escalation. Prefix-scoping the bucket
per repo is follow-up work.

## Checks
- `python3 -m unittest discover -s terraform/lambda-src/tests`: 20 tests
pass. The new ones sign real RS256 tokens: tampered payload, wrong
audience/org/workflow/branch, the override-signing workflow and
environment pin, non-object claims, and verification without any
subprocess.
- Reviewed by an independent agent. Its blockers are fixed in the last
commit: the exec-role trust takeover, and the openssl dependency (the
live runtime does have openssl, but verification no longer needs it).
- Generator tests pass.
- `terraform validate` on `terraform/platform`.
- actionlint.

## Rollout
- Scripts are read from `main`, so they send `id_token` from the moment
this merges. The old Lambdas ignore it until the apply replaces them.
The override script still sends `approved_by`, which the old gate needs.
- The apply creates the exec roles before apps regenerate against the
new `platform-data`.
- platform-test-app has no running tasks, so dropping the shared role's
secrets policy affects nothing live.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Base automatically changed from fix/team-isolation to main October 23, 2026 15:14
# Conflicts:
#	docs/apply-gate.md
#	scripts/github-oidc-token.sh
#	scripts/invoke-override-sign.sh
#	terraform/lambda-src/shared/github_oidc.py
#	terraform/lambda-src/tests/test_github_oidc.py
@github-actions

Copy link
Copy Markdown

Terraform Plan

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

Plan output
Acquiring state lock. This may take a few moments...
aws_ssm_parameter.atlassian_api_key: Refreshing state... [id=/javabin/platform/atlassian-api-key]
aws_ssm_parameter.atlassian_org_id: Refreshing state... [id=/javabin/platform/atlassian-org-id]

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

Terraform will perform the following actions:

  # module.iam.aws_iam_policy.developer_boundary will be updated in-place
  ~ resource "aws_iam_policy" "developer_boundary" {
        id               = "arn:aws:iam::553637109631:policy/javabin-developer-boundary"
        name             = "javabin-developer-boundary"
      ~ policy           = jsonencode(
          ~ {
              ~ Statement = [
                    # (9 unchanged elements hidden)
                    {
                        Action      = "*"
                        Condition   = {
                            Null            = {
                                "aws:ResourceTag/team" = "false"
                            }
                            StringNotEquals = {
                                "aws:ResourceTag/team" = [
                                    "${aws:PrincipalTag/team}",
                                    "shared",
                                ]
                            }
                        }
                        Effect      = "Deny"
                        NotResource = [
                            "arn:aws:s3:::javabin-terraform-state-553637109631",
                            "arn:aws:s3:::javabin-terraform-state-553637109631/*",
                            "arn:aws:dynamodb:eu-central-1:553637109631:table/javabin-terraform-app-locks",
                            "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631",
                            "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631/*",
                        ]
                        Sid         = "DenyXTeam"
                    },
                  ~ {
                      ~ Action    = [
                            # (9 unchanged elements hidden)
                            "iam:DeleteRolePolicy",
                          + "iam:UpdateAssumeRolePolicy",
                            "iam:PutRolePolicy",
                            # (4 unchanged elements hidden)
                            "sns:SetTopicAttributes",
                          + "ec2:AuthorizeSecurityGroup*",
                          + "ec2:RevokeSecurityGroup*",
                        ]
                        # (4 unchanged attributes hidden)
                    },
                    {
                        Action    = [
                            "ec2:DeleteTags",
                            "ec2:CreateTags",
                            "ecs:TagResource",
                            "ecs:UntagResource",
                            "elasticloadbalancing:AddTags",
                            "elasticloadbalancing:RemoveTags",
                            "iam:TagRole",
                            "iam:UntagRole",
                            "sns:TagResource",
                            "sns:UntagResource",
                        ]
                        Condition = {
                            StringEquals = {
                                "aws:ResourceTag/team" = [
                                    "shared",
                                    "platform",
                                ]
                            }
                        }
                        Effect    = "Deny"
                        Resource  = "*"
                        Sid       = "DenyTagStrip"
                    },
                    {
                        Action   = [
                            "ssm:GetParameter*",
                            "ssm:GetParametersByPath",
                        ]
                        Effect   = "Deny"
                        Resource = [
                            "arn:aws:ssm:*:*:parameter/javabin/platform/*",
                            "arn:aws:ssm:*:*:parameter/javabin/slack/*",
                            "arn:aws:ssm:*:*:parameter/javabin/platform-overrides/*",
                        ]
                        Sid      = "DenyPlatSSM"
                    },
                  ~ {
                      ~ NotResource = [
                            "arn:aws:iam::*:role/${aws:PrincipalTag/team}-*",
                          - "arn:aws:iam::*:role/javabin-ecs-execution",
                          + "arn:aws:iam::*:role/javabin-ecs-exec-${aws:PrincipalTag/team}",
                        ]
                        # (3 unchanged attributes hidden)
                    },
                    {
                        Action      = [
                            "logs:GetLogEvents",
                            "logs:FilterLogEvents",
                            "logs:StartQuery",
                            "logs:GetQueryResults",
                        ]
                        Effect      = "Deny"
                        NotResource = [
                            "arn:aws:logs:*:*:log-group:/ecs/${aws:PrincipalTag/team}/*",
                            "arn:aws:logs:*:*:log-group:/ecs/${aws:PrincipalTag/team}/*:*",
                        ]
                        Sid         = "DenyXLogs"
                    },
                    # (3 unchanged elements hidden)
                ]
                # (1 unchanged attribute hidden)
            }
        )
        tags             = {
            "Name" = "javabin-developer-boundary"
        }
        # (6 unchanged attributes hidden)
    }

  # module.iam.aws_iam_role.ecs_exec_team["cake"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-cake"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-cake"
          + "for-team" = "cake"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-cake"
          + "environment" = "production"
          + "for-team"    = "cake"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["commandchimps"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-commandchimps"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-commandchimps"
          + "for-team" = "commandchimps"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-commandchimps"
          + "environment" = "production"
          + "for-team"    = "commandchimps"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["cupcake"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-cupcake"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-cupcake"
          + "for-team" = "cupcake"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-cupcake"
          + "environment" = "production"
          + "for-team"    = "cupcake"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["developer"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-developer"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-developer"
          + "for-team" = "developer"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-developer"
          + "environment" = "production"
          + "for-team"    = "developer"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["java-no"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-java-no"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-java-no"
          + "for-team" = "java-no"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-java-no"
          + "environment" = "production"
          + "for-team"    = "java-no"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["javazone-no"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-javazone-no"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-javazone-no"
          + "for-team" = "javazone-no"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-javazone-no"
          + "environment" = "production"
          + "for-team"    = "javazone-no"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["javazone-work"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-javazone-work"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-javazone-work"
          + "for-team" = "javazone-work"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-javazone-work"
          + "environment" = "production"
          + "for-team"    = "javazone-work"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["jzwatch"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-jzwatch"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-jzwatch"
          + "for-team" = "jzwatch"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-jzwatch"
          + "environment" = "production"
          + "for-team"    = "jzwatch"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["owners"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-owners"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-owners"
          + "for-team" = "owners"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-owners"
          + "environment" = "production"
          + "for-team"    = "owners"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["partnermanagement"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-partnermanagement"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-partnermanagement"
          + "for-team" = "partnermanagement"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-partnermanagement"
          + "environment" = "production"
          + "for-team"    = "partnermanagement"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-apps"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-apps"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-apps"
          + "for-team" = "team-apps"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-apps"
          + "environment" = "production"
          + "for-team"    = "team-apps"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-cibus"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-cibus"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-cibus"
          + "for-team" = "team-cibus"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-cibus"
          + "environment" = "production"
          + "for-team"    = "team-cibus"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-cibus2"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-cibus2"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-cibus2"
          + "for-team" = "team-cibus2"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-cibus2"
          + "environment" = "production"
          + "for-team"    = "team-cibus2"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-ems"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-ems"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-ems"
          + "for-team" = "team-ems"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-ems"
          + "environment" = "production"
          + "for-team"    = "team-ems"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-incogito"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-incogito"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-incogito"
          + "for-team" = "team-incogito"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-incogito"
          + "environment" = "production"
          + "for-team"    = "team-incogito"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-javazone-badge"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-javazone-badge"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-javazone-badge"
          + "for-team" = "team-javazone-badge"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-javazone-badge"
          + "environment" = "production"
          + "for-team"    = "team-javazone-badge"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-javazone-video"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-javazone-video"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-javazone-video"
          + "for-team" = "team-javazone-video"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-javazone-video"
          + "environment" = "production"
          + "for-team"    = "team-javazone-video"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-jz-text-adventure"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-jz-text-adventure"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-jz-text-adventure"
          + "for-team" = "team-jz-text-adventure"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-jz-text-adventure"
          + "environment" = "production"
          + "for-team"    = "team-jz-text-adventure"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-portal"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-portal"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-portal"
          + "for-team" = "team-portal"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-portal"
          + "environment" = "production"
          + "for-team"    = "team-portal"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-scala-training-code"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-scala-training-code"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-scala-training-code"
          + "for-team" = "team-scala-training-code"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-scala-training-code"
          + "environment" = "production"
          + "for-team"    = "team-scala-training-code"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["team-submitit"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-team-submitit"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-team-submitit"
          + "for-team" = "team-submitit"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-team-submitit"
          + "environment" = "production"
          + "for-team"    = "team-submitit"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["teammoosehead"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-teammoosehead"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-teammoosehead"
          + "for-team" = "teammoosehead"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-teammoosehead"
          + "environment" = "production"
          + "for-team"    = "teammoosehead"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["teamteknologihuset"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-teamteknologihuset"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-teamteknologihuset"
          + "for-team" = "teamteknologihuset"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-teamteknologihuset"
          + "environment" = "production"
          + "for-team"    = "teamteknologihuset"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ecs_exec_team["testteam"] will be created
  + resource "aws_iam_role" "ecs_exec_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ecs-tasks.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ecs-exec-testteam"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-org-boundary"
      + tags                  = {
          + "Name"     = "javabin-ecs-exec-testteam"
          + "for-team" = "testteam"
          + "team"     = "shared"
        }
      + tags_all              = {
          + "Name"        = "javabin-ecs-exec-testteam"
          + "environment" = "production"
          + "for-team"    = "testteam"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "shared"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_app_broker will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_app_broker" {
        id     = "javabin-ci-app-broker:invoke-ci-broker-only"
        name   = "invoke-ci-broker-only"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = "lambda:InvokeFunction"
                      - Effect   = "Allow"
                      - Resource = "arn:aws:lambda:eu-central-1:553637109631:function:javabin-ci-broker"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["cake"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-cake:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "cake"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/cake-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["commandchimps"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-commandchimps:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "commandchimps"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/commandchimps-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["cupcake"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-cupcake:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "cupcake"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/cupcake-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["developer"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-developer:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "developer"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/developer-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["java-no"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-java-no:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "java-no"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/java-no-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["javazone-no"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-javazone-no:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "javazone-no"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/javazone-no-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["javazone-work"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id     = "javabin-ci-deploy-javazone-work:ecs-deploy"
        name   = "ecs-deploy"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "javazone-work"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/javazone-work-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["jzwatch"] will be updated in-place
  ~ resource "aws_iam_role_policy" "ci_deploy_ecs" {
        id    

LLM Review

Risk: 🔴 HIGH

Plan updates the developer permissions boundary (adding ec2 security group authorize/revoke and IAM UpdateAssumeRolePolicy permissions, and changing the ECS execution role exemption) and creates about 30+ per-team ECS execution roles, with the output truncated before the full plan is visible.

  • 🔒 [security] The developer permissions boundary (javabin-developer-boundary) gains "ec2:AuthorizeSecurityGroup*" and "ec2:RevokeSecurityGroup*" and "iam:UpdateAssumeRolePolicy" in an allow-style statement. Developers could modify security group rules and trust policies of roles, which may let them open network access or escalate privileges. Verify these are not granted in a way that bypasses the intended deny rules.
  • 🔒 [security] The boundary's NotResource exemption changes from "arn:aws:iam:::role/javabin-ecs-execution" to "arn:aws:iam:::role/javabin-ecs-exec-${aws:PrincipalTag/team}". This changes which roles developers can access and needs careful review of the IAM statement that uses it.
  • 🔒 [security] New roles javabin-ecs-exec- are created with tags team="shared" and for-team=. The boundary's tag-based conditions use aws:ResourceTag/team, so these roles' tagging could affect which principals may manage them. Check that the 'team=shared' tagging does not grant unintended access.
  • ✅ [routine] About 30 aws_iam_role.ecs_exec_team instances are created, one per CI team, each with permissions_boundary javabin-org-boundary and an ECS task trust policy. No policy attachments appear in the visible part of the plan; the truncated output may include more changes.
  • 💥 [destruction] No destroy actions are visible in the shown portion of the plan. The output is truncated, so the full set of changes cannot be confirmed. Review the complete plan before applying.

@Alexanderamiri
Alexanderamiri merged commit 53eeb6a into main Oct 23, 2026
4 checks passed
@Alexanderamiri
Alexanderamiri deleted the fix/app-plan-review branch October 23, 2026 15:18
Alexanderamiri added a commit that referenced this pull request Oct 23, 2026
## Why
Applying #137 and #138 failed (run 39978752602):
`reading ZIP file (identity/builds/auth_claims.zip): no such file or
directory`.
The plan job uploads only `terraform/platform/lambdas/builds/` as the
`lambda-zips` artifact. #138 added a Lambda in the `identity` module,
whose zip is built at `identity/builds/`. A saved plan doesn't rebuild
`archive_file` outputs, so the apply job needs every zip.

## What changed
- Upload `${TF_ROOT}/*/builds/*.zip` (paths relative to `TF_ROOT`), and
fail if nothing matches.
- Download into `${TF_ROOT}/`, so each zip lands in its own module's
`builds/`.

## Checks
actionlint. The real check is this PR's own merge run, which must apply
the pending #137/#138 changes (10 to add, 30 to change, MEDIUM).

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

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

App tf-plan LLM review always fails: developer boundary denies Bedrock for team CI roles

1 participant