This commit is contained in:
Adam Moussa 2026-09-28 17:36:01 +00:00 • committed by GitHub
commit bbc4180908
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -134,9 +134,11 @@ Description: >-
# on the synthesized PolicyDocument with ${AWS::AccountId} resolved, and UPDATE
# THE NUMBERS in the same edit.
#
# Shared LambdaExecutionBoundary (legacy ceiling; do not widen): 5986
# characters / 15 statements as of 2026-08-10 (PLAT-100). Headroom 158.
# Leave it unchanged until live roles retarget (PLAT-52 phase 2).
# Shared LambdaExecutionBoundary (floor only; do not widen): 708
# characters / 4 statements as of 2026-09-28 (PLAT-52). Headroom 5436.
# Statements: CloudWatchLogsWrite, CloudWatchLogsDescribe, XRay, Ec2Eni.
# Packed IsProdAccount data-plane statements removed once
# PermissionsBoundaryUsageCount was 0 in prod and dev.
#
# Per-workload policies (floor + own data plane). Compact sizes recorded
# after synth (prod, ${AWS::AccountId}=011934824531):
@ -147,9 +149,10 @@ Description: >-
# seahaven-lambda-execution-boundary-seahaven-site: 1159 / 6 statements
# seahaven-lambda-execution-boundary-seahaven-door-unlock-api: measure after deploy (PLAT-76)
# seahaven-lambda-execution-boundary-paychex-integrations: 3250 / 10 statements (PLAT-228)
# Dev copies are floor-only (691 / 4) via IsProdAccount, except
# meal-order-manager (PLAT-210): DynamoDB/S3/SSM/invoke plus the
# seahaven-dev slack-bot-token ARN. SNS, SQS (Paychex), and SES stay prod.
# The same four floor statements measure 708 / 4 on the dev policies once
# IsProdAccount drops the prod-only statements. meal-order-manager
# (PLAT-210) also keeps DynamoDB/S3/SSM/invoke plus the seahaven-dev
# slack-bot-token ARN. SNS, SQS (Paychex), and SES stay prod.
#
# Guardrail PolicyDocuments also cap at 6,144. Each extra allow-list ARN
# is copied into four Sids in EACH of SamCfnIamManagementPolicy and
@ -214,16 +217,15 @@ Resources:
# intersection of the role's own policies and this boundary, so a misconfigured
# SAM role can never exceed what is listed here.
#
# SCOPING RULE (PLAT-52 phase 1, 2026-08-13). New workloads get their own
# ManagedPolicy seahaven-lambda-execution-boundary-<workload>: the fleet-wide
# floor (CloudWatchLogsWrite / CloudWatchLogsDescribe / XRay / Ec2Eni) plus
# that workload's data plane, derived from ITS OWN template. Do not add new
# data-plane statements to the shared seahaven-lambda-execution-boundary
# document — it is the legacy ceiling for roles not yet retargeted and stays
# unchanged until PermissionsBoundaryUsageCount is 0. INFRA-186 reduced this
# copy to a floor and later migrations packed data plane back into it under
# the 6,144-character cap (PLAT-93 / PLAT-100). Per-workload policies are
# the escape hatch from that cap and from the shared-ceiling residual.
# SCOPING RULE (PLAT-52). New workloads get their own ManagedPolicy
# seahaven-lambda-execution-boundary-<workload>: the four-statement floor
# (CloudWatchLogsWrite / CloudWatchLogsDescribe / XRay / Ec2Eni) plus that
# workload's data plane, derived from its own template. The shared
# seahaven-lambda-execution-boundary document is that same four-statement
# floor. Do not add data-plane statements to it. PermissionsBoundaryUsageCount
# is 0 in prod and dev, so the packed IsProdAccount statements are removed.
# Retiring the SAM allow-list of boundary ARNs in SamCfnIamManagementPolicy
# is a follow-up pull request.
#
# A resource pattern that genuinely CANNOT be scoped keeps its wildcard WITH a
# written justification on the statement: CloudWatchLogsDescribe, XRay and
@ -523,232 +525,20 @@ Resources:
- ec2:DescribeVpcs
Resource: "*"
# ── Shared workload data-plane (PLAT-93 PolicySize consolidation) ───
# Per-workload secret/DDB/S3 SIDs were merged so meal-order-manager
# (PLAT-70) can fit under the 6,144-character managed-policy cap
# without introducing new action wildcards. Exact secret ARNs only.
# End-state isolation remains PLAT-52 / INFRA-187.
#
# WorkloadSecrets covers: afi-backup-monitor (PLAT-56),
# front-integrations (PLAT-72), procurement-ingest (PLAT-86),
# meal-order-manager (PLAT-70).
- !If
- IsProdAccount
- Sid: WorkloadSecrets
Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource:
- arn:aws:secretsmanager:us-east-1:011934824531:secret:afi-api-key-w0E02a
- arn:aws:secretsmanager:us-east-1:011934824531:secret:afi-slack-webhook-T4oR3G
- arn:aws:secretsmanager:us-east-1:011934824531:secret:front-integrations/front-api-token-UXKv0U
- arn:aws:secretsmanager:us-east-1:011934824531:secret:front-integrations/slack-bot-token-giGfA7
- arn:aws:secretsmanager:us-east-1:011934824531:secret:front-integrations/google-service-account-dqv3Bo
- arn:aws:secretsmanager:us-east-1:011934824531:secret:procurement-ingest/web-ui-auth-token-ApAMmr
- arn:aws:secretsmanager:us-east-1:011934824531:secret:workorder-ingest/shoc-webhook-hmac-puYTcB
- arn:aws:secretsmanager:us-east-1:011934824531:secret:meal-order-manager/slack-bot-token-ZGmSGw
- !Ref AWS::NoValue
# WorkloadDynamoDB: enumerated union of front-integrations CRUD +
# procurement-ingest CRUD/stream actions. Meal-order table ARNs appended.
# Stream actions on non-stream tables are inert at the ceiling.
- !If
- IsProdAccount
- Sid: WorkloadDynamoDB
Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
- dynamodb:Query
- dynamodb:Scan
- dynamodb:BatchGetItem
- dynamodb:BatchWriteItem
- dynamodb:DescribeTable
- dynamodb:ConditionCheckItem
- dynamodb:GetRecords
- dynamodb:GetShardIterator
- dynamodb:DescribeStream
# ListStreams is a collection API (Resource "*"); ARN-scoping
# it is a silent no-op. Runtime stream consumers use the
# stream ARN via DescribeStream/GetRecords above.
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/*"
- !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/*"
- !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/index/*"
- !Ref AWS::NoValue
# ── procurement-ingest remaining data plane + meal-order S3 (PLAT-86/70) ─
# WorkloadS3 keeps the prior ProcurementIngestS3 action list and appends
# meal-order form/reports bucket ARNs (same object CRUD shape).
- !If
- IsProdAccount
- Sid: WorkloadS3
Effect: Allow
Action:
- s3:GetObject*
- s3:GetBucket*
- s3:List*
- s3:PutObject*
- s3:DeleteObject*
- s3:AbortMultipartUpload
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}/*"
- !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}/*"
- !Ref AWS::NoValue
- !If
- IsProdAccount
- Sid: ProcurementIngestSqs
Effect: Allow
Action:
- sqs:SendMessage
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
- sqs:GetQueueUrl
- sqs:ChangeMessageVisibility
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-*"
- !Ref AWS::NoValue
- !If
- IsProdAccount
- Sid: ProcurementIngestKms
Effect: Allow
Action:
- kms:Decrypt
- kms:DescribeKey
- kms:Encrypt
- kms:GenerateDataKey*
- kms:ReEncrypt*
Resource:
- arn:aws:kms:us-east-1:011934824531:key/be5fa4cb-c546-40fe-a13d-c7bec79f5d12
- arn:aws:kms:us-east-1:011934824531:key/d10fd1f0-a61a-4405-8568-85e9fd11ba18
- !Ref AWS::NoValue
- !If
- IsProdAccount
- Sid: ProcurementIngestBedrock
Effect: Allow
Action:
- bedrock:InvokeModel
- bedrock:InvokeModelWithResponseStream
Resource:
- !Sub "arn:aws:bedrock:us-east-1:${AWS::AccountId}:inference-profile/us.anthropic.claude-haiku-4-5-20251001-v1:0"
- arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-haiku-4-5-20251001-v1:0
- arn:aws:bedrock:us-east-2::foundation-model/anthropic.claude-haiku-4-5-20251001-v1:0
- arn:aws:bedrock:us-west-2::foundation-model/anthropic.claude-haiku-4-5-20251001-v1:0
- !Ref AWS::NoValue
# site-alerts publish shared by procurement-ingest alarms and
# meal-order-manager (PLAT-70); no separate MealOrder SNS statement.
- !If
- IsProdAccount
- Sid: ProcurementIngestSns
Effect: Allow
Action:
- sns:Publish
Resource:
- !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
# ── meal-order-manager (PLAT-70 / PLAT-100) — not covered above ─────
# Secrets → WorkloadSecrets; DynamoDB → WorkloadDynamoDB; S3 → WorkloadS3;
# SNS → ProcurementIngestSns. SSM + Lambda Invoke + execute-api share
# one Sid (scoped Resources only) so PolicySize stays under 6,144 —
# a standalone execute-api Sid is ~243 chars against 241 headroom and
# would fail UPDATE with LimitExceeded. SES stays in its own Sid:
# Resource:"*" must not share a statement with execute-api:Invoke
# (that would allow Invoke on every API in the account).
# Weekly-menu OIDC identity policy pins the API id; boundary pins
# method/path only.
- !If
- IsProdAccount
- Sid: MealOrderManager
Effect: Allow
Action:
- ssm:GetParameter
- lambda:InvokeFunction
- execute-api:Invoke
Resource:
- !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/meal-order-manager/*"
- !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:meal-order-manager-*"
- !Sub "arn:aws:execute-api:us-east-1:${AWS::AccountId}:*/*/GET/api/publish/settings"
- !Sub "arn:aws:execute-api:us-east-1:${AWS::AccountId}:*/*/POST/api/publish/menu"
- !Ref AWS::NoValue
- !If
- IsProdAccount
- Sid: MealOrderManagerSes
Effect: Allow
Action:
- ses:SendRawEmail
Resource: "*"
- !Ref AWS::NoValue
# ── FURTHER PER-WORKLOAD DATA-PLANE ────────────────────────────────
# Do not add statements here. Remaining SAM stacks: create
# seahaven-lambda-execution-boundary-<stack> below and append its ARN
# to SamCfnIamManagementPolicy only (WIDENING PATH). New HCP stacks
# do not append here. This shared document stays unchanged until live
# roles retarget (PLAT-52 phase 2) and PermissionsBoundaryUsageCount
# reaches 0.
# Do not add statements here. The shared document is the four-statement
# floor (PLAT-52). Remaining SAM stacks use
# seahaven-lambda-execution-boundary-<stack> below. New HCP stacks
# do not append here.
# ---------------------------------------------------------------------------
# Per-workload Lambda execution boundaries (PLAT-52 phase 1)
#
# Each policy is the fleet floor plus that workload's data plane, split from
# the shared document above without editing it. Live roles keep the shared
# ARN until app-repo retargets. Guardrail StringEquals lists include both.
# Floor statements are YAML-anchored on AfiBackupMonitorBoundary; later
# policies alias them. Floor rationale lives on LambdaExecutionBoundary.
# Prod-only data plane stays behind IsProdAccount (same as the shared copy).
# Each policy is the fleet floor plus that workload's data plane.
# Guardrail StringEquals lists still include the shared ARN and each
# per-workload ARN until the allow-list follow-up. Floor statements are
# YAML-anchored on AfiBackupMonitorBoundary; later policies alias them.
# Floor rationale lives on LambdaExecutionBoundary.
# Prod-only data plane on these policies stays behind IsProdAccount.
# ---------------------------------------------------------------------------
AfiBackupMonitorBoundary:
Type: AWS::IAM::ManagedPolicy