mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-07 16:19:07 +00:00
fix(cdk): grant observed EB deploy reads
This commit is contained in:
parent
45ffa68dfa
commit
7b6031e9a8
2 changed files with 90 additions and 13 deletions
|
|
@ -40,15 +40,18 @@ The role grants only:
|
||||||
describe actions are not reliably constrained by resource ARN.
|
describe actions are not reliably constrained by resource ARN.
|
||||||
- `elasticbeanstalk:CreateApplicationVersion` on application `shoc-backend`.
|
- `elasticbeanstalk:CreateApplicationVersion` on application `shoc-backend`.
|
||||||
- `elasticbeanstalk:UpdateEnvironment` on environment `shoc-backend-dev` only.
|
- `elasticbeanstalk:UpdateEnvironment` on environment `shoc-backend-dev` only.
|
||||||
- `s3:ListBucket` on `elasticbeanstalk-us-east-1-396287094661` (the official
|
- `s3:ListBucket` and `s3:GetBucketLocation` on
|
||||||
action's ownership-safe `HeadBucket` check), plus `s3:CreateBucket` on the
|
`elasticbeanstalk-us-east-1-396287094661` (the official action's
|
||||||
same bucket-level ARN. Under the `shoc-backend/` object prefix only:
|
ownership-safe bucket checks), plus `s3:CreateBucket` and
|
||||||
`s3:PutObject` plus `s3:GetObject` and `s3:GetObjectVersion`, which the
|
`s3:PutBucketOwnershipControls` on the same bucket-level ARN. Under the
|
||||||
pinned official deployment action requires to validate the
|
`shoc-backend/` object prefix only:
|
||||||
`CreateApplicationVersion` source bundle after upload.
|
`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:CreateBucket` is part of the pinned
|
`s3:CreateBucket` is part of the pinned
|
||||||
`aws-actions/aws-elasticbeanstalk-deploy@cfad3e5e...` (v1.0.6) IAM
|
`aws-actions/aws-elastic-beanstalk-deploy@cfad3e5e...` (v1.0.6) IAM
|
||||||
contract even though the workflow sets
|
contract even though the workflow sets
|
||||||
`create-s3-bucket-if-not-exists: "false"`. That input prevents the
|
`create-s3-bucket-if-not-exists: "false"`. That input prevents the
|
||||||
action's explicit bucket-creation helper; it does not remove the permission
|
action's explicit bucket-creation helper; it does not remove the permission
|
||||||
|
|
@ -59,9 +62,53 @@ The role grants only:
|
||||||
exact bucket-level ARN only (no object prefix, no wildcard resource), so it
|
exact bucket-level ARN only (no object prefix, no wildcard resource), so it
|
||||||
cannot create any other bucket.
|
cannot create any other bucket.
|
||||||
|
|
||||||
It grants **no** IAM mutation or `PassRole`, **no** RDS / EC2 / Secrets Manager
|
`s3:PutBucketOwnershipControls` was added after a second live deployment
|
||||||
access, and **no** administrator policy. There are no wildcard mutation
|
(run 30375409934) failed at `UpdateEnvironment` with `AccessDenied` for
|
||||||
surfaces.
|
`s3:PutBucketOwnershipControls` on the same service bucket. That call is
|
||||||
|
emitted by Elastic Beanstalk's `UpdateEnvironment` path after the source
|
||||||
|
bundle upload succeeds; AWS classifies it as a bucket-level permission, so
|
||||||
|
it is scoped to the same exact bucket-level ARN (no object prefix, no
|
||||||
|
wildcard resource). It does not widen object-prefix permissions, does not
|
||||||
|
grant `PutBucketPolicy`, `PutBucketPublicAccessBlock`, or any object-level write,
|
||||||
|
and does not change `create-s3-bucket-if-not-exists: "false"`.
|
||||||
|
|
||||||
|
`s3:GetBucketLocation` was added after CloudTrail showed that run
|
||||||
|
`30375409934` attempt 4 invoked it as
|
||||||
|
`githubdeploy-shoc-backend-dev/GitHubActions` and was denied. It is scoped to
|
||||||
|
the exact bucket-level ARN and grants no object access.
|
||||||
|
|
||||||
|
- `cloudformation:GetTemplate`, `cloudformation:DescribeStackResources`, and
|
||||||
|
`cloudformation:ListStackResources` on the Elastic Beanstalk-managed
|
||||||
|
CloudFormation stack `awseb-e-hehnrqjjrt-stack`, scoped to
|
||||||
|
`arn:aws:cloudformation:us-east-1:396287094661:stack/awseb-e-hehnrqjjrt-stack/*`.
|
||||||
|
These read-only calls are emitted by Elastic Beanstalk's
|
||||||
|
`UpdateEnvironment` path under the GitHub deploy role. `GetTemplate` was
|
||||||
|
added after run `30375409934` attempt 2 advanced past the S3
|
||||||
|
ownership-controls step and was denied on the EB-managed stack instance
|
||||||
|
`awseb-e-hehnrqjjrt-stack/112f77c0-7718-11f1-a1a9-0e48750aef13`.
|
||||||
|
CloudTrail then showed attempt 4 denied `DescribeStackResources` and
|
||||||
|
`ListStackResources` on that same stack instance.
|
||||||
|
CloudFormation stack ARNs carry a random GUID instance suffix, so the
|
||||||
|
permission is scoped to that one stack-name prefix (`/*`) rather than a
|
||||||
|
single instance ARN. The statement grants no CloudFormation mutation, no
|
||||||
|
`Resource: "*"`, and no access to any other stack. CDK does not own or
|
||||||
|
mutate that stack; it is owned by Elastic Beanstalk and referenced by
|
||||||
|
identifier only.
|
||||||
|
|
||||||
|
- `ec2:DescribeSubnets` as a read-only account-level query. Elastic Beanstalk
|
||||||
|
emitted this call during run 30375409934 attempt 3 after the environment
|
||||||
|
update started. EC2 does not support resource-level constraints for this
|
||||||
|
Describe action, so IAM requires `Resource: "*"`. No EC2 mutation action is
|
||||||
|
granted.
|
||||||
|
- `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. There are no wildcard
|
||||||
|
mutation surfaces.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
|
@ -92,7 +139,10 @@ All commands run from `infra/cdk/`.
|
||||||
|
|
||||||
- Trust policy `StringEquals` matches the exact audience and subject above.
|
- Trust policy `StringEquals` matches the exact audience and subject above.
|
||||||
- The inline policy contains no `Resource: "*"` mutation action and no service
|
- The inline policy contains no `Resource: "*"` mutation action and no service
|
||||||
outside `elasticbeanstalk` / `s3`.
|
outside `elasticbeanstalk` / `s3` / `cloudformation` / `ec2`. The
|
||||||
|
`cloudformation` grants are the three observed read-only actions on the
|
||||||
|
single EB-managed stack prefix; the only EC2 grant is the read-only
|
||||||
|
`DescribeSubnets` action whose IAM resource model requires `Resource: "*"`.
|
||||||
|
|
||||||
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`).
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,34 @@ 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:ListBucket', 's3:CreateBucket'],
|
actions: [
|
||||||
|
'cloudformation:GetTemplate',
|
||||||
|
'cloudformation:DescribeStackResources',
|
||||||
|
'cloudformation:ListStackResources',
|
||||||
|
],
|
||||||
|
resources: [
|
||||||
|
`arn:aws:cloudformation:${REGION}:${ACCOUNT_ID}:stack/awseb-e-hehnrqjjrt-stack/*`,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
deployRole.addToPolicy(
|
||||||
|
new iam.PolicyStatement({
|
||||||
|
effect: iam.Effect.ALLOW,
|
||||||
|
actions: ['ec2:DescribeSubnets'],
|
||||||
|
resources: ['*'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
deployRole.addToPolicy(
|
||||||
|
new iam.PolicyStatement({
|
||||||
|
effect: iam.Effect.ALLOW,
|
||||||
|
actions: [
|
||||||
|
's3:ListBucket',
|
||||||
|
's3:CreateBucket',
|
||||||
|
's3:PutBucketOwnershipControls',
|
||||||
|
's3:GetBucketLocation',
|
||||||
|
],
|
||||||
resources: [bucketArn],
|
resources: [bucketArn],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -81,7 +108,7 @@ 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:GetObjectVersion', 's3:PutObject'],
|
actions: ['s3:GetObject', 's3:GetObjectAcl', 's3:GetObjectVersion', 's3:PutObject'],
|
||||||
resources: [`${bucketArn}/${APPLICATION_NAME}/*`],
|
resources: [`${bucketArn}/${APPLICATION_NAME}/*`],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue