diff --git a/infra/cdk/README.md b/infra/cdk/README.md index 93273f3..37446c4 100644 --- a/infra/cdk/README.md +++ b/infra/cdk/README.md @@ -45,10 +45,17 @@ The role grants only: ownership-safe bucket checks), plus `s3:CreateBucket` and `s3:PutBucketOwnershipControls` on the same bucket-level ARN. Under the `shoc-backend/` object prefix only: - `s3:PutObject`, `s3:GetObject`, `s3:GetObjectAcl`, and - `s3:GetObjectVersion`, which the pinned official deployment action and - Elastic Beanstalk require to validate the `CreateApplicationVersion` source - bundle after upload. + `s3:PutObject`, `s3:GetObject`, and `s3:GetObjectVersion`, which the pinned + official deployment action requires to validate the + `CreateApplicationVersion` source bundle after upload. +- `s3:GetObjectAcl` on objects under the service-wide + `arn:aws:s3:::elasticbeanstalk-*/*` namespace. AWS Support case + `178526484500047` confirmed that `UpdateEnvironment` uses the initiating + role to inspect objects in AWS-owned Elastic Beanstalk buckets, not only the + account-owned source-bundle bucket. The wildcard is limited to one read-only + ACL action and the Elastic Beanstalk bucket namespace; it grants no object + content read, write, delete, bucket-management, IAM, or `PassRole` + capability. `s3:CreateBucket` is part of the pinned `aws-actions/aws-elastic-beanstalk-deploy@cfad3e5e...` (v1.0.6) IAM @@ -112,15 +119,11 @@ The role grants only: successful administrator deployment. AWS supports resource-level constraints for all three mutations, so replacement ASGs remain covered without granting access to another environment. -- `s3:GetObjectAcl` under the existing - `elasticbeanstalk-us-east-1-396287094661/shoc-backend/*` object prefix. - Elastic Beanstalk emitted this read during the same attempt while validating - the uploaded application bundle. It grants no bucket-wide or cross-prefix - object access. It grants **no** IAM mutation or `PassRole`, **no** RDS / Secrets Manager access, no EC2 mutation, and **no** administrator policy. The only non-EB/S3 mutations are the three deployment-process Auto Scaling calls, restricted to -this environment's ASG name pattern. There are no wildcard mutation surfaces. +this environment's ASG name pattern. There are no wildcard mutation surfaces; +the only service-wide object grant is read-only ACL metadata. ## Prerequisites @@ -160,13 +163,16 @@ All commands run from `infra/cdk/`. The workflow's `AWS_DEPLOY_ROLE_ARN` repository secret (environment `dev`) must hold the ARN output by this stack (`GithubDeployRoleArn`). -The OIDC deployment is currently fail-closed, not repaired. Elastic Beanstalk -still reports a generic `s3:GetObjectAcl` denial after the account-owned source -prefix and every exact cross-account object referenced by the sanitized live -stack were tested independently. The runtime-prefix, platform-assets, and -launch-control hypotheses were disproved and are intentionally absent from the -policy. Do not broaden `GetObjectAcl` without an exact principal/action/resource -record from AWS Support or the AWS-owned bucket's diagnostic owner. +The previous OIDC deployment remained fail-closed after Elastic Beanstalk +reported a generic `s3:GetObjectAcl` denial outside the account-owned source +prefix. AWS Support case `178526484500047` subsequently confirmed that +`UpdateEnvironment` checks objects in AWS-owned Elastic Beanstalk buckets +using the initiating role and requires the `elasticbeanstalk-*/*` resource +namespace. This policy adds only the denied ACL-read action on that namespace; +it intentionally does not copy the managed +`AdministratorAccess-AWSElasticBeanstalk` policy's broad `s3:Get*`, +`s3:Put*`, or `s3:Delete*` grants. Any later denial must be evaluated and +granted independently. The pinned deployment action can return success after Elastic Beanstalk emits a fatal deployment event. The following workflow step therefore verifies that diff --git a/infra/cdk/deploy-dev-stack.ts b/infra/cdk/deploy-dev-stack.ts index 3575452..36addaf 100644 --- a/infra/cdk/deploy-dev-stack.ts +++ b/infra/cdk/deploy-dev-stack.ts @@ -142,11 +142,22 @@ export class DeployDevStack extends cdk.Stack { deployRole.addToPolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW, - actions: ['s3:GetObject', 's3:GetObjectAcl', 's3:GetObjectVersion', 's3:PutObject'], + actions: ['s3:GetObject', 's3:GetObjectVersion', 's3:PutObject'], resources: [`${bucketArn}/${APPLICATION_NAME}/*`], }), ); + deployRole.addToPolicy( + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: ['s3:GetObjectAcl'], + // UpdateEnvironment also checks objects in AWS-owned Elastic Beanstalk + // buckets. AWS Support case 178526484500047 confirmed that the caller's + // identity policy must cover the service-wide bucket namespace. + resources: ['arn:aws:s3:::elasticbeanstalk-*/*'], + }), + ); + new cdk.CfnOutput(this, 'GithubDeployRoleArn', { value: deployRole.roleArn, description: 'ARN of the GitHub OIDC deploy role for shoc-backend dev.',