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 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 # hcptf-* roles were rolled back the same day, so there is no deployed source # to vendor). HcptfIamManagementPolicy DERIVES FROM the reviewed # seahaven-cfn-exec-iam-management pattern in # lib/deploy-substrate/deploy-substrate.template.yaml (boundary-gated # CreateRole/AttachRolePolicy/PutRolePolicy/PutRolePermissionsBoundary + # DenyBoundaryTampering / DenyBoundaryPolicyEdit / DenySelfMutation) but is # DELIBERATELY STRICTER — it is NOT a byte-identical mirror. Do not "reconcile" # the two by copying this file's statements back, or vice versa; the divergences # below are load-bearing and were required by the 2026-07-30 security review # (findings C1-C5, one confirmed critical + one high): # # 1. ROLE PATH SCOPING (review finding C2). The SAM copy's Resource # `role/*` on the boundary-gated statements is justified there by SAM # auto-generating execution roles at path / with no settable RolePath — # a path condition would break every SAM deploy. THAT RATIONALE DOES NOT # TRANSFER: Terraform's aws_iam_role supports `path` and `name_prefix`. # So every role-WRITE statement here is scoped to the Terraform-owned path # `role/tf-managed/*`. Terraform configs MUST set path = "/tf-managed/" on # every role they create; a role created anywhere else is denied. The path # is deliberately NOT `hcptf-*`, which would collide with the substrate's # own hcptf-* apply/plan roles under DenySelfMutation's wildcard. # 2. READ AND WRITE SPLIT (review findings C1, C3, C4). The SAM copy's # IAMRoleReadAndDelete grants iam:UpdateAssumeRolePolicy / DeleteRole / # DetachRolePolicy / DeleteRolePolicy / UpdateRole on Resource "*" # unconditioned — a confirmed privilege-escalation primitive (repoint the # AdministratorAccess CDK bootstrap role's trust policy, then assume it # cross-account) that DenySelfMutation's three name patterns do not cover. # Here those actions are split: reads stay on "*" (Terraform data sources # need them), every destructive/mutating action is confined to # `role/tf-managed/*`. This closes the escalation at the root instead of # chasing it with a denylist. # 3. PASSROLE SCOPING (review finding C5). The SAM copy passes any role to # Lambda (its comment claims SAM-role scoping the Resource does not # express). Here PassRole is confined to `role/tf-managed/*`, so one # workspace cannot attach another workspace's execution role to a function # it controls — that path performs no IAM write and would otherwise evade # every boundary gate and Deny in this document. # 4. DENYSELFMUTATION SCOPE. Extended beyond the substrate's own principals to # cdk-hnb659fds-* (AdministratorAccess bootstrap roles), # OrganizationAccountAccessRole, and seahaven-* (detective-control roles # such as the Config recorder role, which no SCP on prod/nonprod protects # from iam:DeleteRole). Defense in depth behind the path scoping above. # # The SAM copy retains its adjudicated accepted risks because SAM's constraints # are real; this file has no such excuse. KNOWN OPEN ITEM (pre-existing, not # introduced here): the org's ProtectPrivilegedRoles SCP encodes exactly the # protection in (4) but is attached ONLY to the security OU — extending it to # prod/nonprod is the durable org-level fix and is tracked separately. # # COUPLING (frozen, PLAT-143/PLAT-149): the enumerated StringEquals list below # is the last prod/dev HCP allow-list this document will carry. Do not append # another seahaven-lambda-execution-boundary- ARN here. New HCP # Lambda ceilings are policy/tf-managed/ created by hcptf-bootstrap # (CLI, PLAT-145). CreatePolicy lives only on that bootstrap role. Do not # put ArnLike on this list, and do not add ArnLike to the SAM copy in # deploy-substrate (PLAT-52 AC1: githubdeploy-seahaven-org-baseline can # CreatePolicy via CFN). Existing eight workloads keep these ARNs until their # consumer Terraform imports detach seahaven-hcptf-iam-management and this # stack is deleted in prod/dev (PLAT-147). External-dev SHOC roles below do # not attach this policy. # # SIZE BUDGET: this document is at the 6,144-character wall (4693 compact / # 10 statements after eight workload ARNs). That accumulator is why prod/dev # per-workspace IAM is leaving this file. Do not grow it. # # PER-WORKSPACE ROLE ACCUMULATOR — CLOSED FOR PROD/DEV # Do not append new hcptf- pairs for prod or dev. App Terraform owns # those roles (PLAT-144/PLAT-146). The eight existing prod pairs stay here # with DeletionPolicy: Retain until each is imported, then a Retain-remove # update forgets them, then the prod/dev stacks delete (PLAT-147). External-dev # SHOC roles below remain in this template (PLAT-148). All remaining subs are # exact StringEquals (never StringLike, never a wildcarded run_phase). # # 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, seahaven-dev 710827005802, and external-dev # 396287094661; NEVER mgmt — mgmt stays SAM until its stacks migrate out). Parameters: CreateOIDCProvider: Type: String Default: "true" AllowedValues: ["true", "false"] Description: >- Set to false if the app.terraform.io OIDC provider already exists in this account. An account holds exactly ONE provider per URL, so an unconditional create collides. Because the provider is Retain, a FIRST-create rollback (caused by any other resource in this stack failing) leaves the provider behind as an orphan and the stack in ROLLBACK_COMPLETE — which cannot be updated. Recovery: delete the stack, then either `aws iam delete-open-id-connect-provider --open-id-connect-provider-arn 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"] # Per-workspace hcptf-* roles for afi-backup-monitor-prod (PLAT-56) must only # 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: # --------------------------------------------------------------------------- # HCP Terraform OIDC provider # # Created by default: Phase-0 checks (2026-07-30) confirmed neither prod nor # dev has an app.terraform.io provider (the mgmt POC's copy was deleted in the # same-day rollback and never existed in the member accounts). An account # holds exactly ONE provider per URL — see the parameter above for the # first-create rollback trap this condition exists to make recoverable. # --------------------------------------------------------------------------- TerraformCloudOIDCProvider: Type: AWS::IAM::OIDCProvider Condition: ShouldCreateOIDCProvider Properties: Url: https://app.terraform.io ClientIdList: # Default audience of HCP Terraform dynamic provider credentials # (TFC_AWS_WORKLOAD_IDENTITY_AUDIENCE). Trust policies pin this via # StringEquals on app.terraform.io:aud. - aws.workload.identity ThumbprintList: # AWS ignores thumbprints for issuers signed by a trusted root CA # (app.terraform.io qualifies) and secures trust via the CA bundle; # the property is populated because CloudFormation requires a value. # This is the thumbprint HashiCorp's own AWS setup documentation uses. - 9e99a48a9960b14926bb7f3b02e22da2b0ab7280 # Every future hcptf-* role trusts this provider. Retain so deleting the # stack can never delete the account's Terraform federation anchor out # from under live workspaces. DeletionPolicy: Retain UpdateReplacePolicy: Retain # --------------------------------------------------------------------------- # Shared boundary-gated IAM guardrail policy (attached managed policy) # # Attached by every per-workspace Terraform APPLY role (hcptf-); # NEVER by plan roles (hcptf--plan are read-only and hold no IAM # writes at all). Defined once here so all apply roles carry the identical # reviewed escalation control instead of per-role copies that can drift. # # PRIMARY ESCALATION CONTROL (same design as INFRA-97 on the SAM side): # every iam:CreateRole / AttachRolePolicy / PutRolePolicy is conditioned on # the target role carrying seahaven-lambda-execution-boundary, so a role # created by a Terraform apply can never exceed the boundary ceiling. The # POC security review confirmed the unconditioned alternative is critical: # iam:PutRolePolicy on Lambda exec roles + lambda:UpdateFunctionCode reads # every secret in the account. # --------------------------------------------------------------------------- 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 # migration, not an edit. ManagedPolicyName: seahaven-hcptf-iam-management Description: >- Boundary-gated IAM role lifecycle for per-workspace Terraform apply roles (hcptf-*), plus the explicit Deny backstops that keep the permissions boundary from being detached or rewritten and the deploy substrates' own principals from being mutated. Mirrors seahaven-cfn-exec-iam-management; reconcile changes across both. PolicyDocument: Version: "2012-10-17" Statement: # Create role — MUST attach boundary AND land on the Terraform-owned # path. Two independent gates: the boundary caps what the role can do, # the path caps which roles this policy can touch at all. Terraform # configs set path = "/tf-managed/" on every aws_iam_role. - Sid: IAMCreateRoleWithBoundary Effect: Allow Action: - iam:CreateRole Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/*" Condition: StringEquals: "iam:PermissionsBoundary": &acceptableLambdaBoundaries - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary-afi-backup-monitor" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary-front-integrations" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary-procurement-ingest" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary-meal-order-manager" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary-seahaven-site" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary-seahaven-door-unlock-api" - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-lambda-execution-boundary-paychex-integrations" # Attach managed policies — MUST have boundary already on role - Sid: IAMAttachPolicyWithBoundary Effect: Allow Action: - iam:AttachRolePolicy Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/*" Condition: StringEquals: "iam:PermissionsBoundary": *acceptableLambdaBoundaries # Put inline policy — MUST have boundary already on role - Sid: IAMPutRolePolicyWithBoundary Effect: Allow Action: - iam:PutRolePolicy Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/*" Condition: StringEquals: "iam:PermissionsBoundary": *acceptableLambdaBoundaries # Boundary management — SET only, never DELETE. For a delete, the # iam:PermissionsBoundary condition key resolves to the boundary # CURRENTLY on the target role, so a StringEquals grant would match # exactly the roles the gate protects and self-defeat it (verified # live against the mgmt SAM copy 2026-07-27). Terraform never needs # the delete: it SETS the boundary on roles it creates, and destroy # calls DeleteRole. # Path-scoped as well as boundary-pinned: the condition constrains WHICH # boundary may be set, not WHICH role receives it. Unscoped (as in the # SAM copy) this is a one-way denial-of-service — applying the Lambda # runtime boundary to the CDK bootstrap execution role collapses its # permissions, and DenyBoundaryTampering below then blocks removal by # this same principal (2026-07-30 review finding C3). - Sid: IAMPutPermissionsBoundary Effect: Allow Action: - iam:PutRolePermissionsBoundary Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/*" Condition: StringEquals: "iam:PermissionsBoundary": *acceptableLambdaBoundaries # Explicit Deny backstop (AWS's NoBoundaryPolicyEdit/NoBoundaryDelete # delegation pattern). A Deny is required, not merely omitting the # Allow — any future Allow added to an apply role silently reopens # the escalation otherwise. - Sid: DenyBoundaryTampering Effect: Deny Action: - iam:DeleteRolePermissionsBoundary - iam:DeleteUserPermissionsBoundary Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/*" - !Sub "arn:aws:iam::${AWS::AccountId}:user/*" # Whole seahaven-* policy family: this policy carries the Denies, so # it is a higher-value target than the boundary it protects. Safe to # scope broadly — no Terraform stack manages a seahaven-* managed # policy, and apply roles hold no iam:CreatePolicy. - Sid: DenyBoundaryPolicyEdit Effect: Deny Action: - iam:CreatePolicyVersion - iam:SetDefaultPolicyVersion - iam:DeletePolicyVersion - iam:DeletePolicy Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:policy/seahaven-*" # Self-protection for BOTH deploy substrates' principals. Without # this the control is one API call from being undone — # IAMRoleReadAndDelete below grants iam:DetachRolePolicy on # Resource "*" unconditioned, so an apply role could detach this # very policy from itself. Scope covers the Terraform substrate's # own roles (hcptf-*) AND the GitHub Actions substrate's # (github-cfn-execution-role, githubdeploy-*): a Terraform apply # never legitimately manages any of them — hcptf-* roles are # managed by THIS stack via the CDK bootstrap execution role, the # GitHub-side roles by their own substrate/onboarding — so the Deny # costs nothing operationally and closes the same # UpdateAssumeRolePolicy-on-* repoint risk the SAM-side review # flagged, for every substrate principal reachable from this path. - Sid: DenySelfMutation Effect: Deny Action: - iam:AttachRolePolicy - iam:DeleteRole - iam:DeleteRolePolicy - iam:DeleteRolePermissionsBoundary - iam:DetachRolePolicy - iam:PutRolePolicy - iam:PutRolePermissionsBoundary - iam:UpdateAssumeRolePolicy - iam:UpdateRole - iam:UpdateRoleDescription Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/hcptf-*" - !Sub "arn:aws:iam::${AWS::AccountId}:role/github-cfn-execution-role" - !Sub "arn:aws:iam::${AWS::AccountId}:role/githubdeploy-*" # Extended beyond the SAM copy's three patterns (2026-07-30 review # findings C1/C3/C4). cdk-hnb659fds-* carries AdministratorAccess # and deploys this very stack; OrganizationAccountAccessRole is the # org break-glass path; seahaven-* covers detective-control roles # (e.g. the Config recorder role) that the protect-security-baseline # SCP does NOT shield from iam:DeleteRole. Defense in depth — the # path scoping on the write statements is the primary control. - !Sub "arn:aws:iam::${AWS::AccountId}:role/cdk-hnb659fds-*" - !Sub "arn:aws:iam::${AWS::AccountId}:role/OrganizationAccountAccessRole" - !Sub "arn:aws:iam::${AWS::AccountId}:role/seahaven-*" # READ-ONLY on every role/policy in the account. Terraform data sources # and refresh legitimately need to read arbitrary roles; none of these # actions can modify anything, so Resource "*" is safe here. - Sid: IAMReadOnly Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListAttachedRolePolicies - iam:ListRolePolicies - iam:ListRoles - iam:GetPolicy - iam:GetPolicyVersion - iam:ListPolicies - iam:ListPolicyVersions Resource: "*" # DESTRUCTIVE / MUTATING role actions — confined to the Terraform-owned # path. The SAM copy grants these on Resource "*" unconditioned, which # the 2026-07-30 review confirmed as a critical escalation primitive # (finding C1): iam:UpdateAssumeRolePolicy on "*" lets the principal # repoint the AdministratorAccess CDK bootstrap role's trust policy to # an external account and assume it. Path scoping closes that at the # root rather than enumerating protected names. - Sid: IAMRoleWriteScoped Effect: Allow Action: - iam:DeleteRole - iam:DeleteRolePolicy - iam:DetachRolePolicy - iam:TagRole - iam:UntagRole - iam:UpdateRole - iam:UpdateRoleDescription - iam:UpdateAssumeRolePolicy Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/*" # PassRole — Terraform passes the execution roles it created (which are # on the tf-managed path, boundary-gated above) to the Lambda service. # Path-scoped, not role/*: unscoped, one workspace's apply role could # attach ANOTHER workspace's or a SAM stack's execution role to a # function it controls and run arbitrary code as that identity — a path # that performs no IAM write and so evades every boundary gate and Deny # in this document (2026-07-30 review finding C5). Other target services # (scheduler, apigateway, ...) are NOT granted: a stack that needs one # adds a scoped PassRole statement to its own apply role at migration. - Sid: IAMPassRole Effect: Allow Action: - iam:PassRole Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/*" Condition: StringEquals: "iam:PassedToService": "lambda.amazonaws.com" # --------------------------------------------------------------------------- # Per-workspace role pattern (required for every future hcptf-* append) # and first workload: afi-backup-monitor-prod (PLAT-56). # # Copy this shape — do not invent enumerated Get* allow-lists. # # Plan role (every stack): # - Managed: ViewOnlyAccess (never ReadOnlyAccess — it grants # secretsmanager:GetSecretValue / s3:GetObject / kms:Decrypt to # speculative PR plans). # - PLUS a stack-scoped plan-refresh sidecar. ViewOnly alone omits # iam:GetRole, events:DescribeRule, and provider Lambda/S3 reads # needed after a partial first apply. # # Apply role (Lambda / EventBridge stacks): # - Attach seahaven-hcptf-iam-management. # - Service grants: prefix-scoped lambda:* on function:-* and # layer:-*, events:* on rule/-*, and bucket-scoped # s3:* on the stack artifact bucket. Enumerating provider Get* # (GetFunctionCodeSigningConfig, GetBucketAcl, …) lags and fails # first apply (PLAT-56). # # Trust: exact StringEquals on organization/project/workspace/run_phase — # never StringLike, never a wildcarded run_phase. Prod-only for this # pair (IsProdAccount). See README "Migration checklist". # --------------------------------------------------------------------------- HcptfAfiBackupMonitorPlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-afi-backup-monitor-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:afi-backup-monitor-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: afi-backup-monitor-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshIamRoles Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListRolePolicies - iam:ListAttachedRolePolicies Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/afi-*" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshEventBridge Effect: Allow Action: - events:DescribeRule - events:ListTargetsByRule - events:ListTagsForResource Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/afi-*" - Sid: RefreshLambda Effect: Allow Action: - lambda:* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:afi-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:layer:afi-shared*" - Sid: RefreshArtifactsBucket Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}/*" - Sid: RefreshLogs Effect: Allow Action: - logs:DescribeLogGroups - logs:ListTagsForResource Resource: "*" HcptfAfiBackupMonitorApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-afi-backup-monitor AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:afi-backup-monitor-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: afi-backup-monitor-services PolicyDocument: Version: "2012-10-17" Statement: # lambda:*/events:* on stack prefixes — AWS provider reads many # Get* attributes (e.g. GetFunctionCodeSigningConfig) that lag any # enumerated allow-list (PLAT-56 first-apply misses). - Sid: LambdaAll Effect: Allow Action: - lambda:* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:afi-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:layer:afi-shared*" - Sid: LambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:ListLayers - lambda:GetAccountSettings Resource: "*" - Sid: EventBridgeRules Effect: Allow Action: - events:* Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/afi-*" - Sid: CloudWatchLogs Effect: Allow Action: - logs:CreateLogGroup - logs:DeleteLogGroup - logs:PutRetentionPolicy - logs:DeleteRetentionPolicy - logs:TagResource - logs:UntagResource - logs:ListTagsForResource Resource: - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/afi-*" # logs:DescribeLogGroups is a collection action — AWS authorises it # against "*" only. Scoping it to a log-group ARN is a silent no-op # grant (same pitfall documented on LambdaExecutionBoundary). - Sid: CloudWatchLogsDescribe Effect: Allow Action: - logs:DescribeLogGroups Resource: "*" # Artifact bucket for HCP plan/apply split: zip bytes travel in the # plan via aws_s3_object content_base64 (local archive_file paths # from the plan worker are not on the apply worker). Action set is # s3:* on this bucket only — the AWS provider reads many GetBucket* # attributes (e.g. GetBucketAcl) after CreateBucket; enumerating # them lags provider upgrades (PLAT-56 first-apply miss). - Sid: LambdaArtifactsBucket Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::afi-backup-monitor-artifacts-${AWS::AccountId}/*" # --------------------------------------------------------------------------- # front-integrations (PLAT-72) — plan + apply roles for workspace # front-integrations-prod. Copy shape from afi-backup-monitor above; extend # for DynamoDB table front-sla-alerts, CloudWatch alarms, and site-alerts SNS. # --------------------------------------------------------------------------- HcptfFrontIntegrationsPlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-front-integrations-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:front-integrations-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: front-integrations-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshIamRoles Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListRolePolicies - iam:ListAttachedRolePolicies Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/front-*" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshEventBridge Effect: Allow Action: - events:DescribeRule - events:ListTargetsByRule - events:ListTagsForResource Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/front-*" - Sid: RefreshLambda Effect: Allow Action: # Read-only refresh for plan; mutate APIs stay on the apply role. - lambda:Get* - lambda:List* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:front-*" - Sid: RefreshArtifactsBucket Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - !Sub "arn:aws:s3:::front-integrations-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::front-integrations-artifacts-${AWS::AccountId}/*" - Sid: RefreshDynamoDB Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:DescribeTimeToLive - dynamodb:DescribeContinuousBackups - dynamodb:ListTagsOfResource Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/front-sla-alerts" - Sid: RefreshCloudWatchAlarms Effect: Allow Action: - cloudwatch:DescribeAlarms - cloudwatch:ListTagsForResource Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:front-*" - Sid: RefreshLogs Effect: Allow Action: - logs:DescribeLogGroups - logs:ListTagsForResource Resource: "*" HcptfFrontIntegrationsApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-front-integrations AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:front-integrations-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: front-integrations-services PolicyDocument: Version: "2012-10-17" Statement: - Sid: LambdaAll Effect: Allow Action: - lambda:* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:front-*" - Sid: LambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:ListLayers - lambda:GetAccountSettings Resource: "*" - Sid: EventBridgeRules Effect: Allow Action: - events:* Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/front-*" - Sid: CloudWatchLogs Effect: Allow Action: - logs:CreateLogGroup - logs:DeleteLogGroup - logs:PutRetentionPolicy - logs:DeleteRetentionPolicy - logs:TagResource - logs:UntagResource - logs:ListTagsForResource Resource: - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/front-*" - Sid: CloudWatchLogsDescribe Effect: Allow Action: - logs:DescribeLogGroups Resource: "*" - Sid: LambdaArtifactsBucket Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::front-integrations-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::front-integrations-artifacts-${AWS::AccountId}/*" - Sid: DynamoDBTable Effect: Allow Action: - dynamodb:* Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/front-sla-alerts" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/front-sla-alerts/index/*" - Sid: DynamoDBList Effect: Allow Action: - dynamodb:ListTables Resource: "*" - Sid: CloudWatchAlarms Effect: Allow Action: - cloudwatch:* Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:front-*" - Sid: SiteAlertsSns Effect: Allow Action: - sns:Publish - sns:GetTopicAttributes Resource: - !Sub "arn:aws:sns:us-east-1:${AWS::AccountId}:site-alerts" # --------------------------------------------------------------------------- # paychex-integrations (PLAT-120/123) — plan + apply roles for workspace # paychex-integrations-prod. Copy shape from front-integrations. Secret # Get/Put value stays off the apply role. Lambda execution boundary pins # minted secret ARNs and table paychex-worker-ledger. # --------------------------------------------------------------------------- HcptfPaychexIntegrationsPlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-paychex-integrations-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:paychex-integrations-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: paychex-integrations-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshIamRoles Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListRolePolicies - iam:ListAttachedRolePolicies Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/paychex-*" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshLambda Effect: Allow Action: - lambda:Get* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:paychex-*" # Collection/list APIs authorize only against Resource "*". - Sid: RefreshLambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:GetAccountSettings Resource: "*" - Sid: RefreshArtifactsBucket Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - !Sub "arn:aws:s3:::paychex-integrations-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::paychex-integrations-artifacts-${AWS::AccountId}/*" - Sid: RefreshCloudWatchAlarms Effect: Allow Action: - cloudwatch:DescribeAlarms - cloudwatch:ListTagsForResource Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:paychex-*" - Sid: RefreshLogs Effect: Allow Action: - logs:DescribeLogGroups - logs:ListTagsForResource Resource: "*" - Sid: RefreshSecrets Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:ListSecretVersionIds Resource: - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:paychex-integrations/*" - Sid: RefreshDynamoDB Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:DescribeTimeToLive - dynamodb:DescribeContinuousBackups - dynamodb:ListTagsOfResource Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/paychex-worker-ledger" HcptfPaychexIntegrationsApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-paychex-integrations AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:paychex-integrations-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: paychex-integrations-services PolicyDocument: Version: "2012-10-17" Statement: - Sid: LambdaAll Effect: Allow Action: - lambda:* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:paychex-*" - Sid: LambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:ListLayers - lambda:GetAccountSettings Resource: "*" - Sid: CloudWatchLogs Effect: Allow Action: - logs:CreateLogGroup - logs:DeleteLogGroup - logs:PutRetentionPolicy - logs:DeleteRetentionPolicy - logs:TagResource - logs:UntagResource - logs:ListTagsForResource Resource: - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/paychex-*" - Sid: CloudWatchLogsDescribe Effect: Allow Action: - logs:DescribeLogGroups Resource: "*" - Sid: LambdaArtifactsBucket Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::paychex-integrations-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::paychex-integrations-artifacts-${AWS::AccountId}/*" - Sid: CloudWatchAlarms Effect: Allow Action: - cloudwatch:* Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:paychex-*" - Sid: SiteAlertsSns Effect: Allow Action: - sns:Publish - sns:GetTopicAttributes Resource: - !Sub "arn:aws:sns:us-east-1:${AWS::AccountId}:site-alerts" - Sid: PaychexSecretShell Effect: Allow Action: - secretsmanager:DeleteSecret - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:PutResourcePolicy - secretsmanager:DeleteResourcePolicy - secretsmanager:TagResource - secretsmanager:UntagResource Resource: - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:paychex-integrations/*" - Sid: PaychexSecretCreate Effect: Allow Action: - secretsmanager:CreateSecret Resource: "*" Condition: StringEquals: "secretsmanager:Name": - paychex-integrations/oauth-client - paychex-integrations/webhook-api-key - paychex-integrations/google-service-account - paychex-integrations/slack-bot-token - paychex-integrations/front-inboxes-write - paychex-integrations/3cx-system-admin - Sid: DynamoDBTable Effect: Allow Action: - dynamodb:* Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/paychex-worker-ledger" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/paychex-worker-ledger/index/*" - Sid: DynamoDBList Effect: Allow Action: - dynamodb:ListTables Resource: "*" # --------------------------------------------------------------------------- # Per-workspace hcptf-* roles for sh-openswe-traces-prod (PLAT-73). # # Storage / IAM-user stack — NOT Lambda/EventBridge. Deviations from the # Lambda apply-role pattern (documented on PLAT-73): # - No seahaven-lambda-execution-boundary widen (no Lambda exec roles). # - No lambda:*/events:*/artifact-bucket statements. # - Explicit IAM user CRUD (seahaven-hcptf-iam-management is role-path-only). # - Stack-scoped s3:* on account-suffixed data + log buckets. # - KMS manage for alias/sh-openswe-traces CMK. # - Secrets Manager shell lifecycle on exact secret name (no Get/Put value). # --------------------------------------------------------------------------- HcptfShOpensweTracesPlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-sh-openswe-traces-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:sh-openswe-traces-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: sh-openswe-traces-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshIamUser Effect: Allow Action: - iam:GetUser - iam:GetUserPolicy - iam:ListUserPolicies - iam:ListAttachedUserPolicies - iam:ListUserTags - iam:GetAccessKeyLastUsed - iam:ListAccessKeys Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:user/sh-openswe-langsmith-export" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshBuckets Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - !Sub "arn:aws:s3:::sh-openswe-traces-${AWS::AccountId}" - !Sub "arn:aws:s3:::sh-openswe-traces-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::sh-openswe-traces-logs-${AWS::AccountId}" - !Sub "arn:aws:s3:::sh-openswe-traces-logs-${AWS::AccountId}/*" - Sid: RefreshKms Effect: Allow Action: - kms:Describe* - kms:GetKeyPolicy - kms:GetKeyRotationStatus - kms:ListResourceTags - kms:ListAliases Resource: "*" - Sid: RefreshSecret Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:ListSecretVersionIds Resource: - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:sh-openswe/langsmith-export-s3-*" HcptfShOpensweTracesApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-sh-openswe-traces AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:sh-openswe-traces-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: sh-openswe-traces-services PolicyDocument: Version: "2012-10-17" Statement: - Sid: TracesBuckets Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::sh-openswe-traces-${AWS::AccountId}" - !Sub "arn:aws:s3:::sh-openswe-traces-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::sh-openswe-traces-logs-${AWS::AccountId}" - !Sub "arn:aws:s3:::sh-openswe-traces-logs-${AWS::AccountId}/*" # CreateKey is account-level; pin via RequestTag matching the # app provider default_tags (Project=sh-openswe-traces). Key # admin after create requires the same ResourceTag — no # unconstrained PutKeyPolicy/DisableKey on unrelated CMKs. - Sid: TracesKmsCreate Effect: Allow Action: - kms:CreateKey Resource: "*" Condition: StringEquals: "aws:RequestTag/Project": sh-openswe-traces - Sid: TracesKmsList Effect: Allow Action: - kms:ListAliases Resource: "*" - Sid: TracesKmsAlias Effect: Allow Action: - kms:CreateAlias - kms:UpdateAlias - kms:DeleteAlias Resource: - !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:alias/sh-openswe-traces" - Sid: TracesKmsKey Effect: Allow Action: - kms:TagResource - kms:UntagResource - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion - kms:EnableKeyRotation - kms:DisableKeyRotation - kms:PutKeyPolicy - kms:DescribeKey - kms:GetKeyPolicy - kms:GetKeyRotationStatus - kms:ListResourceTags - kms:EnableKey - kms:DisableKey # Alias attach/detach also authorizes against the key ARN. - kms:CreateAlias - kms:UpdateAlias - kms:DeleteAlias Resource: "*" Condition: StringEquals: "aws:ResourceTag/Project": sh-openswe-traces - Sid: ExportIamUser Effect: Allow Action: - iam:CreateUser - iam:DeleteUser - iam:GetUser - iam:TagUser - iam:UntagUser - iam:UpdateUser - iam:PutUserPolicy - iam:DeleteUserPolicy - iam:GetUserPolicy - iam:ListUserPolicies - iam:ListAttachedUserPolicies - iam:ListUserTags - iam:ListAccessKeys Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:user/sh-openswe-langsmith-export" # CreateUser is authorized against the user ARN that will exist; # ListUsers is a collection action on "*". - Sid: ExportIamUserList Effect: Allow Action: - iam:ListUsers - iam:GetAccountSummary Resource: "*" # Shell lifecycle only — no GetSecretValue / PutSecretValue / # UpdateSecret so apply never renders or overwrites key material # in HCP state or run logs. CreateSecret is only on # ExportSecretCreate with an exact Name pin (not this ARN # prefix, which would also match longer secret names). - Sid: ExportSecretShell Effect: Allow Action: - secretsmanager:DeleteSecret - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:PutResourcePolicy - secretsmanager:DeleteResourcePolicy - secretsmanager:TagResource - secretsmanager:UntagResource Resource: - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:sh-openswe/langsmith-export-s3-*" - Sid: ExportSecretCreate Effect: Allow Action: - secretsmanager:CreateSecret Resource: "*" Condition: StringEquals: "secretsmanager:Name": sh-openswe/langsmith-export-s3 # --------------------------------------------------------------------------- # procurement-ingest (PLAT-86) — plan + apply roles for workspace # procurement-ingest-prod. Import-in-place of three former CDK stacks # (po-ingest, WorkorderIngestStack, procurement-api). Copy shape from # front-integrations; extend for S3 email buckets, SQS, SES receipt rules, # API Gateway, KMS (SHOC + DynamoDB CMK manage), Secrets Manager shell/ # rotation, DynamoDB streams, and prefix-scoped Lambda/alarms/log groups. # --------------------------------------------------------------------------- HcptfProcurementIngestPlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-procurement-ingest-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:procurement-ingest-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: procurement-ingest-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshIamRoles Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListRolePolicies - iam:ListAttachedRolePolicies Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/po-*" - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/workorder-*" - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/procurement-api" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshLambda Effect: Allow Action: - lambda:Get* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:po-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:workorder-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:procurement-api" # Collection/list APIs authorize only against Resource "*". # GetEventSourceMapping is authorized on the UUID mapping ARN # (no FunctionArn in the request context), so it cannot share # the apply-role FunctionArn condition. - Sid: RefreshLambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:ListEventSourceMappings - lambda:GetEventSourceMapping - lambda:GetAccountSettings Resource: "*" - Sid: RefreshArtifactsBucket Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - !Sub "arn:aws:s3:::procurement-ingest-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::procurement-ingest-artifacts-${AWS::AccountId}/*" - Sid: RefreshEmailBuckets Effect: Allow Action: - s3:Get* - s3:ListBucket - s3:GetBucketNotification - s3:GetBucketPolicy - s3:GetEncryptionConfiguration - s3:GetBucketTagging - s3:GetBucketVersioning - s3:GetBucketPublicAccessBlock Resource: - !Sub "arn:aws:s3:::po-ingest-emails-${AWS::AccountId}" - !Sub "arn:aws:s3:::po-ingest-emails-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::workorder-ingest-emails-${AWS::AccountId}" - !Sub "arn:aws:s3:::workorder-ingest-emails-${AWS::AccountId}/*" - Sid: RefreshDynamoDB Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:DescribeTimeToLive - dynamodb:DescribeContinuousBackups - dynamodb:DescribeStream - dynamodb:ListTagsOfResource Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/purchase-orders" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/purchase-orders/*" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/verified-sites" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/pending-site-review" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-orders" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-orders/*" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-order-comments" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-order-comments/*" - Sid: RefreshDynamoDBList Effect: Allow Action: - dynamodb:ListStreams - dynamodb:ListTables Resource: "*" - Sid: RefreshSqs Effect: Allow Action: - sqs:GetQueueAttributes - sqs:GetQueueUrl - sqs:ListQueueTags Resource: - !Sub "arn:aws:sqs:us-east-1:${AWS::AccountId}:po-ingest-*" - !Sub "arn:aws:sqs:us-east-1:${AWS::AccountId}:WorkorderIngestStack-*" - !Sub "arn:aws:sqs:us-east-1:${AWS::AccountId}:workorder-shoc-emitter-*" - Sid: RefreshCloudWatchAlarms Effect: Allow Action: - cloudwatch:DescribeAlarms - cloudwatch:ListTagsForResource Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:po-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:workorder-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:procurement-api-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:purchase-orders-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:verified-sites-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:pending-site-review-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:work-orders-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:work-order-comments-*" - Sid: RefreshApiGateway Effect: Allow Action: - apigateway:GET Resource: - !Sub "arn:aws:apigateway:us-east-1::/restapis/mvul1efda2" - !Sub "arn:aws:apigateway:us-east-1::/restapis/mvul1efda2/*" - arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com - arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com/* - Sid: RefreshKms Effect: Allow Action: - kms:DescribeKey - kms:GetKeyPolicy - kms:GetKeyRotationStatus - kms:ListResourceTags Resource: - !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:key/*" - !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:alias/workorder-ingest-shoc-webhook-kms" # ListAliases/ListKeys are collection APIs (Resource "*"). - Sid: RefreshKmsList Effect: Allow Action: - kms:ListAliases - kms:ListKeys Resource: "*" - Sid: RefreshSecrets Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:ListSecretVersionIds Resource: - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:workorder-ingest/shoc-webhook-hmac-*" - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:procurement-ingest/web-ui-auth-token-*" # OOB SSM pins used by data.aws_ssm_parameter (not in ViewOnlyAccess). - Sid: RefreshSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/dynamodb/cmk-arn" - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/procurement-api/custom-domain/certificate-arn" - Sid: RefreshSes Effect: Allow Action: - ses:DescribeReceiptRule - ses:DescribeReceiptRuleSet Resource: "*" - Sid: RefreshLogs Effect: Allow Action: - logs:DescribeLogGroups - logs:DescribeMetricFilters - logs:ListTagsForResource Resource: "*" HcptfProcurementIngestApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-procurement-ingest AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:procurement-ingest-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: procurement-ingest-services PolicyDocument: Version: "2012-10-17" Statement: - Sid: LambdaAll Effect: Allow Action: - lambda:* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:po-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:workorder-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:procurement-api" # Event source mapping ARNs are UUID-keyed; AWS authorises Create against # FunctionArn. Mutating Get/Update/Delete also take the mapping ARN. # GetEventSourceMapping by UUID does not carry FunctionArn in the # request context, so read is unconditioned on "*"; mutate stays # FunctionArn-constrained. - Sid: LambdaEventSourceMappingRead Effect: Allow Action: - lambda:GetEventSourceMapping - lambda:ListTags # Tag/Untag on ESM UUID ARNs do not carry FunctionArn in the # request context (provider default_tags on import). - lambda:TagResource - lambda:UntagResource Resource: "*" - Sid: LambdaEventSourceMappings Effect: Allow Action: - lambda:CreateEventSourceMapping - lambda:DeleteEventSourceMapping - lambda:UpdateEventSourceMapping Resource: "*" Condition: "ForAnyValue:StringLike": "lambda:FunctionArn": - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:po-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:workorder-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:procurement-api" - Sid: LambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:ListEventSourceMappings - lambda:GetAccountSettings Resource: "*" - Sid: SsmRead Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/dynamodb/cmk-arn" - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/procurement-api/custom-domain/certificate-arn" - Sid: CloudWatchLogs Effect: Allow Action: - logs:CreateLogGroup - logs:DeleteLogGroup - logs:PutRetentionPolicy - logs:DeleteRetentionPolicy - logs:TagResource - logs:UntagResource - logs:ListTagsForResource - logs:PutMetricFilter - logs:DeleteMetricFilter - logs:DescribeMetricFilters Resource: - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/po-*" - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/workorder-*" - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/procurement-api*" - Sid: CloudWatchLogsDescribe Effect: Allow Action: - logs:DescribeLogGroups Resource: "*" - Sid: ArtifactsBucket Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::procurement-ingest-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::procurement-ingest-artifacts-${AWS::AccountId}/*" - Sid: EmailBuckets Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::po-ingest-emails-${AWS::AccountId}" - !Sub "arn:aws:s3:::po-ingest-emails-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::workorder-ingest-emails-${AWS::AccountId}" - !Sub "arn:aws:s3:::workorder-ingest-emails-${AWS::AccountId}/*" - Sid: DynamoDBTables Effect: Allow Action: - dynamodb:* Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/purchase-orders" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/purchase-orders/*" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/verified-sites" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/verified-sites/*" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/pending-site-review" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/pending-site-review/*" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-orders" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-orders/*" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-order-comments" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/work-order-comments/*" - Sid: DynamoDBList Effect: Allow Action: - dynamodb:ListTables - dynamodb:ListStreams Resource: "*" - Sid: SqsQueues Effect: Allow Action: - sqs:* Resource: - !Sub "arn:aws:sqs:us-east-1:${AWS::AccountId}:po-ingest-*" - !Sub "arn:aws:sqs:us-east-1:${AWS::AccountId}:WorkorderIngestStack-*" - !Sub "arn:aws:sqs:us-east-1:${AWS::AccountId}:workorder-shoc-emitter-*" - Sid: CloudWatchAlarms Effect: Allow Action: - cloudwatch:* Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:po-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:workorder-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:procurement-api-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:purchase-orders-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:verified-sites-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:pending-site-review-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:work-orders-*" - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:work-order-comments-*" - Sid: SiteAlertsSns Effect: Allow Action: - sns:Publish - sns:GetTopicAttributes - sns:ListTagsForResource Resource: - !Sub "arn:aws:sns:us-east-1:${AWS::AccountId}:site-alerts" - Sid: ApiGateway Effect: Allow Action: - apigateway:* Resource: - !Sub "arn:aws:apigateway:us-east-1::/restapis/mvul1efda2" - !Sub "arn:aws:apigateway:us-east-1::/restapis/mvul1efda2/*" - arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com - arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com/* # TagResource/UntagResource authorize against /tags/. - arn:aws:apigateway:us-east-1::/tags/* - Sid: SesReceiptRules Effect: Allow Action: - ses:CreateReceiptRule - ses:UpdateReceiptRule - ses:DeleteReceiptRule - ses:DescribeReceiptRule - ses:SetReceiptRulePosition Resource: - !Sub "arn:aws:ses:us-east-1:${AWS::AccountId}:receipt-rule-set/INBOUND_MAIL:receipt-rule/ExistingRuleSetPoEmailRuleAC8E9C87-qwGDj9lBoL1G" - !Sub "arn:aws:ses:us-east-1:${AWS::AccountId}:receipt-rule-set/INBOUND_MAIL:receipt-rule/ExistingRuleSetWorkorderEmailRuleEA29F845-PKtaDBvIg61a" - Sid: SesDescribeRuleSet Effect: Allow Action: - ses:DescribeReceiptRuleSet Resource: "*" # Key management only on the live SHOC CMK — no kms:* (excludes # unconstrained key-policy/destructive ops on other keys and # avoids data-plane Encrypt/Decrypt on the apply role). - Sid: ShocKms Effect: Allow Action: - kms:DescribeKey - kms:GetKeyPolicy - kms:GetKeyRotationStatus - kms:ListResourceTags - kms:PutKeyPolicy - kms:EnableKeyRotation - kms:DisableKeyRotation - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion - kms:TagResource - kms:UntagResource - kms:EnableKey - kms:DisableKey Resource: - !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:key/d10fd1f0-a61a-4405-8568-85e9fd11ba18" - Sid: KmsList Effect: Allow Action: - kms:ListAliases - kms:ListKeys Resource: "*" - Sid: ShocKmsAlias Effect: Allow Action: - kms:CreateAlias - kms:DeleteAlias - kms:UpdateAlias Resource: - !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:alias/workorder-ingest-shoc-webhook-kms" - !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:key/d10fd1f0-a61a-4405-8568-85e9fd11ba18" # Shell lifecycle only — no CreateSecret / UpdateSecret so apply # never writes SecretString into HCP state or run logs. Create is # isolated in ShocSecretCreate with an exact Name pin. - Sid: ShocSecretShell Effect: Allow Action: - secretsmanager:DeleteSecret - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:PutResourcePolicy - secretsmanager:DeleteResourcePolicy - secretsmanager:TagResource - secretsmanager:UntagResource - secretsmanager:RotateSecret - secretsmanager:CancelRotateSecret - secretsmanager:UpdateSecretVersionStage Resource: - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:workorder-ingest/shoc-webhook-hmac-*" - Sid: ShocSecretCreate Effect: Allow Action: - secretsmanager:CreateSecret Resource: "*" Condition: StringEquals: "secretsmanager:Name": workorder-ingest/shoc-webhook-hmac - Sid: WebUiSecretDescribe Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy Resource: - !Sub "arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:procurement-ingest/web-ui-auth-token-*" # --------------------------------------------------------------------------- # seahaven-site-prod (PLAT-91) — static site S3 + CloudFront + ACM + GHA # content-deploy role. No Lambda → no boundary widen. No Route53 (apex DNS # stays OOB in mgmt). Plan role: ViewOnly + plan-refresh sidecar. # --------------------------------------------------------------------------- HcptfSeahavenSitePlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-seahaven-site-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:seahaven-site-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: seahaven-site-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshDeployRole Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListRolePolicies - iam:ListAttachedRolePolicies - iam:ListRoleTags Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/githubdeploy-seahaven-site" - Sid: RefreshGithubOidcProvider Effect: Allow Action: - iam:GetOpenIDConnectProvider Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshOriginBucket Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - arn:aws:s3:::seahaven-site-prod - arn:aws:s3:::seahaven-site-prod/* - Sid: RefreshCloudFront Effect: Allow Action: - cloudfront:Get* - cloudfront:List* Resource: "*" # aws_cloudfront_function refresh reads DEVELOPMENT via # DescribeFunction. Get* does not cover that API (PLAT-106). - Sid: RefreshCloudFrontFunction Effect: Allow Action: - cloudfront:DescribeFunction Resource: - !Sub "arn:aws:cloudfront::${AWS::AccountId}:function/seahaven-site-prod-directory-index" - Sid: RefreshAcm Effect: Allow Action: - acm:DescribeCertificate - acm:ListCertificates - acm:ListTagsForCertificate - acm:GetCertificate Resource: "*" - Sid: RefreshAppWebAclSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/waf/app-web-acl-arn" - Sid: RefreshWafWebAcl Effect: Allow Action: - wafv2:GetWebACL - wafv2:ListWebACLs Resource: "*" HcptfSeahavenSiteApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-seahaven-site AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:seahaven-site-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: seahaven-site-services PolicyDocument: Version: "2012-10-17" Statement: - Sid: OriginBucket Effect: Allow Action: - s3:* Resource: - arn:aws:s3:::seahaven-site-prod - arn:aws:s3:::seahaven-site-prod/* - Sid: ReadGithubOidcProvider Effect: Allow Action: - iam:GetOpenIDConnectProvider Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com" - Sid: CloudFrontManage Effect: Allow Action: - cloudfront:* Resource: "*" # RequestCertificate is account-level; pin via RequestTag matching # provider default_tags (Project=seahaven-site). Post-create manage # requires the same ResourceTag. - Sid: AcmCreate Effect: Allow Action: - acm:RequestCertificate Resource: "*" Condition: StringEquals: "aws:RequestTag/Project": seahaven-site - Sid: AcmList Effect: Allow Action: - acm:ListCertificates - acm:ListTagsForCertificate Resource: "*" - Sid: AcmManageTagged Effect: Allow Action: - acm:DescribeCertificate - acm:GetCertificate - acm:DeleteCertificate - acm:AddTagsToCertificate - acm:RemoveTagsFromCertificate - acm:RenewCertificate Resource: "*" Condition: StringEquals: "aws:ResourceTag/Project": seahaven-site # CloudFront web_acl_id is set via UpdateDistribution (cloudfront:* # above). Read the shared ACL ARN from SSM (PLAT-92) and allow # WAFv2 describe so plans/applies can validate the association. - Sid: ReadAppWebAclSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/waf/app-web-acl-arn" - Sid: ReadWafWebAcl Effect: Allow Action: - wafv2:GetWebACL - wafv2:GetWebACLForResource - wafv2:ListWebACLs - wafv2:ListResourcesForWebACL Resource: "*" # --------------------------------------------------------------------------- # meal-order-manager-prod (PLAT-70, imported to the app workspace in PLAT-146). # Live plan/apply IAM is terraform/hcp_iam.tf in meal-order-manager (ECS/ALB # as of PLAT-215). Do not mutate these CFN role policies; they are Retain # leftovers. githubdeploy-meal-order-manager OIDC lives in that app module. # --------------------------------------------------------------------------- # Original shape: HttpApi + Lambdas + DynamoDB + S3 + CloudFront. # Plan role: ViewOnly + plan-refresh sidecar. Apply role: HcptfIamManagement # + prefix-scoped service wildcards (no enumerated Get* lists). # --------------------------------------------------------------------------- HcptfMealOrderManagerPlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-meal-order-manager-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:meal-order-manager-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: meal-order-manager-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshIamRoles Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListRolePolicies - iam:ListAttachedRolePolicies - iam:ListRoleTags Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/meal-order-manager-*" - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/githubdeploy-meal-order-manager*" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshEventBridge Effect: Allow Action: - events:DescribeRule - events:ListTargetsByRule - events:ListTagsForResource Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/meal-order-manager-*" - Sid: RefreshLambda Effect: Allow Action: # Read-only refresh for plan; mutate APIs stay on the apply role. - lambda:Get* - lambda:List* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:meal-order-manager-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:layer:meal-order-manager-*" - Sid: RefreshBuckets Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - !Sub "arn:aws:s3:::meal-order-manager-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::meal-order-manager-artifacts-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::meal-order-manager-form-${AWS::AccountId}" - !Sub "arn:aws:s3:::meal-order-manager-form-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::meal-order-manager-reports-${AWS::AccountId}" - !Sub "arn:aws:s3:::meal-order-manager-reports-${AWS::AccountId}/*" - Sid: RefreshDynamoDB Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:DescribeTimeToLive - dynamodb:DescribeContinuousBackups - dynamodb:ListTagsOfResource Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/meal-order-manager-orders" - Sid: RefreshLogs Effect: Allow Action: - logs:DescribeLogGroups - logs:ListTagsForResource Resource: "*" - Sid: RefreshCloudFront Effect: Allow Action: - cloudfront:Get* - cloudfront:List* Resource: "*" - Sid: RefreshAcm Effect: Allow Action: - acm:DescribeCertificate - acm:ListCertificates - acm:ListTagsForCertificate - acm:GetCertificate Resource: "*" - Sid: RefreshAppWebAclSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters # aws_ssm_parameter refresh lists tags on managed parameters. - ssm:ListTagsForResource Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/waf/app-web-acl-arn" - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/meal-order-manager/*" # aws_ssm_parameter refresh uses DescribeParameters (collection API; # resource-level parameter ARNs are a silent no-op for this action). - Sid: RefreshSsmDescribeParameters Effect: Allow Action: - ssm:DescribeParameters Resource: "*" - Sid: RefreshWafWebAcl Effect: Allow Action: - wafv2:GetWebACL - wafv2:ListWebACLs Resource: "*" - Sid: RefreshHttpApi Effect: Allow Action: - apigateway:GET Resource: - !Sub "arn:aws:apigateway:us-east-1::/apis/*" - !Sub "arn:aws:apigateway:us-east-1::/tags/*" - Sid: RefreshAlarms Effect: Allow Action: - cloudwatch:DescribeAlarms - cloudwatch:ListTagsForResource Resource: "*" HcptfMealOrderManagerApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-meal-order-manager AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:meal-order-manager-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: meal-order-manager-services PolicyDocument: Version: "2012-10-17" Statement: - Sid: LambdaAll Effect: Allow Action: - lambda:* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:meal-order-manager-*" - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:layer:meal-order-manager-*" - Sid: LambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:ListLayers - lambda:GetAccountSettings Resource: "*" - Sid: EventBridgeRules Effect: Allow Action: - events:* Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/meal-order-manager-*" - Sid: CloudWatchLogs Effect: Allow Action: - logs:CreateLogGroup - logs:DeleteLogGroup - logs:PutRetentionPolicy - logs:DeleteRetentionPolicy - logs:TagResource - logs:UntagResource - logs:ListTagsForResource - logs:PutMetricFilter - logs:DeleteMetricFilter - logs:DescribeMetricFilters Resource: - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/meal-order-manager-*" - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/apigateway/meal-order-manager*" - Sid: CloudWatchLogsDescribe Effect: Allow Action: - logs:DescribeLogGroups Resource: "*" # HTTP API stage access_log_settings uses Log Delivery APIs # (account-level Resource "*"). PutResourcePolicy is intentionally # omitted: MealOrderApiAccessLogResourcePolicy below pre-grants # delivery.logs.amazonaws.com on the meal-order API log group so # the apply role cannot mutate account-wide log resource policies. - Sid: MealOrderApiGwAccessLogDelivery Effect: Allow Action: - logs:CreateLogDelivery - logs:GetLogDelivery - logs:UpdateLogDelivery - logs:DeleteLogDelivery - logs:ListLogDeliveries - logs:DescribeResourcePolicies Resource: "*" - Sid: StackBuckets Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::meal-order-manager-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::meal-order-manager-artifacts-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::meal-order-manager-form-${AWS::AccountId}" - !Sub "arn:aws:s3:::meal-order-manager-form-${AWS::AccountId}/*" - !Sub "arn:aws:s3:::meal-order-manager-reports-${AWS::AccountId}" - !Sub "arn:aws:s3:::meal-order-manager-reports-${AWS::AccountId}/*" - Sid: DynamoDBTable Effect: Allow Action: - dynamodb:* Resource: - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/meal-order-manager-orders" - !Sub "arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/meal-order-manager-orders/*" - Sid: DynamoDBList Effect: Allow Action: - dynamodb:ListTables Resource: "*" - Sid: HttpApiManage Effect: Allow Action: - apigateway:* Resource: - !Sub "arn:aws:apigateway:us-east-1::/apis" - !Sub "arn:aws:apigateway:us-east-1::/apis/*" - !Sub "arn:aws:apigateway:us-east-1::/tags/*" - !Sub "arn:aws:apigateway:us-east-1::/vpclinks" - !Sub "arn:aws:apigateway:us-east-1::/vpclinks/*" - Sid: CloudFrontManage Effect: Allow Action: - cloudfront:* Resource: "*" - Sid: AcmCreate Effect: Allow Action: - acm:RequestCertificate Resource: "*" Condition: StringEquals: "aws:RequestTag/Project": meal-order-manager - Sid: AcmList Effect: Allow Action: - acm:ListCertificates - acm:ListTagsForCertificate Resource: "*" - Sid: AcmManageTagged Effect: Allow Action: - acm:DescribeCertificate - acm:GetCertificate - acm:DeleteCertificate - acm:AddTagsToCertificate - acm:RemoveTagsFromCertificate - acm:RenewCertificate Resource: "*" Condition: StringEquals: "aws:ResourceTag/Project": meal-order-manager - Sid: ReadAppWebAclSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/waf/app-web-acl-arn" - Sid: MealOrderSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters - ssm:PutParameter - ssm:DeleteParameter - ssm:AddTagsToResource - ssm:RemoveTagsFromResource - ssm:ListTagsForResource Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/meal-order-manager/*" # Collection API required for aws_ssm_parameter refresh/import. - Sid: MealOrderSsmDescribeParameters Effect: Allow Action: - ssm:DescribeParameters Resource: "*" # API Gateway Lambda authorizer requires PassRole to # apigateway.amazonaws.com. Shared HcptfIamManagementPolicy only # grants PassRole to lambda.amazonaws.com (see IAMPassRole comment). - Sid: MealOrderPassRoleApiGateway Effect: Allow Action: - iam:PassRole Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/meal-order-manager-*" Condition: StringEquals: "iam:PassedToService": "apigateway.amazonaws.com" - Sid: ReadWafWebAcl Effect: Allow Action: - wafv2:GetWebACL - wafv2:GetWebACLForResource - wafv2:ListWebACLs - wafv2:ListResourcesForWebACL Resource: "*" - Sid: CloudWatchAlarms Effect: Allow Action: - cloudwatch:PutMetricAlarm - cloudwatch:DeleteAlarms - cloudwatch:DescribeAlarms - cloudwatch:TagResource - cloudwatch:UntagResource - cloudwatch:ListTagsForResource Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:meal-order-manager-*" - Sid: SnsPublishSiteAlerts Effect: Allow Action: - sns:Publish - sns:GetTopicAttributes - sns:ListTagsForResource Resource: - !Sub "arn:aws:sns:us-east-1:${AWS::AccountId}:site-alerts" - Sid: SesIdentityRead Effect: Allow Action: - ses:GetIdentityVerificationAttributes - ses:GetSendQuota Resource: "*" # Pre-grant delivery.logs write to the meal-order API access log group so # hcptf-meal-order-manager does not need logs:PutResourcePolicy (account-wide). # Deployed by CDK CFN exec on substrate update (PLAT-99). MealOrderApiAccessLogResourcePolicy: Type: AWS::Logs::ResourcePolicy Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: PolicyName: MealOrderManagerApiAccessLogDelivery PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Sid": "AWSLogDeliveryWrite", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/apigateway/meal-order-manager", "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/apigateway/meal-order-manager:*" ], "Condition": { "StringEquals": { "aws:SourceAccount": "${AWS::AccountId}" } } } ] } # --------------------------------------------------------------------------- # seahaven-door-unlock-api-prod (PLAT-76) — HttpApi + 5 Lambdas + EventBridge # + ACM custom domain + alarms. Plan role: ViewOnly + plan-refresh sidecar. # Apply role: HcptfIamManagement + prefix-scoped service wildcards. # --------------------------------------------------------------------------- HcptfDoorUnlockApiPlanRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-seahaven-door-unlock-api-plan AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:seahaven-door-unlock-api-prod:run_phase:plan ManagedPolicyArns: - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess Policies: - PolicyName: seahaven-door-unlock-api-plan-refresh PolicyDocument: Version: "2012-10-17" Statement: - Sid: RefreshIamRoles Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy - iam:ListRolePolicies - iam:ListAttachedRolePolicies - iam:ListRoleTags Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/door-unlock-api-*" - Sid: RefreshManagedPolicies Effect: Allow Action: - iam:GetPolicy - iam:GetPolicyVersion Resource: "*" - Sid: RefreshEventBridge Effect: Allow Action: - events:DescribeRule - events:ListTargetsByRule - events:ListTagsForResource Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/door-unlock-api-*" - Sid: RefreshLambda Effect: Allow Action: - lambda:Get* - lambda:List* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:door-unlock-api-*" - Sid: RefreshBuckets Effect: Allow Action: - s3:Get* - s3:ListBucket Resource: - !Sub "arn:aws:s3:::door-unlock-api-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::door-unlock-api-artifacts-${AWS::AccountId}/*" - Sid: RefreshLogs Effect: Allow Action: - logs:DescribeLogGroups - logs:ListTagsForResource Resource: "*" - Sid: RefreshAcm Effect: Allow Action: - acm:DescribeCertificate - acm:ListCertificates - acm:ListTagsForCertificate - acm:GetCertificate Resource: "*" # String door-id only. SecureString auth-token / elements-api-key # stay off the plan role so speculative runs cannot render them. - Sid: RefreshDoorUnlockSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/door-unlock/door-id" - Sid: RefreshDoorUnlockSsmTags Effect: Allow Action: - ssm:ListTagsForResource Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/door-unlock/*" - Sid: RefreshSsmDescribeParameters Effect: Allow Action: - ssm:DescribeParameters Resource: "*" - Sid: RefreshHttpApi Effect: Allow Action: - apigateway:GET Resource: - !Sub "arn:aws:apigateway:us-east-1::/apis/*" - arn:aws:apigateway:us-east-1::/domainnames/doorunlock.seahaven.com - arn:aws:apigateway:us-east-1::/domainnames/doorunlock.seahaven.com/* - !Sub "arn:aws:apigateway:us-east-1::/tags/*" - Sid: RefreshAlarms Effect: Allow Action: - cloudwatch:DescribeAlarms - cloudwatch:ListTagsForResource Resource: "*" - Sid: RefreshThreeCxSecrets Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:ListSecretVersionIds Resource: - arn:aws:secretsmanager:us-east-1:011934824531:secret:afterhours-shift-manager/3cx-domain-TPwqWP - arn:aws:secretsmanager:us-east-1:011934824531:secret:afterhours-shift-manager/3cx-client-id-jzyQXb - arn:aws:secretsmanager:us-east-1:011934824531:secret:afterhours-shift-manager/3cx-client-secret-jpO476 HcptfDoorUnlockApiApplyRole: Type: AWS::IAM::Role Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: RoleName: hcptf-seahaven-door-unlock-api AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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-prod:workspace:seahaven-door-unlock-api-prod:run_phase:apply ManagedPolicyArns: - !Ref HcptfIamManagementPolicy Policies: - PolicyName: seahaven-door-unlock-api-services PolicyDocument: Version: "2012-10-17" Statement: - Sid: LambdaAll Effect: Allow Action: - lambda:* Resource: - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:door-unlock-api-*" - Sid: LambdaList Effect: Allow Action: - lambda:ListFunctions - lambda:GetAccountSettings Resource: "*" - Sid: EventBridgeRules Effect: Allow Action: - events:* Resource: - !Sub "arn:aws:events:us-east-1:${AWS::AccountId}:rule/door-unlock-api-*" - Sid: CloudWatchLogs Effect: Allow Action: - logs:CreateLogGroup - logs:DeleteLogGroup - logs:PutRetentionPolicy - logs:DeleteRetentionPolicy - logs:TagResource - logs:UntagResource - logs:ListTagsForResource Resource: - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/lambda/door-unlock-api-*" - !Sub "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/apigateway/door-unlock-api*" - Sid: CloudWatchLogsDescribe Effect: Allow Action: - logs:DescribeLogGroups Resource: "*" - Sid: DoorUnlockApiGwAccessLogDelivery Effect: Allow Action: - logs:CreateLogDelivery - logs:GetLogDelivery - logs:UpdateLogDelivery - logs:DeleteLogDelivery - logs:ListLogDeliveries - logs:DescribeResourcePolicies Resource: "*" - Sid: StackBuckets Effect: Allow Action: - s3:* Resource: - !Sub "arn:aws:s3:::door-unlock-api-artifacts-${AWS::AccountId}" - !Sub "arn:aws:s3:::door-unlock-api-artifacts-${AWS::AccountId}/*" # HTTP API ids are allocated at create (same as meal-order). # Custom domain is hostname-pinned like procurement-api. # CreateDomainName POSTs to /domainnames and cannot be hostname-pinned; # mgmt still holds doorunlock.seahaven.com, so the domain is attached # at DNS cutover rather than granted as an unscoped collection POST. - Sid: HttpApiManage Effect: Allow Action: - apigateway:* Resource: - !Sub "arn:aws:apigateway:us-east-1::/apis" - !Sub "arn:aws:apigateway:us-east-1::/apis/*" - !Sub "arn:aws:apigateway:us-east-1::/tags/*" - Sid: HttpApiDomain Effect: Allow Action: - apigateway:* Resource: - arn:aws:apigateway:us-east-1::/domainnames/doorunlock.seahaven.com - arn:aws:apigateway:us-east-1::/domainnames/doorunlock.seahaven.com/* - Sid: AcmCreate Effect: Allow Action: - acm:RequestCertificate Resource: "*" Condition: StringEquals: "aws:RequestTag/Project": seahaven-door-unlock-api - Sid: AcmList Effect: Allow Action: - acm:ListCertificates - acm:ListTagsForCertificate Resource: "*" - Sid: AcmManageTagged Effect: Allow Action: - acm:DescribeCertificate - acm:GetCertificate - acm:DeleteCertificate - acm:AddTagsToCertificate - acm:RemoveTagsFromCertificate - acm:RenewCertificate Resource: "*" Condition: StringEquals: "aws:ResourceTag/Project": seahaven-door-unlock-api # HCP reads the String door-id data source only. Lambda execution # roles (not this apply role) GetParameter the SecureStrings. - Sid: DoorUnlockSsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/door-unlock/door-id" - Sid: DoorUnlockSsmTags Effect: Allow Action: - ssm:ListTagsForResource Resource: - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/seahaven/door-unlock/*" - Sid: DoorUnlockSsmDescribeParameters Effect: Allow Action: - ssm:DescribeParameters Resource: "*" - Sid: DescribeThreeCxSecrets Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetResourcePolicy - secretsmanager:ListSecretVersionIds Resource: - arn:aws:secretsmanager:us-east-1:011934824531:secret:afterhours-shift-manager/3cx-domain-TPwqWP - arn:aws:secretsmanager:us-east-1:011934824531:secret:afterhours-shift-manager/3cx-client-id-jzyQXb - arn:aws:secretsmanager:us-east-1:011934824531:secret:afterhours-shift-manager/3cx-client-secret-jpO476 - Sid: DoorUnlockPassRoleApiGateway Effect: Allow Action: - iam:PassRole Resource: - !Sub "arn:aws:iam::${AWS::AccountId}:role/tf-managed/door-unlock-api-*" Condition: StringEquals: "iam:PassedToService": "apigateway.amazonaws.com" - Sid: CloudWatchAlarms Effect: Allow Action: - cloudwatch:PutMetricAlarm - cloudwatch:DeleteAlarms - cloudwatch:DescribeAlarms - cloudwatch:TagResource - cloudwatch:UntagResource - cloudwatch:ListTagsForResource Resource: - !Sub "arn:aws:cloudwatch:us-east-1:${AWS::AccountId}:alarm:door-unlock-api-*" - Sid: SnsPublishSiteAlerts Effect: Allow Action: - sns:Publish - sns:GetTopicAttributes - sns:ListTagsForResource Resource: - !Sub "arn:aws:sns:us-east-1:${AWS::AccountId}:site-alerts" DoorUnlockApiAccessLogResourcePolicy: Type: AWS::Logs::ResourcePolicy Condition: IsProdAccount DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: PolicyName: DoorUnlockApiAccessLogDelivery PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Sid": "AWSLogDeliveryWrite", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/apigateway/door-unlock-api", "arn:aws:logs:us-east-1:${AWS::AccountId}:log-group:/aws/apigateway/door-unlock-api:*" ], "Condition": { "StringEquals": { "aws:SourceAccount": "${AWS::AccountId}" } } } ] } # --------------------------------------------------------------------------- # SHOC backend GitHub deployment permissions boundaries (external-dev only) # # These are ceilings for the dev and staging githubdeploy roles, not grants. # Existing dev/staging roles receive them through a separately approved # administrator/CDK action before HCP import. # --------------------------------------------------------------------------- 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-* - Sid: ReadDeployParameters Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: arn:aws:ssm:us-east-1:396287094661:parameter/shoc-backend/dev/deploy/* 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 - s3:PutObjectAcl - s3:PutObjectVersionAcl - s3:GetObject - s3:GetObjectAcl - s3:GetObjectVersion - s3:GetObjectVersionAcl - s3:DeleteObject Resource: - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/shoc-backend/* - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/resources/_runtime/_embedded_extensions/shoc-backend/* - arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/resources/environments/e-6c9m4vb62z/* - Sid: UseBeanstalkBucket Effect: Allow Action: - s3:GetBucketLocation - s3:ListBucket - s3:GetBucketPolicy - s3:GetBucketAcl - s3:GetBucketVersioning - s3:GetBucketOwnershipControls Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 - Sid: ReadDeployParameters Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters Resource: arn:aws:ssm:us-east-1:396287094661:parameter/shoc-backend/staging/deploy/* # 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. 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 boundaries, read/write secret # values, or pass a role. Live apply roles may UpdateAssumeRolePolicy only # on the matching githubdeploy-shoc-backend-{dev,staging} role so the # GitHub OIDC job_workflow_ref seam can land. 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 - autoscaling:DescribeAutoScalingGroups - ec2:DescribeSecurityGroups - ec2:DescribeSubnets - ec2:DescribeVpcAttribute - 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 "aws:ResourceTag/env": tf-poc - Sid: ReadSharedRdsTags Effect: Allow Action: rds:ListTagsForResource Resource: arn:aws:rds:us-east-1:396287094661:db:shoc-sqlserver-shared - Sid: AccessExistingElasticBeanstalkStorage Effect: Allow Action: - s3:CreateBucket - s3:PutBucketOwnershipControls Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 - Sid: ReadPocDns Effect: Allow Action: - route53:GetHostedZone - route53:ListResourceRecordSets - route53:ListTagsForResource Resource: arn:aws:route53:::hostedzone/Z02451891BSZD93CMMGDU - 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 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/Z02451891BSZD93CMMGDU 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/Z02451891BSZD93CMMGDU - Sid: TagPocCertificate Effect: Allow Action: - acm:AddTagsToCertificate - acm:RemoveTagsFromCertificate Resource: arn:aws:acm:us-east-1:396287094661:certificate/* Condition: StringEquals: "aws:ResourceTag/project": shoc "aws:ResourceTag/env": tf-poc - Sid: TerminatePocEnvironment Effect: Allow Action: elasticbeanstalk:TerminateEnvironment Resource: arn:aws:elasticbeanstalk:us-east-1:396287094661:environment/shoc-backend/shoc-backend-tf-poc - Sid: DeletePocRuntimeIam Effect: Allow Action: - iam:DeleteRole - iam:DeleteRolePolicy - iam:DetachRolePolicy Resource: arn:aws:iam::396287094661:role/shoc-backend-tf-poc - Sid: DeletePocInstanceProfile Effect: Allow Action: - iam:DeleteInstanceProfile - iam:RemoveRoleFromInstanceProfile Resource: arn:aws:iam::396287094661:instance-profile/shoc-backend-tf-poc - Sid: DeletePocAppConfig Effect: Allow Action: secretsmanager:DeleteSecret Resource: arn:aws:secretsmanager:us-east-1:396287094661:secret:shoc/tf-poc/app-config-* - Sid: DeletePocHostedZone Effect: Allow Action: route53:DeleteHostedZone Resource: arn:aws:route53:::hostedzone/Z02451891BSZD93CMMGDU - Sid: DeletePocCertificate Effect: Allow Action: acm:DeleteCertificate Resource: arn:aws:acm:us-east-1:396287094661:certificate/* Condition: StringEquals: "aws:ResourceTag/project": shoc "aws:ResourceTag/env": 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 - autoscaling:DescribeAutoScalingGroups - ec2:DescribeSecurityGroups - ec2:DescribeSubnets - ec2:DescribeVpcs - elasticbeanstalk:DescribeApplications - elasticbeanstalk:DescribeConfigurationOptions - elasticbeanstalk:DescribeConfigurationSettings - elasticbeanstalk:DescribeEnvironmentResources - elasticbeanstalk:DescribeEnvironments - elasticbeanstalk:ListTagsForResource - rds:DescribeDBInstances - route53:ListHostedZones - route53:ListHostedZonesByName Resource: "*" # Elastic Beanstalk DescribeConfigurationSettings calls # CreateBucket against its existing regional service bucket # during both plan and apply refresh. - Sid: AuthorizeExistingEbBucketDiscovery Effect: Allow Action: - s3:CreateBucket - s3:PutBucketOwnershipControls Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 Condition: StringEquals: s3:x-amz-object-ownership: ObjectWriter - Sid: ReadSharedCertificate Effect: Allow Action: - acm:DescribeCertificate - acm:GetCertificate - 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-* - Sid: ReadDevDeploySsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters - ssm:ListTagsForResource Resource: arn:aws:ssm:us-east-1:396287094661:parameter/shoc-backend/dev/deploy/* - Sid: DescribeDevDeploySsm Effect: Allow Action: ssm:DescribeParameters Resource: "*" 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: 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: DescribeDeploymentResources Effect: Allow Action: - autoscaling:Describe* - ec2:Describe* - elasticloadbalancing:Describe* Resource: "*" - 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-* - 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: UpdateDevGithubDeployTrust Effect: Allow Action: iam:UpdateAssumeRolePolicy Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-dev - Sid: ManageDevDeploySsm Effect: Allow Action: - ssm:PutParameter - ssm:AddTagsToResource - ssm:RemoveTagsFromResource Resource: arn:aws:ssm:us-east-1:396287094661:parameter/shoc-backend/dev/deploy/* - 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 - autoscaling:DescribeAutoScalingGroups - ec2:DescribeSecurityGroups - ec2:DescribeSubnets - ec2:DescribeVpcs - elasticbeanstalk:DescribeApplications - elasticbeanstalk:DescribeConfigurationOptions - elasticbeanstalk:DescribeConfigurationSettings - elasticbeanstalk:DescribeEnvironmentResources - elasticbeanstalk:DescribeEnvironments - elasticbeanstalk:ListTagsForResource - rds:DescribeDBInstances - route53:ListHostedZones - route53:ListHostedZonesByName Resource: "*" # Elastic Beanstalk DescribeConfigurationSettings calls # CreateBucket against its existing regional service bucket # during both plan and apply refresh. - Sid: AuthorizeExistingEbBucketDiscovery Effect: Allow Action: - s3:CreateBucket - s3:PutBucketOwnershipControls Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 Condition: StringEquals: s3:x-amz-object-ownership: ObjectWriter - Sid: ReadSharedCertificate Effect: Allow Action: - acm:DescribeCertificate - acm:GetCertificate - 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-* - Sid: ReadStagingDeploySsm Effect: Allow Action: - ssm:GetParameter - ssm:GetParameters - ssm:ListTagsForResource Resource: arn:aws:ssm:us-east-1:396287094661:parameter/shoc-backend/staging/deploy/* - Sid: DescribeStagingDeploySsm Effect: Allow Action: ssm:DescribeParameters Resource: "*" 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: 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: DescribeDeploymentResources Effect: Allow Action: - autoscaling:Describe* - ec2:Describe* - elasticloadbalancing:Describe* Resource: "*" - 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: StagingBeanstalkObjects Effect: Allow Action: - s3:Delete* - s3:Get* - s3:Put* Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661/* - Sid: StagingBeanstalkBuckets Effect: Allow Action: - s3:GetBucket* - s3:ListBucket - s3:PutBucketOwnershipControls - s3:PutBucketPolicy - s3:PutBucketPublicAccessBlock Resource: arn:aws:s3:::elasticbeanstalk-us-east-1-396287094661 # Elastic Beanstalk stages the CloudFormation template for # configuration UpdateStack calls in its AWS-owned regional # bucket and CloudFormation fetches it with the caller's # credentials. Zip deploys never touch this path. - Sid: ReadBeanstalkServiceTemplates Effect: Allow Action: - s3:GetObject - s3:GetObjectVersion Resource: arn:aws:s3:::elasticbeanstalk-us-east-1/* - Sid: ManageCloudFormationTemplates Effect: Allow Action: - s3:CreateBucket - s3:GetBucket* - s3:ListBucket - s3:PutBucketPolicy - s3:PutBucketOwnershipControls - s3:PutBucketPublicAccessBlock - s3:PutEncryptionConfiguration Resource: arn:aws:s3:::cf-templates-* - Sid: ManageCloudFormationTemplateObjects Effect: Allow Action: - s3:Get* - s3:Put* - s3:Delete* Resource: arn:aws:s3:::cf-templates-*/* - 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: UpdateStagingRuntimeTrust Effect: Allow Action: - iam:UpdateAssumeRolePolicy - iam:UpdateRole - iam:UpdateRoleDescription Resource: arn:aws:iam::396287094661:role/shoc-backend-staging - 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: UpdateStagingGithubDeployTrust Effect: Allow Action: iam:UpdateAssumeRolePolicy Resource: arn:aws:iam::396287094661:role/githubdeploy-shoc-backend-staging - Sid: ManageStagingDeploySsm Effect: Allow Action: - ssm:PutParameter - ssm:AddTagsToResource - ssm:RemoveTagsFromResource Resource: arn:aws:ssm:us-east-1:396287094661:parameter/shoc-backend/staging/deploy/* - 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