fix(cdk): grant AWS-confirmed EB ACL read

This commit is contained in:
brandizzi 2026-07-29 08:01:01 -03:00
parent 658bae77d3
commit 061a084fda
2 changed files with 35 additions and 18 deletions

View file

@ -45,10 +45,17 @@ The role grants only:
ownership-safe bucket checks), plus `s3:CreateBucket` and ownership-safe bucket checks), plus `s3:CreateBucket` and
`s3:PutBucketOwnershipControls` on the same bucket-level ARN. Under the `s3:PutBucketOwnershipControls` on the same bucket-level ARN. Under the
`shoc-backend/` object prefix only: `shoc-backend/` object prefix only:
`s3:PutObject`, `s3:GetObject`, `s3:GetObjectAcl`, and `s3:PutObject`, `s3:GetObject`, and `s3:GetObjectVersion`, which the pinned
`s3:GetObjectVersion`, which the pinned official deployment action and official deployment action requires to validate the
Elastic Beanstalk require to validate the `CreateApplicationVersion` source `CreateApplicationVersion` source bundle after upload.
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 `s3:CreateBucket` is part of the pinned
`aws-actions/aws-elastic-beanstalk-deploy@cfad3e5e...` (v1.0.6) IAM `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 successful administrator deployment. AWS supports resource-level
constraints for all three mutations, so replacement ASGs remain covered constraints for all three mutations, so replacement ASGs remain covered
without granting access to another environment. 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 It grants **no** IAM mutation or `PassRole`, **no** RDS / Secrets Manager
access, no EC2 mutation, and **no** administrator policy. The only non-EB/S3 access, no EC2 mutation, and **no** administrator policy. The only non-EB/S3
mutations are the three deployment-process Auto Scaling calls, restricted to 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 ## Prerequisites
@ -160,13 +163,16 @@ All commands run from `infra/cdk/`.
The workflow's `AWS_DEPLOY_ROLE_ARN` repository secret (environment `dev`) must The workflow's `AWS_DEPLOY_ROLE_ARN` repository secret (environment `dev`) must
hold the ARN output by this stack (`GithubDeployRoleArn`). hold the ARN output by this stack (`GithubDeployRoleArn`).
The OIDC deployment is currently fail-closed, not repaired. Elastic Beanstalk The previous OIDC deployment remained fail-closed after Elastic Beanstalk
still reports a generic `s3:GetObjectAcl` denial after the account-owned source reported a generic `s3:GetObjectAcl` denial outside the account-owned source
prefix and every exact cross-account object referenced by the sanitized live prefix. AWS Support case `178526484500047` subsequently confirmed that
stack were tested independently. The runtime-prefix, platform-assets, and `UpdateEnvironment` checks objects in AWS-owned Elastic Beanstalk buckets
launch-control hypotheses were disproved and are intentionally absent from the using the initiating role and requires the `elasticbeanstalk-*/*` resource
policy. Do not broaden `GetObjectAcl` without an exact principal/action/resource namespace. This policy adds only the denied ACL-read action on that namespace;
record from AWS Support or the AWS-owned bucket's diagnostic owner. 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 The pinned deployment action can return success after Elastic Beanstalk emits a
fatal deployment event. The following workflow step therefore verifies that fatal deployment event. The following workflow step therefore verifies that

View file

@ -142,11 +142,22 @@ export class DeployDevStack extends cdk.Stack {
deployRole.addToPolicy( deployRole.addToPolicy(
new iam.PolicyStatement({ new iam.PolicyStatement({
effect: iam.Effect.ALLOW, effect: iam.Effect.ALLOW,
actions: ['s3:GetObject', 's3:GetObjectAcl', 's3:GetObjectVersion', 's3:PutObject'], actions: ['s3:GetObject', 's3:GetObjectVersion', 's3:PutObject'],
resources: [`${bucketArn}/${APPLICATION_NAME}/*`], 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', { new cdk.CfnOutput(this, 'GithubDeployRoleArn', {
value: deployRole.roleArn, value: deployRole.roleArn,
description: 'ARN of the GitHub OIDC deploy role for shoc-backend dev.', description: 'ARN of the GitHub OIDC deploy role for shoc-backend dev.',