diff --git a/infra/cdk/deploy-staging-stack.ts b/infra/cdk/deploy-staging-stack.ts index a634520..ed8c5dd 100644 --- a/infra/cdk/deploy-staging-stack.ts +++ b/infra/cdk/deploy-staging-stack.ts @@ -114,25 +114,44 @@ export class DeployStagingStack extends cdk.Stack { deployRole.addToPolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW, - actions: ['s3:PutObject'], - // The pinned deployment action writes exactly - // shoc-backend/.zip to the explicitly configured, - // pre-existing account bucket. It never reads or deletes objects. - resources: [ - `arn:aws:s3:::elasticbeanstalk-${REGION}-${ACCOUNT_ID}/${APPLICATION_NAME}/*`, - ], + actions: ['s3:Delete*', 's3:Get*', 's3:Put*'], + // Matches deploy-dev-stack.ts. The narrower s3:PutObject on + // shoc-backend/* covers only the upload the deploy action performs + // itself; AWS Support case 178526484500047 confirmed that + // UpdateEnvironment then reads, writes, versions, ACL-checks, and + // removes objects as the calling identity, in both the account bucket + // and AWS-owned Elastic Beanstalk service buckets whose names are not + // enumerable in advance. That is the failure the dev lane already hit; + // staging calls the same deploy action and the same rollback + // update-environment, so it needs the same set or the first OIDC + // deploy and every rollback stop there. + // + // NOTE: dev and staging are two environments of ONE Elastic Beanstalk + // application (APPLICATION_NAME is shared), so application versions for + // both live under the same shoc-backend/ prefix in the same account + // bucket. This grant therefore reaches dev's application-version + // objects. Environment authority stays separate -- + // elasticbeanstalk:UpdateEnvironment below is pinned to the staging + // environment ARN, so this role still cannot update or terminate + // shoc-backend-dev. + resources: ['arn:aws:s3:::elasticbeanstalk-*/*'], }), ); deployRole.addToPolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW, - // HeadBucket on the explicit existing bucket requires ListBucket. - // GetBucketLocation is retained for regional SDK compatibility. - actions: ['s3:GetBucketLocation', 's3:ListBucket'], - resources: [ - `arn:aws:s3:::elasticbeanstalk-${REGION}-${ACCOUNT_ID}`, + actions: [ + 's3:GetBucket*', + 's3:ListBucket', + 's3:PutBucketOwnershipControls', + 's3:PutBucketPolicy', + 's3:PutBucketPublicAccessBlock', ], + // AWS Support's bucket-level UpdateEnvironment set, excluding + // CreateBucket because the workflow deploys only to an existing + // application/environment and disables bucket creation. + resources: ['arn:aws:s3:::elasticbeanstalk-*'], }), );