diff --git a/.gitignore b/.gitignore index 1b323b7..bbb81f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules/ -cdk.out/ +cdk.out*/ *.js *.d.ts *.js.map diff --git a/README.md b/README.md index 4113aa9..a1b4444 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ like any other stack. > only) until 2026-07-14, when the external-dev member baseline was merged in > and the repo renamed. Deployed CloudFormation stack names are unchanged. -Stacks (deployed by the CD workflow — one job per target account): +Stacks (normally deployed by one CD job per target account; staged exceptions +are noted): | Stack | Account | Region | Purpose | |---|---|---|---| @@ -30,6 +31,7 @@ Stacks (deployed by the CD workflow — one job per target account): | `seahaven-backup-offsite` | 328440206208 | us-west-2 | Governance-locked offsite copy vault (C-7) | | `seahaven-org-governance` | 328440206208 | us-east-1 | AWS Organizations OU tree + SCPs (incl. the cdk-imported external-dev guardrails) | | `seahaven-external-dev-baseline` | 396287094661 | us-east-1 | Member-account baseline: Config, GuardDuty, Security Hub (FSBP + CIS v3.0), Access Analyzer, flow logs, budget | +| `seahaven-terraform-substrate` | 396287094661 | us-east-1 | Staged manually until SHOC role imports complete; HCP roles/deploy boundaries for the backend rehearsal, referencing the existing OIDC provider | | `seahaven-security-baseline` | 001520130573 | us-east-1 | Member-account baseline for the delegated security-admin account (same construct set) | | `seahaven-dev-baseline` | 710827005802 | us-east-1 | Member-account baseline for internal dev/staging (org-managed detection — no local GuardDuty/SecurityHub) | | `seahaven-prod-baseline` | 011934824531 | us-east-1 | Member-account baseline for production workloads (org-managed detection; mgmt account frozen for new workloads) | @@ -67,6 +69,7 @@ the TypeScript source — no separate compile step needed for `cdk synth` / | `prod-baseline` | `seahaven-prod-baseline` | 011934824531 | us-east-1 | `lib/member-baseline-stack.ts` (orgManagedDetection) | | `deploy-substrate-prod` | `seahaven-deploy-substrate` | 011934824531 | us-east-1 | `lib/deploy-substrate-stack.ts` | | `deploy-substrate-dev` | `seahaven-deploy-substrate` | 710827005802 | us-east-1 | `lib/deploy-substrate-stack.ts` | +| `terraform-substrate-external-dev` | `seahaven-terraform-substrate` | 396287094661 | us-east-1 | `lib/terraform-substrate-stack.ts` | | `dynamodb-cmk-prod` | `seahaven-dynamodb-cmk` | 011934824531 | us-east-1 | `lib/dynamodb-cmk-stack.ts` | | `alarm-topic-prod` | `seahaven-alarm-topic` | 011934824531 | us-east-1 | `lib/alarm-topic-stack.ts` | | `app-web-acl-prod` | `seahaven-app-web-acl` | 011934824531 | us-east-1 | `lib/app-web-acl-stack.ts` | @@ -214,9 +217,11 @@ created with the boundary already attached. `lib/terraform-substrate-stack.ts` + `lib/terraform-substrate/terraform-substrate.template.yaml` deploy `seahaven-terraform-substrate` into each member account that hosts -Terraform-managed workloads (currently seahaven-prod and seahaven-dev; never -mgmt — mgmt stays SAM until its stacks migrate out). It contains only the -shared account-level plumbing: +Terraform-managed workloads (currently seahaven-prod, seahaven-dev, and +external-dev; never mgmt — mgmt stays SAM until its stacks migrate out). +Prod/dev use the shared IAM-management policy. External-dev references its +existing `app.terraform.io` provider and carries only exact SHOC +import/adoption roles: - the `app.terraform.io` OIDC identity provider (audience `aws.workload.identity`; Retain — it is the federation anchor for every @@ -226,7 +231,19 @@ shared account-level plumbing: `seahaven-lambda-execution-boundary` allow-list owned by the deploy-substrate stack — hence the explicit stack dependency in `bin/app.ts`) plus the `DenyBoundaryTampering` / `DenyBoundaryPolicyEdit` - / `DenySelfMutation` backstops. + / `DenySelfMutation` backstops, +- external-dev-only deploy boundaries + `shoc-backend-{tf-poc,dev,staging}-deploy-boundary`. Each is the maximum + current policy for one exact `githubdeploy-shoc-backend-*` role. Dev + temporarily retains its live broad `elasticbeanstalk-*` S3 grants so + boundary attachment cannot regress deployment before the separately + reviewed policy narrowing, +- external-dev-only runtime boundaries + `shoc-backend-{tf-poc,dev,staging}-runtime-boundary`. These retain only the + account-scoped S3, environment health/log, and X-Ray portions of + `AWSElasticBeanstalkWebTier`, plus each environment's exact secrets/KMS/STS + data plane. They deliberately exclude the managed policy's 2026 + Bedrock/Marketplace additions. **This policy derives from `seahaven-cfn-exec-iam-management` but is deliberately stricter — it is not a mirror.** The 2026-07-30 security review @@ -255,6 +272,110 @@ deliberately NOT pre-provisioned — they are appended to the template at each stack's migration time so an account never carries trust for workspaces that do not deploy to it. +**External-dev SHOC role adoption is a staged CloudFormation import, not a +normal first deploy.** Exactly four roles exist today: +`hcptf-shoc-backend-{dev,staging}` and their `-plan` partners. The tf-poc pair +does not exist. Two independent CDK contexts make each transition explicit: +`enableShocBackendPocRoles` and `enableShocBackendLiveRoles`. Both are +version-controlled as `false` in `cdk.json` for the initial rollout. +`terraform-substrate-external-dev` is deliberately absent from the automatic +external-dev deploy job during this sequence; `external-dev-baseline` remains +automatic and unchanged. + +1. Create the role-free base stack: + + ```bash + npx cdk deploy terraform-substrate-external-dev \ + -c enableShocBackendPocRoles=false \ + -c enableShocBackendLiveRoles=false + ``` + + `CreateOIDCProvider=false` is fixed in `bin/app.ts`; the external-dev + account therefore creates neither the existing provider, SHOC roles, nor + the prod/dev-only shared IAM policy. The base stack does create all six + retained external-dev deploy/runtime boundary policies. +2. Set `enableShocBackendPocRoles` to `true` in `cdk.json`, leave the live gate + `false`, review the synthesized two-role addition, then run the normal + external-dev stack update. This creates only the new tf-poc HCP plan/apply + pair. The retained POC CDK stack references + `shoc-backend-tf-poc-deploy-boundary` when it creates + `githubdeploy-shoc-backend-tf-poc` and + `shoc-backend-tf-poc-runtime-boundary` when it creates the POC runtime + role; do not attach the generic account execution boundary to either role. +3. Prove both tf-poc HCP assumptions and the retained POC import rehearsal + before touching the live-role ownership boundary. +4. In a separately approved administrator/CDK migration, tag the existing HCP + apply roles first: + `hcptf-shoc-backend-dev` gets + `HcpTerraformWorkspace=shoc-backend-dev`, and + `hcptf-shoc-backend-staging` gets + `HcpTerraformWorkspace=shoc-backend-staging`. Next attach + `shoc-backend-dev-deploy-boundary` and + `shoc-backend-staging-deploy-boundary` to the exact `githubdeploy-*` roles, + and attach `shoc-backend-dev-runtime-boundary` / + `shoc-backend-staging-runtime-boundary` to the exact runtime roles. Verify + the boundary ceilings before adding the matching manager tag to either + target `githubdeploy-*` role. The POC CDK + creates its deploy role with `HcpTerraformWorkspace=shoc-backend-tf-poc`; + the substrate-created POC apply role already carries the same principal + tag. Verify each effective deployment action before continuing. HCP remains + blocked while a target tag is missing/different or the target lacks its + exact dedicated boundary, so a partial migration cannot authorize policy + writes. Complete both runtime/deploy boundary attachments before workload + imports. HCP apply roles deliberately have no + `iam:PutRolePermissionsBoundary` or boundary-policy mutation permissions. +5. In the backend bootstrap, add Terraform `removed` blocks with + `destroy = false` for only the four dev/staging HCP roles and their inline + policies. Apply and verify Terraform state no longer owns them while all + four physical roles and ARNs remain unchanged. +6. Set both contexts to `true`, synthesize with + `npx cdk synth terraform-substrate-external-dev`, and create a + CloudFormation **IMPORT** change set for the four existing + `AWS::IAM::Role` resources by exact role name. Do not run a normal + CREATE/UPDATE change set for this ownership transition. The POC gate must + remain true so the already-managed pair stays in the template. Import + records ownership; it does not update existing role properties or inline + policies. +7. Run a separate, reviewed CloudFormation reconcile update after import and + before switching workspace credentials. Each current live role has one + inline policy: `shoc-backend-dev-import-plan`, + `shoc-backend-dev-import-apply`, + `shoc-backend-staging-import-plan`, or + `shoc-backend-staging-import-apply`. Existing descriptions and tags are + inventoried in the backend handoff. Reconcile those explicit differences + to the final baseline shape without replacing a role. +8. After reconcile and HCP assumption proof, keep both context values committed + as `true`. Every subsequent normal deployment must synthesize all six + roles. Never return either gate to false as a rollback mechanism; Retain + protects the physical role but removing it from the stack abandons + CloudFormation ownership. +9. Only after all imports/reconciliation complete and both context defaults + are permanently `true`, add `terraform-substrate-external-dev` back to the + external-dev workflow stack selector. Until then all substrate operations + are deliberate manual deploy/import actions. +10. Retire the backend bootstrap only after the POC pair and all four imported + live roles are proven under this stack. Role deletion/recreation is never a + migration step. + +The external-dev apply roles intentionally omit role create/delete, +managed-policy attach/detach, trust or boundary mutation, `iam:PassRole`, and +secret-value APIs. IAM writes are limited to exact-role inline-policy and +ordinary tag updates plus exact-profile tags; role descriptions remain stable +and HCP receives no `UpdateRole` or `UpdateRoleDescription`. The SCP permits +only the three enumerated HCP apply roles to mutate a `githubdeploy-*` role +whose locked `HcpTerraformWorkspace` resource tag equals the caller's immutable +principal tag. Adding or changing that manager tag remains administrator/CDK +only. POC DNS and certificate access is tag/name constrained because their +physical IDs are allocated by the temporary retained CDK stack before +Terraform imports them. Dev and staging DNS writes are pinned to their existing +hosted-zone IDs and API record names. + +Current compact policy-document sizes are 1,387 / 1,873 / 1,844 characters for +the POC/dev/staging deploy boundaries and 1,176 / 1,779 / 1,656 for their +runtime boundaries, each below IAM's 6,144-character managed-policy limit. The +external-dev IAM guardrail SCP is 4,922 compact characters against its +5,120-character Organizations limit; keep size assertions in every change. + **HCP Terraform layout (org-level setup, console):** one org `seahaven` (free tier: 500 managed resources, 1 concurrent run); one HCP **project per AWS account** (`seahaven-prod`, `seahaven-dev`); one **workspace per stack** diff --git a/bin/app.ts b/bin/app.ts index b42a902..6dc8911 100644 --- a/bin/app.ts +++ b/bin/app.ts @@ -31,6 +31,13 @@ const PROD_VPC_IDS = [ const app = new cdk.App(); +const contextBoolean = (key: string): boolean => { + const value = app.node.tryGetContext(key); + if (value === true || value === "true") return true; + if (value === false || value === "false" || value === undefined) return false; + throw new Error(`${key} must be true or false`); +}; + new AccountBaselineStack(app, "account-baseline", { stackName: "seahaven-account-baseline", env: { account: ACCOUNT, region: "us-east-1" }, @@ -190,8 +197,10 @@ const deploySubstrateDev = new DeploySubstrateStack(app, "deploy-substrate-dev", // OIDC provider + the shared boundary-gated guardrail policy // (seahaven-hcptf-iam-management) that per-workspace apply roles attach. // Per-workspace hcptf-* roles are appended to the template at each stack's -// migration time, never here. prod/dev ONLY — mgmt stays SAM (Terraform POC -// decision 2026-07-30; the mgmt POC substrate was rolled back the same day). +// migration time, never here. prod/dev/external-dev ONLY — mgmt stays SAM +// (Terraform POC decision 2026-07-30; the mgmt POC substrate was rolled back +// the same day). External-dev references its existing provider and uses +// workload-specific inline policies instead of the shared IAM manager. // The guardrail policy names the seahaven-lambda-execution-boundary ARN only // inside Condition strings, so CFN infers no creation edge — the explicit // dependency below guarantees the deploy-substrate stack (which owns the @@ -227,6 +236,21 @@ const terraformSubstrateDev = new TerraformSubstrateStack( ); terraformSubstrateDev.addStackDependency(deploySubstrateDev); +// External-dev already has app.terraform.io federation. Both role gates start +// false in cdk.json: POC is enabled by a normal update; dev/staging only by +// CloudFormation import after Terraform relinquishes those four live roles. +const terraformSubstrateExternalDev = new TerraformSubstrateStack( + app, + "terraform-substrate-external-dev", + { + stackName: "seahaven-terraform-substrate", + env: { account: EXTERNAL_DEV_ACCOUNT, region: "us-east-1" }, + createOidcProvider: false, + enableShocBackendPocRoles: contextBoolean("enableShocBackendPocRoles"), + enableShocBackendLiveRoles: contextBoolean("enableShocBackendLiveRoles"), + }, +); + // ── Shared DynamoDB CMK (INFRA-95 / M-3) ───────────────────────────────────── // Dedicated, standalone stack so the customer-managed key for sensitive // finance/PII DynamoDB tables is an independent shared dependency for the owning diff --git a/cdk.json b/cdk.json index 011d8a5..729caac 100644 --- a/cdk.json +++ b/cdk.json @@ -17,6 +17,8 @@ "context": { "@aws-cdk/aws-lambda:recognizeLayerVersion": true, "@aws-cdk/core:checkSecretUsage": true, - "@aws-cdk/core:target-partitions": ["aws"] + "@aws-cdk/core:target-partitions": ["aws"], + "enableShocBackendPocRoles": false, + "enableShocBackendLiveRoles": false } } diff --git a/lib/scp/external-dev-iam-guardrails.json b/lib/scp/external-dev-iam-guardrails.json index f85148f..3e049c3 100644 --- a/lib/scp/external-dev-iam-guardrails.json +++ b/lib/scp/external-dev-iam-guardrails.json @@ -12,11 +12,18 @@ } }, { - "Sid": "ProtectBoundaryPolicyFromEdits", + "Sid": "ProtectExecutionBoundary", "Effect": "Deny", "Action": ["iam:CreatePolicyVersion", "iam:SetDefaultPolicyVersion", "iam:DeletePolicy", "iam:DeletePolicyVersion"], "Resource": "arn:aws:iam::396287094661:policy/external-dev-execution-boundary" }, + { + "Sid": "ProtectShocBoundaries", + "Effect": "Deny", + "Action": ["iam:CreatePolicyVersion", "iam:SetDefaultPolicyVersion", "iam:DeletePolicy", "iam:DeletePolicyVersion"], + "Resource": "arn:aws:iam::396287094661:policy/shoc-backend-*-boundary", + "Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*"] } } + }, { "Sid": "DenyAlteringPermissionsBoundaries", "Effect": "Deny", @@ -32,18 +39,61 @@ "Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole"] } } }, { - "Sid": "ProtectPrivilegedRoles", + "Sid": "ProtectNonGithubPrivilegedRoles", "Effect": "Deny", "Action": ["iam:UpdateAssumeRolePolicy", "iam:AttachRolePolicy", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:DeleteRolePolicy", "iam:DeleteRole", "iam:UpdateRole", "iam:TagRole", "iam:UntagRole"], "Resource": [ "arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*", - "arn:aws:iam::396287094661:role/githubdeploy-*", "arn:aws:iam::396287094661:role/seahaven-extdev-config-recorder-role", "arn:aws:iam::396287094661:role/seahaven-extdev-config-custom-resource-role", "arn:aws:iam::396287094661:role/aws-service-role/*" ], "Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*"] } } + }, + { + "Sid": "ProtectDeploymentPrincipalLifecycle", + "Effect": "Deny", + "Action": ["iam:UpdateAssumeRolePolicy", "iam:AttachRolePolicy", "iam:DetachRolePolicy", "iam:DeleteRolePolicy", "iam:DeleteRole", "iam:UpdateRole", "iam:UpdateRoleDescription", "iam:PutRolePermissionsBoundary", "iam:DeleteRolePermissionsBoundary"], + "Resource": ["arn:aws:iam::396287094661:role/githubdeploy-*", "arn:aws:iam::396287094661:role/hcptf-*"], + "Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*"] } } + }, + { + "Sid": "ProtectGithubRoleMetadata", + "Effect": "Deny", + "Action": ["iam:PutRolePolicy", "iam:TagRole", "iam:UntagRole"], + "Resource": "arn:aws:iam::396287094661:role/githubdeploy-*", + "Condition": { "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*", "arn:aws:iam::396287094661:role/hcptf-shoc-backend-tf-poc", "arn:aws:iam::396287094661:role/hcptf-shoc-backend-dev", "arn:aws:iam::396287094661:role/hcptf-shoc-backend-staging"] } } + }, + { + "Sid": "DenyUnmanagedGithubRole", + "Effect": "Deny", + "Action": ["iam:PutRolePolicy", "iam:TagRole", "iam:UntagRole"], + "Resource": "arn:aws:iam::396287094661:role/githubdeploy-*", + "Condition": { + "ArnLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/hcptf-shoc-backend-tf-poc", "arn:aws:iam::396287094661:role/hcptf-shoc-backend-dev", "arn:aws:iam::396287094661:role/hcptf-shoc-backend-staging"] }, + "Null": { "aws:ResourceTag/HcpTerraformWorkspace": "true" } + } + }, + { + "Sid": "EnforceGithubRoleManagerTag", + "Effect": "Deny", + "Action": ["iam:PutRolePolicy", "iam:TagRole", "iam:UntagRole"], + "Resource": "arn:aws:iam::396287094661:role/githubdeploy-*", + "Condition": { + "ArnLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/hcptf-shoc-backend-tf-poc", "arn:aws:iam::396287094661:role/hcptf-shoc-backend-dev", "arn:aws:iam::396287094661:role/hcptf-shoc-backend-staging"] }, + "StringNotEquals": { "aws:ResourceTag/HcpTerraformWorkspace": "${aws:PrincipalTag/HcpTerraformWorkspace}" } + } + }, + { + "Sid": "LockHcpTerraformWorkspaceTag", + "Effect": "Deny", + "Action": ["iam:TagRole", "iam:UntagRole"], + "Resource": "arn:aws:iam::396287094661:role/*", + "Condition": { + "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::396287094661:role/OrganizationAccountAccessRole", "arn:aws:iam::396287094661:role/cdk-hnb659fds-*"] }, + "ForAnyValue:StringEquals": { "aws:TagKeys": "HcpTerraformWorkspace" } + } } ] } diff --git a/lib/terraform-substrate-stack.ts b/lib/terraform-substrate-stack.ts index b7a1e58..c70adfa 100644 --- a/lib/terraform-substrate-stack.ts +++ b/lib/terraform-substrate-stack.ts @@ -17,14 +17,26 @@ export interface TerraformSubstrateStackProps extends cdk.StackProps { * remove the orphaned provider or redeploy with this false. */ createOidcProvider?: boolean; + + /** + * Enable the two SHOC backend tf-poc HCP roles. Defaults false so the + * external-dev base-stack create is role-free. + */ + enableShocBackendPocRoles?: boolean; + + /** + * Enable the four existing SHOC backend dev/staging HCP roles. Defaults + * false because these names must enter the stack through CloudFormation + * resource import, never a normal create/update. + */ + enableShocBackendLiveRoles?: boolean; } /** - * Per-account HCP Terraform deploy substrate: the shared account-level - * resources every Terraform workspace pipeline needs - - * - app.terraform.io OIDC identity provider (conditional, see props), and - * - `seahaven-hcptf-iam-management`, the shared boundary-gated IAM - * guardrail policy every per-workspace APPLY role attaches. + * Per-account HCP Terraform deploy substrate: the conditional + * app.terraform.io OIDC provider, the prod/dev shared boundary-gated IAM + * manager, and reviewed per-workspace role pairs. External-dev conditions out + * the shared manager and uses exact inline policies for its SHOC import roles. * * Deliberately NOT here: per-workspace hcptf- / hcptf--plan * roles. Those are appended to the template at each stack's migration time @@ -58,6 +70,10 @@ export class TerraformSubstrateStack extends cdk.Stack { ), parameters: { CreateOIDCProvider: props?.createOidcProvider === false ? "false" : "true", + EnableShocBackendPocRoles: + props?.enableShocBackendPocRoles === true ? "true" : "false", + EnableShocBackendLiveRoles: + props?.enableShocBackendLiveRoles === true ? "true" : "false", }, }); diff --git a/lib/terraform-substrate/terraform-substrate.template.yaml b/lib/terraform-substrate/terraform-substrate.template.yaml index a478aa7..c01b89a 100644 --- a/lib/terraform-substrate/terraform-substrate.template.yaml +++ b/lib/terraform-substrate/terraform-substrate.template.yaml @@ -2,9 +2,9 @@ AWSTemplateFormatVersion: "2010-09-09" Description: >- Per-account HCP Terraform deploy substrate for Sea Haven Industries: the app.terraform.io OIDC identity provider and the shared boundary-gated - IAM guardrail policy that every per-workspace Terraform APPLY role attaches. - Per-workspace hcptf-* roles are NOT pre-provisioned — they are appended to - this template at each stack's migration time. + IAM guardrail policy used by prod/dev apply roles, plus exact per-workspace + role pairs appended at each stack's migration time. External-dev SHOC roles + use environment-scoped inline policies instead of the shared IAM manager. # PROVENANCE / DESIGN SOURCE # Authored fresh 2026-07-30 (the mgmt Terraform POC's CLI-created provider and @@ -91,7 +91,9 @@ Description: >- # - hcptf--plan: read-only (ViewOnlyAccess-class), trust sub # organization:seahaven:project:seahaven-:workspace::run_phase:plan # - hcptf-: apply role attaching HcptfIamManagementPolicy plus -# stack-scoped service statements, trust sub ...run_phase:apply +# stack-scoped service statements, trust sub ...run_phase:apply. An account +# with incompatible guardrails may use a reviewed, exact inline policy +# instead, as the external-dev SHOC import roles do below. # All subs are exact StringEquals (never StringLike, never a wildcarded # run_phase — a speculative PR plan must never hold write credentials); # audience is aws.workload.identity. IAM role additions here are a mandatory @@ -102,8 +104,8 @@ Description: >- # This template is deployed via lib/terraform-substrate-stack.ts # (cloudformation-include) as stack seahaven-terraform-substrate, once per # member account that hosts Terraform-managed workloads (currently -# seahaven-prod 011934824531 and seahaven-dev 710827005802; NEVER mgmt — -# mgmt stays SAM until its stacks migrate out). +# seahaven-prod 011934824531, seahaven-dev 710827005802, and external-dev +# 396287094661; NEVER mgmt — mgmt stays SAM until its stacks migrate out). Parameters: CreateOIDCProvider: @@ -121,6 +123,21 @@ Parameters: arn:aws:iam:::oidc-provider/app.terraform.io` before retrying, or redeploy with this parameter false. Same idempotency affordance the sibling deploy-substrate template carries for the GitHub provider. + EnableShocBackendPocRoles: + Type: String + Default: "false" + AllowedValues: ["true", "false"] + Description: >- + External-dev tf-poc gate. Keep false for the base-stack create, then set + true on the reviewed normal update that creates the new tf-poc role pair. + EnableShocBackendLiveRoles: + Type: String + Default: "false" + AllowedValues: ["true", "false"] + Description: >- + External-dev live-role collision guard. Keep false until the four existing + dev/staging roles have been removed from Terraform state with destroy=false. + Set true only in the CloudFormation IMPORT change set that adopts them. Conditions: ShouldCreateOIDCProvider: !Equals [!Ref CreateOIDCProvider, "true"] @@ -128,6 +145,16 @@ Conditions: # exist in seahaven-prod. The same template deploys to seahaven-dev; creating # prod-workspace trust there would leave dead credentials in the wrong account. IsProdAccount: !Equals [!Ref "AWS::AccountId", "011934824531"] + IsExternalDevAccount: !Equals [!Ref "AWS::AccountId", "396287094661"] + IsSharedIamManagementAccount: !Or + - !Equals [!Ref "AWS::AccountId", "011934824531"] + - !Equals [!Ref "AWS::AccountId", "710827005802"] + ShouldManageShocBackendPocRoles: !And + - !Condition IsExternalDevAccount + - !Equals [!Ref EnableShocBackendPocRoles, "true"] + ShouldManageShocBackendLiveRoles: !And + - !Condition IsExternalDevAccount + - !Equals [!Ref EnableShocBackendLiveRoles, "true"] Resources: @@ -180,6 +207,7 @@ Resources: # --------------------------------------------------------------------------- HcptfIamManagementPolicy: Type: AWS::IAM::ManagedPolicy + Condition: IsSharedIamManagementAccount Properties: # Fixed name: future hcptf-* roles reference it by ARN, and a rename # would detach-and-replace mid-update. Treat a rename as a coordinated @@ -2531,3 +2559,971 @@ Resources: } ] } + + # --------------------------------------------------------------------------- + # SHOC backend GitHub deployment permissions boundaries (external-dev only) + # + # These are ceilings for the three exact githubdeploy roles, not grants. + # Existing dev/staging roles receive them through a separately approved + # administrator/CDK action before HCP import. The retained POC CDK stack + # attaches its boundary when it creates the POC deploy role. + # --------------------------------------------------------------------------- + ShocBackendPocDeployBoundary: + Type: AWS::IAM::ManagedPolicy + Condition: IsExternalDevAccount + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + ManagedPolicyName: shoc-backend-tf-poc-deploy-boundary + Description: Maximum deployment permissions for githubdeploy-shoc-backend-tf-poc. + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: DescribeDeploymentResources + Effect: Allow + Action: + - autoscaling:Describe* + - ec2:Describe* + - elasticbeanstalk:DescribeApplicationVersions + - elasticbeanstalk:DescribeEnvironments + - elasticbeanstalk:DescribeEvents + - elasticloadbalancing:Describe* + Resource: "*" + - Sid: CreateApplicationVersion + Effect: Allow + Action: elasticbeanstalk:CreateApplicationVersion + Resource: + - arn:aws:elasticbeanstalk:us-east-1:396287094661:application/shoc-backend + - arn:aws:elasticbeanstalk:us-east-1:396287094661:applicationversion/shoc-backend/* + - Sid: UpdatePocEnvironment + Effect: Allow + Action: elasticbeanstalk:UpdateEnvironment + Resource: arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-tf-poc + - Sid: UseBeanstalkBucket + Effect: Allow + Action: + - s3:GetBucketLocation + - s3:ListBucket + Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 + - Sid: UploadApplicationVersion + Effect: Allow + Action: s3:PutObject + Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/shoc-backend/* + - Sid: DenyLiveEnvironments + Effect: Deny + Action: elasticbeanstalk:* + Resource: + - arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-dev + - arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-staging + + ShocBackendDevDeployBoundary: + Type: AWS::IAM::ManagedPolicy + Condition: IsExternalDevAccount + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + ManagedPolicyName: shoc-backend-dev-deploy-boundary + Description: Maximum deployment permissions for githubdeploy-shoc-backend-dev. + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: DescribeDeploymentResources + Effect: Allow + Action: + - autoscaling:Describe* + - ec2:Describe* + - elasticbeanstalk:DescribeApplicationVersions + - elasticbeanstalk:DescribeEnvironments + - elasticbeanstalk:DescribeEvents + - elasticloadbalancing:Describe* + Resource: "*" + - Sid: CreateApplicationVersion + Effect: Allow + Action: elasticbeanstalk:CreateApplicationVersion + Resource: + - arn:aws:elasticbeanstalk:us-east-1:396287094661:application/shoc-backend + - arn:aws:elasticbeanstalk:us-east-1:396287094661:applicationversion/shoc-backend/* + - Sid: UpdateDevEnvironment + Effect: Allow + Action: elasticbeanstalk:UpdateEnvironment + Resource: arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-dev + - Sid: ManageDevEnvironmentStack + Effect: Allow + Action: + - cloudformation:CancelUpdateStack + - cloudformation:DescribeStackEvents + - cloudformation:DescribeStackResource + - cloudformation:DescribeStackResources + - cloudformation:DescribeStacks + - cloudformation:GetTemplate + - cloudformation:ListStackResources + - cloudformation:UpdateStack + Resource: arn:aws:cloudformation:us-east-1:396287094661:stack/awseb-e-hehnrqjjrt-stack/* + - Sid: ManageDevEnvironmentAsg + Effect: Allow + Action: + - autoscaling:PutNotificationConfiguration + - autoscaling:ResumeProcesses + - autoscaling:SuspendProcesses + Resource: arn:aws:autoscaling:us-east-1:396287094661:autoScalingGroup:*:autoScalingGroupName/awseb-e-hehnrqjjrt-stack-* + - Sid: LegacyBeanstalkObjects + Effect: Allow + Action: + - s3:Delete* + - s3:Get* + - s3:Put* + Resource: arn:aws:s3:::elasticbeanstalk-*/* + - Sid: LegacyBeanstalkBuckets + Effect: Allow + Action: + - s3:GetBucket* + - s3:ListBucket + - s3:PutBucketOwnershipControls + - s3:PutBucketPolicy + - s3:PutBucketPublicAccessBlock + Resource: arn:aws:s3:::elasticbeanstalk-* + + ShocBackendStagingDeployBoundary: + Type: AWS::IAM::ManagedPolicy + Condition: IsExternalDevAccount + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + ManagedPolicyName: shoc-backend-staging-deploy-boundary + Description: Maximum deployment permissions for githubdeploy-shoc-backend-staging. + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: DescribeDeploymentResources + Effect: Allow + Action: + - autoscaling:Describe* + - ec2:Describe* + - elasticbeanstalk:DescribeApplicationVersions + - elasticbeanstalk:DescribeEnvironments + - elasticbeanstalk:DescribeEvents + - elasticloadbalancing:Describe* + Resource: "*" + - Sid: CreateApplicationVersion + Effect: Allow + Action: elasticbeanstalk:CreateApplicationVersion + Resource: + - arn:aws:elasticbeanstalk:us-east-1:396287094661:application/shoc-backend + - arn:aws:elasticbeanstalk:us-east-1:396287094661:applicationversion/shoc-backend/* + - Sid: UpdateStagingEnvironment + Effect: Allow + Action: elasticbeanstalk:UpdateEnvironment + Resource: arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-staging + - Sid: ManageStagingEnvironmentStack + Effect: Allow + Action: + - cloudformation:CancelUpdateStack + - cloudformation:DescribeStackEvents + - cloudformation:DescribeStackResource + - cloudformation:DescribeStackResources + - cloudformation:DescribeStacks + - cloudformation:GetTemplate + - cloudformation:ListStackResources + - cloudformation:UpdateStack + Resource: arn:aws:cloudformation:us-east-1:396287094661:stack/awseb-e-6c9m4vb62z-stack/* + - Sid: ManageStagingEnvironmentAsg + Effect: Allow + Action: + - autoscaling:PutNotificationConfiguration + - autoscaling:ResumeProcesses + - autoscaling:SuspendProcesses + Resource: arn:aws:autoscaling:us-east-1:396287094661:autoScalingGroup:*:autoScalingGroupName/awseb-e-6c9m4vb62z-stack-* + - Sid: UploadApplicationVersion + Effect: Allow + Action: s3:PutObject + Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/shoc-backend/* + - Sid: UseBeanstalkBucket + Effect: Allow + Action: + - s3:GetBucketLocation + - s3:ListBucket + Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 + + # Dedicated runtime ceilings preserve the non-AI portions of + # AWSElasticBeanstalkWebTier while removing its 2026 Bedrock/Marketplace + # additions. All S3/log/health resources are pinned to this account and the + # exact SHOC environment; X-Ray APIs do not support resource scoping. + ShocBackendPocRuntimeBoundary: + Type: AWS::IAM::ManagedPolicy + Condition: IsExternalDevAccount + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + ManagedPolicyName: shoc-backend-tf-poc-runtime-boundary + Description: Maximum runtime permissions for the SHOC backend tf-poc instance role. + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: ReadAppConfig + Effect: Allow + Action: secretsmanager:GetSecretValue + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/tf-poc/app-config-* + - Sid: ElasticBeanstalkBucket + Effect: Allow + Action: + - s3:Get* + - s3:List* + - s3:PutObject + Resource: + - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 + - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/* + - Sid: ElasticBeanstalkHealth + Effect: Allow + Action: elasticbeanstalk:PutInstanceStatistics + Resource: + - arn:aws:elasticbeanstalk:us-east-1:396287094661:application/shoc-backend + - arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-tf-poc + - Sid: ElasticBeanstalkLogs + Effect: Allow + Action: + - logs:PutLogEvents + - logs:CreateLogStream + - logs:DescribeLogStreams + - logs:DescribeLogGroups + Resource: arn:aws:logs:us-east-1:396287094661:log-group:/aws/elasticbeanstalk/shoc-backend-tf-poc* + - Sid: XRayTelemetry + Effect: Allow + Action: + - xray:PutTraceSegments + - xray:PutTelemetryRecords + - xray:GetSamplingRules + - xray:GetSamplingTargets + - xray:GetSamplingStatisticSummaries + Resource: "*" + + ShocBackendDevRuntimeBoundary: + Type: AWS::IAM::ManagedPolicy + Condition: IsExternalDevAccount + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + ManagedPolicyName: shoc-backend-dev-runtime-boundary + Description: Maximum runtime permissions for the SHOC backend dev instance role. + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: ReadAppConfig + Effect: Allow + Action: secretsmanager:GetSecretValue + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/dev/app-config-* + - Sid: ReadWebhookSecret + Effect: Allow + Action: + - secretsmanager:DescribeSecret + - secretsmanager:GetSecretValue + Resource: arn:aws:secretsmanager:us-east-1:011934824531:secret:workorder-ingest/shoc-webhook-hmac-puYTcB + - Sid: DecryptWebhookSecret + Effect: Allow + Action: kms:Decrypt + Resource: arn:aws:kms:us-east-1:011934824531:key/d10fd1f0-a61a-4405-8568-85e9fd11ba18 + Condition: + StringEquals: + "kms:ViaService": secretsmanager.us-east-1.amazonaws.com + - Sid: AssumeDynamoReader + Effect: Allow + Action: sts:AssumeRole + Resource: arn:aws:iam::328440206208:role/shoc-dynamo-reader + - Sid: ElasticBeanstalkBucket + Effect: Allow + Action: + - s3:Get* + - s3:List* + - s3:PutObject + Resource: + - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 + - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/* + - Sid: ElasticBeanstalkHealth + Effect: Allow + Action: elasticbeanstalk:PutInstanceStatistics + Resource: + - arn:aws:elasticbeanstalk:us-east-1:396287094661:application/shoc-backend + - arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-dev + - Sid: ElasticBeanstalkLogs + Effect: Allow + Action: + - logs:PutLogEvents + - logs:CreateLogStream + - logs:DescribeLogStreams + - logs:DescribeLogGroups + Resource: arn:aws:logs:us-east-1:396287094661:log-group:/aws/elasticbeanstalk/shoc-backend-dev* + - Sid: XRayTelemetry + Effect: Allow + Action: + - xray:PutTraceSegments + - xray:PutTelemetryRecords + - xray:GetSamplingRules + - xray:GetSamplingTargets + - xray:GetSamplingStatisticSummaries + Resource: "*" + + ShocBackendStagingRuntimeBoundary: + Type: AWS::IAM::ManagedPolicy + Condition: IsExternalDevAccount + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + ManagedPolicyName: shoc-backend-staging-runtime-boundary + Description: Maximum runtime permissions for the SHOC backend staging instance role. + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: ReadAppConfig + Effect: Allow + Action: secretsmanager:GetSecretValue + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/staging/app-config-* + - Sid: ReadWebhookSecret + Effect: Allow + Action: + - secretsmanager:DescribeSecret + - secretsmanager:GetSecretValue + Resource: arn:aws:secretsmanager:us-east-1:011934824531:secret:workorder-ingest/shoc-webhook-hmac-puYTcB + - Sid: DecryptWebhookSecret + Effect: Allow + Action: kms:Decrypt + Resource: arn:aws:kms:us-east-1:011934824531:key/d10fd1f0-a61a-4405-8568-85e9fd11ba18 + Condition: + StringEquals: + "kms:ViaService": secretsmanager.us-east-1.amazonaws.com + - Sid: ElasticBeanstalkBucket + Effect: Allow + Action: + - s3:Get* + - s3:List* + - s3:PutObject + Resource: + - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 + - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/* + - Sid: ElasticBeanstalkHealth + Effect: Allow + Action: elasticbeanstalk:PutInstanceStatistics + Resource: + - arn:aws:elasticbeanstalk:us-east-1:396287094661:application/shoc-backend + - arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-staging + - Sid: ElasticBeanstalkLogs + Effect: Allow + Action: + - logs:PutLogEvents + - logs:CreateLogStream + - logs:DescribeLogStreams + - logs:DescribeLogGroups + Resource: arn:aws:logs:us-east-1:396287094661:log-group:/aws/elasticbeanstalk/shoc-backend-staging* + - Sid: XRayTelemetry + Effect: Allow + Action: + - xray:PutTraceSegments + - xray:PutTelemetryRecords + - xray:GetSamplingRules + - xray:GetSamplingTargets + - xray:GetSamplingStatisticSummaries + Resource: "*" + + # --------------------------------------------------------------------------- + # shoc-backend import/adoption rehearsal (external-dev only) + # + # These roles intentionally do not attach HcptfIamManagementPolicy. Its + # DenySelfMutation protects every githubdeploy-* role, while this rehearsal + # must adopt three exact githubdeploy roles. Each apply role instead carries + # an environment-scoped inline policy. No apply role can create/delete roles, + # change managed-policy attachments or trust/boundaries, read/write secret + # values, or pass a role. The POC gate controls its new pair independently; + # the live gate stays false until the four existing dev/staging roles enter + # through a CloudFormation IMPORT change set. + # + # The existing app.terraform.io provider is referenced by literal ARN. The + # stack instance sets CreateOIDCProvider=false, so external-dev never attempts + # to create the account-global provider. + # --------------------------------------------------------------------------- + HcptfShocBackendPocPlanRole: + Type: AWS::IAM::Role + Condition: ShouldManageShocBackendPocRoles + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + RoleName: hcptf-shoc-backend-tf-poc-plan + Description: Read-only HCP Terraform plan role for the SHOC backend import rehearsal. + PermissionsBoundary: arn:aws:iam::396287094661:policy/external-dev-execution-boundary + MaxSessionDuration: 3600 + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Federated: arn:aws:iam::396287094661:oidc-provider/app.terraform.io + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + "app.terraform.io:aud": aws.workload.identity + "app.terraform.io:sub": organization:seahaven:project:seahaven-external-dev:workspace:shoc-backend-tf-poc:run_phase:plan + Policies: + - &shocPocReadPolicy + PolicyName: shoc-backend-tf-poc-import-read + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: CallerIdentity + Effect: Allow + Action: sts:GetCallerIdentity + Resource: "*" + - Sid: ReadExactIam + Effect: Allow + Action: + - iam:GetInstanceProfile + - iam:GetRole + - iam:GetRolePolicy + - iam:ListAttachedRolePolicies + - iam:ListInstanceProfileTags + - iam:ListInstanceProfilesForRole + - iam:ListRolePolicies + - iam:ListRoleTags + Resource: + - arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-tf-poc + - arn:aws:iam::396287094661:role/shoc-backend-tf-poc + - arn:aws:iam::396287094661:instance-profile/shoc-backend-tf-poc + - arn:aws:iam::396287094661:role/shoc-eb-service-role + - Sid: ReadOidcProviders + Effect: Allow + Action: iam:GetOpenIDConnectProvider + Resource: + - arn:aws:iam::396287094661:oidc-provider/app.terraform.io + - arn:aws:iam::396287094661:oidc-provider/token.actions.githubusercontent.com + - Sid: ListOidcProviders + Effect: Allow + Action: iam:ListOpenIDConnectProviders + Resource: "*" + - Sid: ReadSharedInventory + Effect: Allow + Action: + - acm:ListCertificates + - ec2:DescribeSecurityGroups + - ec2:DescribeSubnets + - ec2:DescribeVpcs + - elasticbeanstalk:DescribeApplications + - elasticbeanstalk:DescribeConfigurationOptions + - elasticbeanstalk:DescribeConfigurationSettings + - elasticbeanstalk:DescribeEnvironmentResources + - elasticbeanstalk:DescribeEnvironments + - elasticbeanstalk:ListTagsForResource + - rds:DescribeDBInstances + - route53:ListHostedZonesByName + Resource: "*" + - Sid: ReadSharedCertificate + Effect: Allow + Action: + - acm:DescribeCertificate + - acm:ListTagsForCertificate + Resource: arn:aws:acm:us-east-1:396287094661:certificate/2b78e74f-7b65-4b82-a413-7a498b102f00 + - Sid: ReadPocCertificate + Effect: Allow + Action: + - acm:DescribeCertificate + - acm:GetCertificate + - acm:ListTagsForCertificate + Resource: arn:aws:acm:us-east-1:396287094661:certificate/* + Condition: + StringEquals: + "aws:ResourceTag/Project": shoc-backend + "aws:ResourceTag/Environment": tf-poc + - Sid: ReadSharedRdsTags + Effect: Allow + Action: rds:ListTagsForResource + Resource: arn:aws:rds:us-east-1:396287094661:db:shoc-sqlserver-shared + - Sid: ReadPocDns + Effect: Allow + Action: + - route53:GetHostedZone + - route53:ListResourceRecordSets + - route53:ListTagsForResource + Resource: arn:aws:route53:::hostedzone/* + Condition: + StringEquals: + "aws:ResourceTag/Project": shoc-backend + "aws:ResourceTag/Environment": tf-poc + - Sid: ReadRoute53Changes + Effect: Allow + Action: route53:GetChange + Resource: arn:aws:route53:::change/* + - Sid: ReadPocAppConfigMetadata + Effect: Allow + Action: + - secretsmanager:DescribeSecret + - secretsmanager:GetResourcePolicy + - secretsmanager:ListSecretVersionIds + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/tf-poc/app-config-* + + HcptfShocBackendPocApplyRole: + Type: AWS::IAM::Role + Condition: ShouldManageShocBackendPocRoles + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + RoleName: hcptf-shoc-backend-tf-poc + Description: Import/adoption HCP Terraform apply role for SHOC backend tf-poc. + Tags: + - Key: HcpTerraformWorkspace + Value: shoc-backend-tf-poc + PermissionsBoundary: arn:aws:iam::396287094661:policy/external-dev-execution-boundary + MaxSessionDuration: 3600 + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Federated: arn:aws:iam::396287094661:oidc-provider/app.terraform.io + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + "app.terraform.io:aud": aws.workload.identity + "app.terraform.io:sub": organization:seahaven:project:seahaven-external-dev:workspace:shoc-backend-tf-poc:run_phase:apply + Policies: + - *shocPocReadPolicy + - PolicyName: shoc-backend-tf-poc-import-apply + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: UpdatePocEnvironment + Effect: Allow + Action: + - elasticbeanstalk:UpdateEnvironment + - elasticbeanstalk:UpdateTagsForResource + Resource: arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-tf-poc + - Sid: PutPocRuntimePolicy + Effect: Allow + Action: iam:PutRolePolicy + Resource: arn:aws:iam::396287094661:role/shoc-backend-tf-poc + Condition: + StringEquals: + "iam:PermissionsBoundary": arn:aws:iam::396287094661:policy/shoc-backend-tf-poc-runtime-boundary + - Sid: TagPocRuntimeRole + Effect: Allow + Action: + - iam:TagRole + - iam:UntagRole + Resource: arn:aws:iam::396287094661:role/shoc-backend-tf-poc + - Sid: ManagePocInstanceProfile + Effect: Allow + Action: + - iam:TagInstanceProfile + - iam:UntagInstanceProfile + Resource: arn:aws:iam::396287094661:instance-profile/shoc-backend-tf-poc + - Sid: PutPocGithubDeployPolicy + Effect: Allow + Action: iam:PutRolePolicy + Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-tf-poc + Condition: + StringEquals: + "iam:PermissionsBoundary": arn:aws:iam::396287094661:policy/shoc-backend-tf-poc-deploy-boundary + - Sid: TagPocGithubDeployRole + Effect: Allow + Action: + - iam:TagRole + - iam:UntagRole + Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-tf-poc + - Sid: TagPocAppConfig + Effect: Allow + Action: + - secretsmanager:TagResource + - secretsmanager:UntagResource + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/tf-poc/app-config-* + - Sid: ChangePocApiAndValidationRecords + Effect: Allow + Action: route53:ChangeResourceRecordSets + Resource: arn:aws:route53:::hostedzone/* + Condition: + ForAllValues:StringLike: + "route53:ChangeResourceRecordSetsNormalizedRecordNames": + - api.tf-poc.seahaven.com + - "*.tf-poc.seahaven.com" + ForAllValues:StringEquals: + "route53:ChangeResourceRecordSetsRecordTypes": + - CNAME + - Sid: TagPocHostedZone + Effect: Allow + Action: route53:ChangeTagsForResource + Resource: arn:aws:route53:::hostedzone/* + Condition: + StringEquals: + "aws:ResourceTag/Project": shoc-backend + "aws:ResourceTag/Environment": tf-poc + - Sid: TagPocCertificate + Effect: Allow + Action: + - acm:AddTagsToCertificate + - acm:RemoveTagsFromCertificate + Resource: arn:aws:acm:us-east-1:396287094661:certificate/* + Condition: + StringEquals: + "aws:ResourceTag/Project": shoc-backend + "aws:ResourceTag/Environment": tf-poc + + HcptfShocBackendDevPlanRole: + Type: AWS::IAM::Role + Condition: ShouldManageShocBackendLiveRoles + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + RoleName: hcptf-shoc-backend-dev-plan + Description: Read-only HCP Terraform plan role for SHOC backend dev import. + PermissionsBoundary: arn:aws:iam::396287094661:policy/external-dev-execution-boundary + MaxSessionDuration: 3600 + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Federated: arn:aws:iam::396287094661:oidc-provider/app.terraform.io + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + "app.terraform.io:aud": aws.workload.identity + "app.terraform.io:sub": organization:seahaven:project:seahaven-external-dev:workspace:shoc-backend-dev:run_phase:plan + Policies: + - &shocDevReadPolicy + PolicyName: shoc-backend-dev-import-read + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: CallerIdentity + Effect: Allow + Action: sts:GetCallerIdentity + Resource: "*" + - Sid: ReadExactIam + Effect: Allow + Action: + - iam:GetInstanceProfile + - iam:GetRole + - iam:GetRolePolicy + - iam:ListAttachedRolePolicies + - iam:ListInstanceProfileTags + - iam:ListInstanceProfilesForRole + - iam:ListRolePolicies + - iam:ListRoleTags + Resource: + - arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-dev + - arn:aws:iam::396287094661:role/shoc-backend-dev + - arn:aws:iam::396287094661:instance-profile/shoc-backend-dev + - arn:aws:iam::396287094661:role/shoc-eb-service-role + - Sid: ReadGithubOidc + Effect: Allow + Action: iam:GetOpenIDConnectProvider + Resource: arn:aws:iam::396287094661:oidc-provider/token.actions.githubusercontent.com + - Sid: ListOidcProviders + Effect: Allow + Action: iam:ListOpenIDConnectProviders + Resource: "*" + - Sid: ReadSharedInventory + Effect: Allow + Action: + - acm:ListCertificates + - ec2:DescribeSecurityGroups + - ec2:DescribeSubnets + - ec2:DescribeVpcs + - elasticbeanstalk:DescribeApplications + - elasticbeanstalk:DescribeConfigurationOptions + - elasticbeanstalk:DescribeConfigurationSettings + - elasticbeanstalk:DescribeEnvironmentResources + - elasticbeanstalk:DescribeEnvironments + - elasticbeanstalk:ListTagsForResource + - rds:DescribeDBInstances + - route53:ListHostedZonesByName + Resource: "*" + - Sid: ReadSharedCertificate + Effect: Allow + Action: + - acm:DescribeCertificate + - acm:ListTagsForCertificate + Resource: arn:aws:acm:us-east-1:396287094661:certificate/2b78e74f-7b65-4b82-a413-7a498b102f00 + - Sid: ReadSharedRdsTags + Effect: Allow + Action: rds:ListTagsForResource + Resource: arn:aws:rds:us-east-1:396287094661:db:shoc-sqlserver-shared + - Sid: ReadDevDns + Effect: Allow + Action: + - route53:GetHostedZone + - route53:GetChange + - route53:ListResourceRecordSets + - route53:ListTagsForResource + Resource: + - arn:aws:route53:::hostedzone/Z07671212N75U4YLPWZR8 + - arn:aws:route53:::change/* + - Sid: ReadDevAppConfigMetadata + Effect: Allow + Action: + - secretsmanager:DescribeSecret + - secretsmanager:GetResourcePolicy + - secretsmanager:ListSecretVersionIds + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/dev/app-config-* + + HcptfShocBackendDevApplyRole: + Type: AWS::IAM::Role + Condition: ShouldManageShocBackendLiveRoles + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + RoleName: hcptf-shoc-backend-dev + Description: Import/adoption HCP Terraform apply role for SHOC backend dev. + Tags: + - Key: HcpTerraformWorkspace + Value: shoc-backend-dev + PermissionsBoundary: arn:aws:iam::396287094661:policy/external-dev-execution-boundary + MaxSessionDuration: 3600 + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Federated: arn:aws:iam::396287094661:oidc-provider/app.terraform.io + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + "app.terraform.io:aud": aws.workload.identity + "app.terraform.io:sub": organization:seahaven:project:seahaven-external-dev:workspace:shoc-backend-dev:run_phase:apply + Policies: + - *shocDevReadPolicy + - PolicyName: shoc-backend-dev-import-apply + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: UpdateDevEnvironment + Effect: Allow + Action: + - elasticbeanstalk:UpdateEnvironment + - elasticbeanstalk:UpdateTagsForResource + Resource: arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-dev + - Sid: PutDevRuntimePolicy + Effect: Allow + Action: iam:PutRolePolicy + Resource: arn:aws:iam::396287094661:role/shoc-backend-dev + Condition: + StringEquals: + "iam:PermissionsBoundary": arn:aws:iam::396287094661:policy/shoc-backend-dev-runtime-boundary + - Sid: TagDevRuntimeRole + Effect: Allow + Action: + - iam:TagRole + - iam:UntagRole + Resource: arn:aws:iam::396287094661:role/shoc-backend-dev + - Sid: ManageDevInstanceProfile + Effect: Allow + Action: + - iam:TagInstanceProfile + - iam:UntagInstanceProfile + Resource: arn:aws:iam::396287094661:instance-profile/shoc-backend-dev + - Sid: PutDevGithubDeployPolicy + Effect: Allow + Action: iam:PutRolePolicy + Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-dev + Condition: + StringEquals: + "iam:PermissionsBoundary": arn:aws:iam::396287094661:policy/shoc-backend-dev-deploy-boundary + - Sid: TagDevGithubDeployRole + Effect: Allow + Action: + - iam:TagRole + - iam:UntagRole + Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-dev + - Sid: TagDevAppConfig + Effect: Allow + Action: + - secretsmanager:TagResource + - secretsmanager:UntagResource + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/dev/app-config-* + - Sid: ChangeDevApiRecord + Effect: Allow + Action: route53:ChangeResourceRecordSets + Resource: arn:aws:route53:::hostedzone/Z07671212N75U4YLPWZR8 + Condition: + ForAllValues:StringEquals: + "route53:ChangeResourceRecordSetsNormalizedRecordNames": + - api.dev.seahaven.com + "route53:ChangeResourceRecordSetsRecordTypes": + - A + + HcptfShocBackendStagingPlanRole: + Type: AWS::IAM::Role + Condition: ShouldManageShocBackendLiveRoles + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + RoleName: hcptf-shoc-backend-staging-plan + Description: Read-only HCP Terraform plan role for SHOC backend staging import. + PermissionsBoundary: arn:aws:iam::396287094661:policy/external-dev-execution-boundary + MaxSessionDuration: 3600 + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Federated: arn:aws:iam::396287094661:oidc-provider/app.terraform.io + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + "app.terraform.io:aud": aws.workload.identity + "app.terraform.io:sub": organization:seahaven:project:seahaven-external-dev:workspace:shoc-backend-staging:run_phase:plan + Policies: + - &shocStagingReadPolicy + PolicyName: shoc-backend-staging-import-read + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: CallerIdentity + Effect: Allow + Action: sts:GetCallerIdentity + Resource: "*" + - Sid: ReadExactIam + Effect: Allow + Action: + - iam:GetInstanceProfile + - iam:GetRole + - iam:GetRolePolicy + - iam:ListAttachedRolePolicies + - iam:ListInstanceProfileTags + - iam:ListInstanceProfilesForRole + - iam:ListRolePolicies + - iam:ListRoleTags + Resource: + - arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-staging + - arn:aws:iam::396287094661:role/shoc-backend-staging + - arn:aws:iam::396287094661:instance-profile/shoc-backend-staging + - arn:aws:iam::396287094661:role/shoc-eb-service-role + - Sid: ReadGithubOidc + Effect: Allow + Action: iam:GetOpenIDConnectProvider + Resource: arn:aws:iam::396287094661:oidc-provider/token.actions.githubusercontent.com + - Sid: ListOidcProviders + Effect: Allow + Action: iam:ListOpenIDConnectProviders + Resource: "*" + - Sid: ReadSharedInventory + Effect: Allow + Action: + - acm:ListCertificates + - ec2:DescribeSecurityGroups + - ec2:DescribeSubnets + - ec2:DescribeVpcs + - elasticbeanstalk:DescribeApplications + - elasticbeanstalk:DescribeConfigurationOptions + - elasticbeanstalk:DescribeConfigurationSettings + - elasticbeanstalk:DescribeEnvironmentResources + - elasticbeanstalk:DescribeEnvironments + - elasticbeanstalk:ListTagsForResource + - rds:DescribeDBInstances + - route53:ListHostedZonesByName + Resource: "*" + - Sid: ReadSharedCertificate + Effect: Allow + Action: + - acm:DescribeCertificate + - acm:ListTagsForCertificate + Resource: arn:aws:acm:us-east-1:396287094661:certificate/2b78e74f-7b65-4b82-a413-7a498b102f00 + - Sid: ReadSharedRdsTags + Effect: Allow + Action: rds:ListTagsForResource + Resource: arn:aws:rds:us-east-1:396287094661:db:shoc-sqlserver-shared + - Sid: ReadStagingDns + Effect: Allow + Action: + - route53:GetHostedZone + - route53:GetChange + - route53:ListResourceRecordSets + - route53:ListTagsForResource + Resource: + - arn:aws:route53:::hostedzone/Z02602739VQWBWCAGXP4 + - arn:aws:route53:::change/* + - Sid: ReadStagingAppConfigMetadata + Effect: Allow + Action: + - secretsmanager:DescribeSecret + - secretsmanager:GetResourcePolicy + - secretsmanager:ListSecretVersionIds + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/staging/app-config-* + + HcptfShocBackendStagingApplyRole: + Type: AWS::IAM::Role + Condition: ShouldManageShocBackendLiveRoles + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + RoleName: hcptf-shoc-backend-staging + Description: Import/adoption HCP Terraform apply role for SHOC backend staging. + Tags: + - Key: HcpTerraformWorkspace + Value: shoc-backend-staging + PermissionsBoundary: arn:aws:iam::396287094661:policy/external-dev-execution-boundary + MaxSessionDuration: 3600 + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Federated: arn:aws:iam::396287094661:oidc-provider/app.terraform.io + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + "app.terraform.io:aud": aws.workload.identity + "app.terraform.io:sub": organization:seahaven:project:seahaven-external-dev:workspace:shoc-backend-staging:run_phase:apply + Policies: + - *shocStagingReadPolicy + - PolicyName: shoc-backend-staging-import-apply + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: UpdateStagingEnvironment + Effect: Allow + Action: + - elasticbeanstalk:UpdateEnvironment + - elasticbeanstalk:UpdateTagsForResource + Resource: arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-staging + - Sid: PutStagingRuntimePolicy + Effect: Allow + Action: iam:PutRolePolicy + Resource: arn:aws:iam::396287094661:role/shoc-backend-staging + Condition: + StringEquals: + "iam:PermissionsBoundary": arn:aws:iam::396287094661:policy/shoc-backend-staging-runtime-boundary + - Sid: TagStagingRuntimeRole + Effect: Allow + Action: + - iam:TagRole + - iam:UntagRole + Resource: arn:aws:iam::396287094661:role/shoc-backend-staging + - Sid: ManageStagingInstanceProfile + Effect: Allow + Action: + - iam:TagInstanceProfile + - iam:UntagInstanceProfile + Resource: arn:aws:iam::396287094661:instance-profile/shoc-backend-staging + - Sid: PutStagingGithubDeployPolicy + Effect: Allow + Action: iam:PutRolePolicy + Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-staging + Condition: + StringEquals: + "iam:PermissionsBoundary": arn:aws:iam::396287094661:policy/shoc-backend-staging-deploy-boundary + - Sid: TagStagingGithubDeployRole + Effect: Allow + Action: + - iam:TagRole + - iam:UntagRole + Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-staging + - Sid: TagStagingAppConfig + Effect: Allow + Action: + - secretsmanager:TagResource + - secretsmanager:UntagResource + Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/staging/app-config-* + - Sid: ChangeStagingApiRecord + Effect: Allow + Action: route53:ChangeResourceRecordSets + Resource: arn:aws:route53:::hostedzone/Z02602739VQWBWCAGXP4 + Condition: + ForAllValues:StringEquals: + "route53:ChangeResourceRecordSetsNormalizedRecordNames": + - api.staging.seahaven.com + "route53:ChangeResourceRecordSetsRecordTypes": + - CNAME