diff --git a/infra/cdk/README.md b/infra/cdk/README.md index 14cb8f0..2a62daa 100644 --- a/infra/cdk/README.md +++ b/infra/cdk/README.md @@ -291,9 +291,10 @@ instantiated in `app.ts` as stack `shoc-backend-deploy-staging` `shoc-backend-staging`, CloudFormation mutations scoped to the EB-managed stack `awseb-e-6c9m4vb62z-stack`, Auto Scaling mutations scoped to the `awseb-e-6c9m4vb62z-stack-*` ASG name prefix, and S3 limited to the existing - Elastic Beanstalk bucket namespace. It grants no dev resource, no IAM - mutation, no `PassRole`, and no RDS/Secrets Manager access to the deploy - role. + account bucket and `shoc-backend/` release-object prefix. The role can check + that bucket and upload a version bundle; it cannot read, delete, or mutate + other objects or buckets. It grants no dev resource, no IAM mutation, no + `PassRole`, and no RDS/Secrets Manager access to the deploy role. It references — and never creates, imports as CDK constructs, or modifies — the existing Elastic Beanstalk application `shoc-backend`, environment diff --git a/infra/cdk/deploy-staging-stack.ts b/infra/cdk/deploy-staging-stack.ts index d9591d6..a634520 100644 --- a/infra/cdk/deploy-staging-stack.ts +++ b/infra/cdk/deploy-staging-stack.ts @@ -114,28 +114,25 @@ export class DeployStagingStack extends cdk.Stack { deployRole.addToPolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW, - actions: ['s3:Delete*', 's3:Get*', 's3:Put*'], - // AWS Support case 178526484500047 confirmed that UpdateEnvironment - // reads, writes, versions, ACL-checks, and removes objects in both the - // account bucket and AWS-owned Elastic Beanstalk service buckets. - resources: ['arn:aws:s3:::elasticbeanstalk-*/*'], + 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}/*`, + ], }), ); deployRole.addToPolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW, - actions: [ - 's3:GetBucket*', - 's3:ListBucket', - 's3:PutBucketOwnershipControls', - 's3:PutBucketPolicy', - 's3:PutBucketPublicAccessBlock', + // 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}`, ], - // This is 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-*'], }), );