feat(iam): add hcptf-seahaven-site plan/apply roles (PLAT-91) (#89)
Some checks are pending
Deploy / deploy-management (push) Waiting to run
Deploy / deploy-external-dev (push) Waiting to run
Deploy / deploy-security (push) Waiting to run
Deploy / deploy-dev (push) Waiting to run
Deploy / deploy-prod (push) Waiting to run

* 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).
This commit is contained in:
Adam Moussa 2026-08-07 15:09:57 -04:00 • committed by GitHub
parent e12944a42d
commit 35461d9267
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 180 additions and 4 deletions

View file

@ -661,12 +661,43 @@ Resources:
- !Sub "arn:aws:sns:us-east-1:${AWS::AccountId}:site-alerts"
- !Ref AWS::NoValue
# ── seahaven-site (PLAT-91) — content-deploy role data plane ────────
# TF creates githubdeploy-seahaven-site under /tf-managed/ with this
# boundary as ceiling. Role policy is S3 sync + CloudFront invalidate
# only; no Lambda. Exact origin bucket + distribution-scoped invalidate.
- !If
- IsProdAccount
- Sid: SeahavenSiteOriginS3
Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
- s3:DeleteObject
- s3:GetObjectTagging
- s3:PutObjectTagging
- s3:ListBucket
- s3:GetBucketLocation
Resource:
- arn:aws:s3:::seahaven-site-prod
- arn:aws:s3:::seahaven-site-prod/*
- !Ref AWS::NoValue
- !If
- IsProdAccount
- Sid: SeahavenSiteCloudFrontInvalidate
Effect: Allow
Action:
- cloudfront:CreateInvalidation
- cloudfront:GetInvalidation
Resource:
- !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/*"
- !Ref AWS::NoValue
# ── FURTHER PER-WORKLOAD DATA-PLANE STATEMENTS ──────────────────────
# Floor above + afi-backup-monitor (PLAT-56) + front-integrations
# (PLAT-72) + procurement-ingest (PLAT-86). Additional stacks add
# their own statements here, derived from THEIR OWN template, in
# their own PR, deployed to UPDATE_COMPLETE before first workload
# deploy. WIDENING PATH in the header still governs.
# (PLAT-72) + procurement-ingest (PLAT-86) + seahaven-site (PLAT-91).
# Additional stacks add their own statements here, derived from THEIR
# OWN template, in their own PR, deployed to UPDATE_COMPLETE before
# first workload deploy. WIDENING PATH in the header still governs.
#
# WHY the floor stayed empty of data-plane (decided 2026-07-30, Adam):
# The security win of INFRA-186 comes from DELETION, not enumeration.

View file

@ -1409,3 +1409,148 @@ Resources:
- 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
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: "*"
- Sid: RefreshAcm
Effect: Allow
Action:
- acm:DescribeCertificate
- acm:ListCertificates
- acm:ListTagsForCertificate
- acm:GetCertificate
Resource: "*"
HcptfSeahavenSiteApplyRole:
Type: AWS::IAM::Role
Condition: IsProdAccount
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