* feat(iam): add platform permission set and org-admin assume alarm (SEC-37)
Adds an Identity Center platform group and Platform permission set
assigned to the management account, and a CloudTrail alarm on
AssumeRole of OrganizationAccountAccessRole. Scripts still assume
that role. This change is not deployed.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* fix(iam): skip sanctioned org-admin assumes in the alarm (SEC-37)
Count failed assumes for every principal. Do not page on a successful
assume by the Platform permission set or the two repo script sessions.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* feat(scp): deny iam changes on role/platform unless the platform principal (PLAT-233)
Adds ProtectPlatformPath beside the existing name denies in the
prod/nonprod SCP and the security OU copy. New hcptf-bootstrap
creates use /platform/. Existing roles are not recreated.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* fix(scp): use live bootstrap ARNs and close the platform path gaps (PLAT-233)
Resolve simulate and printed role ARNs from iam:GetRole so a /platform/
create is not reported as an unpathed role. Deny boundary changes on
role/platform/*, and match both Identity Center SSO role ARN shapes.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
* fix(scp): deny platform-path changes in bootstrap simulate (PLAT-233)
Add a simulate case for role/platform/hcptf-example and fail when CreateRole,
PutRolePolicy, or DeleteRole is allowed. The unpathed hcptf-* import check stays.
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
The live boundary denies lambda:InvokeFunction, so the Monday and Thursday
schedules would be created and would not fire. Allow that action only on
paychex-payroll-schedule, and allow SendMessage on paychex-checkcomponents
so the schedule role can enqueue the flush.
* feat(iam): move seahaven-site exec roles into their own stack (PLAT-225)
Drop the retained roles from the substrate template so the new stack can import them without a second owner.
* fix(iam): address review feedback
* fix(iam): allow frontend HCP apply to write deploy SSM and githubdeploy trust (PLAT-212)
* fix(iam): grant frontend HCP plan named SSM describe and tag reads (PLAT-212)
* fix(iam): allow frontend githubdeploy to read deploy SSM (PLAT-212)
HCP apply already writes /shoc-frontend-new/<env>/deploy/*, but the
githubdeploy ceiling omitted GetParameter so Deploy Web cannot resolve
bucket and distribution after origin moves to the bucket root.
* fix(iam): allow staging HCP apply to update the SHOC backend EB stack (PLAT-213)
* fix(iam): allow staging HCP apply to use the Elastic Beanstalk bucket (PLAT-213)
* fix(iam): allow staging HCP apply to copy the current release zip (PLAT-213)
* fix(iam): allow staging HCP apply versioned ACLs on EB env objects (PLAT-213)
* fix(iam): give staging HCP apply the proven Elastic Beanstalk bucket grants (PLAT-213)
* fix(iam): allow staging HCP apply to write CloudFormation template buckets (PLAT-213)
* fix(iam): let staging HCP apply read Elastic Beanstalk service templates (PLAT-213)
* fix(iam): enable meal-order-manager Lambda boundary in seahaven-dev (PLAT-210)
The per-workload boundary was floor-only outside prod, so meals-dev Lambdas
were denied DynamoDB. Keep Paychex SQS, SNS, and SES prod-only.
* fix(iam): keep meal-order-manager boundary Description unchanged (PLAT-210)
Named IAM managed-policy Description is immutable. Changing it replaces the
resource and 409s on ManagedPolicyName. PolicyDocument still widens in place.
* fix(iam): allow paychex period table and optional secrets (PLAT-195)
The processor role already allows these ARNs. The live boundary denied
them, so GetSecretValue and period PutItem returned HTTP 400. Sync the
template to the live ceiling and add the missing period table plus
slack-admin and afterhours secret suffixes.
* fix(iam): keep paychex boundary description unchanged (PLAT-195)
IAM managed-policy Description is immutable. Changing it on a named
policy forces replacement and 409s against the live ManagedPolicyName.
Widen PolicyDocument only.
* feat(iam): allow frontend HCP apply to own release pointer and invalidation (PLAT-188)
Plan and apply roles can read .release/current; apply can PutObject that key and CreateInvalidation on the exact distribution.
* fix(iam): allow frontend HCP roles to tag the release pointer (PLAT-188)
Terraform aws_s3_object lists object tags on every refresh, so plan and apply need GetObjectTagging and apply needs PutObjectTagging on the exact .release/current key.
* feat(iam): allow frontend HCP apply to update exact CloudFront resources (PLAT-187)
Phase 2 ownership tags cannot apply while UpdateDistribution and UpdateFunction are denied on *. Allow those two actions only on the pinned distribution and function ARNs.
* fix(iam): allow PublishFunction on exact frontend CloudFront functions (PLAT-187)
The AWS provider publishes after UpdateFunction, including tag-only applies, so denying PublishFunction on * still blocked Phase 2 function updates.
* feat(iam): lock app-owned HCP IAM and add bootstrap SCP (PLAT-143)
* fix(iam): pin HCP boundary ARNs and bootstrap trust window (PLAT-143)
Null on iam:PermissionsBoundary accepted any ceiling, including AdministratorAccess. Import apply cannot self-mutate hcptf-* while bootstrap trust is iam-bootstrap only; add a time-boxed exact StringEquals workspace grant instead of StringLike.
* fix(iam): update paychex boundary in place without fn if
CloudFormation replaced the named managed policy when the secrets statement was wrapped in Fn::If (409 duplicate name). Keep the six minted ARNs as a static statement so the document updates in place.
* fix(iam): leave paychex boundary description unchanged
Keep the live ManagedPolicy Description so CloudFormation only updates PolicyDocument.
CreateDomainName cannot be hostname-pinned, and mgmt still holds doorunlock.seahaven.com. Attach the domain at cutover instead of granting collection POST.
* feat(iam): add door-unlock-api hcptf roles and boundary
Give HCP Terraform a prod plan/apply pair, a per-workload Lambda boundary with exact SSM and 3CX ARNs, and API access-log delivery so PLAT-76 can leave the mgmt CDK stack.
* fix(iam): pin door-unlock apigw domain and ssm reads
Stop the apply role from managing every HTTP API custom domain, and keep SecureString door-unlock parameters off HCP plan and apply GetParameter.
Shared seahaven-lambda-execution-boundary stays unchanged for live roles.
New named policies plus an enumerated StringEquals allow-list unblock the
next PLAT-71 widen without growing the 6144-character shared document.
Pre-grant delivery.logs write via MealOrderApiAccessLogResourcePolicy on
substrate so the HCP apply role cannot mutate account-wide log resource
policies.
* feat(iam): add hcptf roles and boundary widen for meal-order-manager
Append plan/apply OIDC roles for meal-order-manager-prod and widen the lambda execution boundary with exact prod secret ARN and data-plane statements.
* fix(iam): make meal-order plan role Lambda refresh read-only
Replace plan-role lambda:* with Get*/List* so plan-phase credentials cannot mutate functions or layers.
* feat(waf): add seahaven-prod shared CloudFront WebACL stack
Stand up AppWebAcl in a thin prod stack and widen seahaven-site HCP
roles to read the SSM ARN so CloudFront can associate the ACL in-account.
* fix(deploy): add app-web-acl-prod to deploy.yaml
* feat(iam): add hcptf-seahaven-site plan/apply roles
Static-site HCP substrate for seahaven-site-prod plus boundary widen for
the TF-managed content-deploy role (S3 origin + CloudFront invalidate).
* fix(iam): allow seahaven-site HCP roles to read GitHub OIDC provider
Plan refresh needs iam:GetOpenIDConnectProvider for the content-deploy
role trust data source (PLAT-91 first-plan AccessDenied).