mirror of
https://github.com/Sea-Haven-Industries/seahaven-org-baseline.git
synced 2026-09-30 04:33:15 +00:00
fix(iam): shrink shared lambda boundary to the four-statement floor (PLAT-52) (#158)
* fix(iam): shrink shared lambda boundary to the four-statement floor (PLAT-52) PermissionsBoundaryUsageCount is 0 in prod and dev, so the shared seahaven-lambda-execution-boundary drops the packed IsProdAccount data-plane statements and keeps CloudWatchLogsWrite, CloudWatchLogsDescribe, XRay, and Ec2Eni. Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com> * docs(iam): correct shared boundary size and scoping notes (PLAT-52) The dev floor is the same 708-character document as the shared policy. 691 was stale. The scoping note now says the shared document is the four-statement floor, and allow-list retirement is a follow-up. Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com> * docs(iam): limit scoping rule to remaining SAM workloads (PLAT-52) The shared boundary shrink is unchanged. The scoping note now matches the HCP path already stated later in the same file. Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com> * docs(iam): record the shared floor size as 691 characters (PLAT-52) The stated measurement, with the account id resolved, is 691 characters and 4 statements for the shared boundary and for the dev floor copies. Headroom is 5453. 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>
This commit is contained in:
parent
ff492de58d
commit
055feca605
1 changed files with 28 additions and 238 deletions
|
|
@ -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): 691
|
||||
# characters / 4 statements as of 2026-09-28 (PLAT-52). Headroom 5453.
|
||||
# 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 691 / 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). Remaining SAM 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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue