diff --git a/infra/cdk/README.md b/infra/cdk/README.md index 9485c85..e32d030 100644 --- a/infra/cdk/README.md +++ b/infra/cdk/README.md @@ -78,6 +78,12 @@ The role grants only: above. Attempt 10 showed that Elastic Beanstalk verifies the materialized environment copy with `HeadObject`, which S3 authorizes through `s3:GetObject`. The shared embedded-extension prefix remains write-only. +- `s3:GetObject` and `s3:PutObject` on only + `elasticbeanstalk-us-east-1-396287094661/resources/environments/e-hehnrqjjrt/_runtime/versions/*`. + Attempt 12 showed Elastic Beanstalk reading the previous environment version + manifest and writing its replacement under this exact dev-environment + runtime prefix. The grant excludes deletes, ACL mutation, other environments, + and application bundle content. - `s3:GetObjectAcl` on objects under the service-wide `arn:aws:s3:::elasticbeanstalk-*/*` namespace. AWS Support case `178526484500047` confirmed that `UpdateEnvironment` uses the initiating diff --git a/infra/cdk/deploy-dev-stack.ts b/infra/cdk/deploy-dev-stack.ts index d501786..0cdef0c 100644 --- a/infra/cdk/deploy-dev-stack.ts +++ b/infra/cdk/deploy-dev-stack.ts @@ -27,6 +27,9 @@ export class DeployDevStack extends cdk.Stack { const environmentEmbeddedExtensionArn = `${bucketArn}/resources/environments/${ENVIRONMENT_ID}` + `/_runtime/_embedded_extensions/${APPLICATION_NAME}/*`; + const runtimeManifestArn = + `${bucketArn}/resources/environments/${ENVIRONMENT_ID}` + + '/_runtime/versions/*'; const oidcProviderArn = `arn:aws:iam::${ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com`; const deployRole = new iam.Role(this, 'GithubDeployRole', { @@ -193,6 +196,16 @@ export class DeployDevStack extends cdk.Stack { }), ); + deployRole.addToPolicy( + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: ['s3:GetObject', 's3:PutObject'], + // UpdateEnvironment reads the prior environment version manifest and + // writes its replacement under this environment-only runtime prefix. + resources: [runtimeManifestArn], + }), + ); + deployRole.addToPolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW,