diff --git a/lib/deploy-substrate/deploy-substrate.template.yaml b/lib/deploy-substrate/deploy-substrate.template.yaml index bc1f8dc..c2b37fd 100644 --- a/lib/deploy-substrate/deploy-substrate.template.yaml +++ b/lib/deploy-substrate/deploy-substrate.template.yaml @@ -692,9 +692,96 @@ Resources: - !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/*" - !Ref AWS::NoValue + # ── meal-order-manager (PLAT-70) — prod-only exact secret ARN + data plane ─ + # Derived from meal-order-manager template.yaml + secrets created in + # seahaven-prod 2026-08-07. Exact ARN only (no secret:meal-order-* patterns). + - !If + - IsProdAccount + - Sid: MealOrderManagerSecrets + Effect: Allow + Action: + - secretsmanager:GetSecretValue + Resource: + - arn:aws:secretsmanager:us-east-1:011934824531:secret:meal-order-manager/slack-bot-token-ZGmSGw + - !Ref AWS::NoValue + - !If + - IsProdAccount + - Sid: MealOrderManagerDynamoDB + Effect: Allow + Action: + - dynamodb:GetItem + - dynamodb:PutItem + - dynamodb:UpdateItem + - dynamodb:DeleteItem + - dynamodb:Query + - dynamodb:Scan + - dynamodb:BatchGetItem + - dynamodb:BatchWriteItem + - dynamodb:DescribeTable + - dynamodb:ConditionCheckItem + 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/index/*" + - !Ref AWS::NoValue + - !If + - IsProdAccount + - Sid: MealOrderManagerS3 + Effect: Allow + Action: + - s3:GetObject* + - s3:GetBucket* + - s3:List* + - s3:PutObject* + - s3:DeleteObject* + - s3:AbortMultipartUpload + Resource: + - !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: MealOrderManagerSsm + Effect: Allow + Action: + - ssm:GetParameter + - ssm:GetParameters + Resource: + - !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/meal-order-manager/*" + - !Ref AWS::NoValue + - !If + - IsProdAccount + - Sid: MealOrderManagerLambdaInvoke + Effect: Allow + Action: + - lambda:InvokeFunction + Resource: + - !Sub "arn:aws:lambda:us-east-1:${AWS::AccountId}:function:meal-order-manager-*" + - !Ref AWS::NoValue + - !If + - IsProdAccount + - Sid: MealOrderManagerSes + Effect: Allow + Action: + - ses:SendRawEmail + - ses:SendEmail + Resource: "*" + - !Ref AWS::NoValue + - !If + - IsProdAccount + - Sid: MealOrderManagerSns + Effect: Allow + Action: + - sns:Publish + Resource: + - !Sub "arn:aws:sns:us-east-1:${AWS::AccountId}:site-alerts" + - !Ref AWS::NoValue + # ── FURTHER PER-WORKLOAD DATA-PLANE STATEMENTS ────────────────────── # Floor above + afi-backup-monitor (PLAT-56) + front-integrations - # (PLAT-72) + procurement-ingest (PLAT-86) + seahaven-site (PLAT-91). + # (PLAT-72) + procurement-ingest (PLAT-86) + seahaven-site (PLAT-91) + # + meal-order-manager (PLAT-70). # 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. diff --git a/lib/terraform-substrate/terraform-substrate.template.yaml b/lib/terraform-substrate/terraform-substrate.template.yaml index ab93017..2beb176 100644 --- a/lib/terraform-substrate/terraform-substrate.template.yaml +++ b/lib/terraform-substrate/terraform-substrate.template.yaml @@ -1585,3 +1585,317 @@ Resources: - wafv2:ListWebACLs - wafv2:ListResourcesForWebACL Resource: "*" + + # --------------------------------------------------------------------------- + # meal-order-manager-prod (PLAT-70) — HttpApi + 7 Lambdas + layer + DynamoDB + # + S3 form/reports/artifacts + CloudFront/ACM/WAF + EventBridge + alarms. + # Plan role: ViewOnly + plan-refresh sidecar. Apply role: HcptfIamManagement + # + prefix-scoped service wildcards (no enumerated Get* lists). + # --------------------------------------------------------------------------- + HcptfMealOrderManagerPlanRole: + Type: AWS::IAM::Role + Condition: IsProdAccount + 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 + 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/*" + - 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 + 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: "*" + - 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/*" + - 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: "*"