From 4aef5b463baf7ddbf40305ffb3e740e35d7f398a Mon Sep 17 00:00:00 2001 From: Alexandre Brandizzi Date: Mon, 31 Aug 2026 10:57:04 -0300 Subject: [PATCH] fix: grant staging deploy role the Support-confirmed Elastic Beanstalk S3 set s3:PutObject on shoc-backend/* covered only the upload the deploy action performs itself. AWS Support case 178526484500047 established that UpdateEnvironment then reads, writes, versions, ACL-checks and removes objects as the calling identity, across both the account bucket and AWS-owned Elastic Beanstalk service buckets whose names cannot be enumerated in advance. That is the failure the dev lane already hit, and staging calls the same deploy action and the same rollback update-environment, so the first OIDC deploy and every rollback would have stopped there. Brings the staging role to parity with deploy-dev-stack.ts. elasticbeanstalk:UpdateEnvironment stays pinned to the staging environment ARN, so the role still cannot update or terminate shoc-backend-dev. --- infra/cdk/deploy-staging-stack.ts | 43 ++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 12 deletions(-) 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-*'], }), );