-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(bootstrap): same-account modern bootstrapping still requires policy ARNs #9867
Conversation
The current bootstrapping experience has sharp edges. It requires you to pass `--cloudformation-execution-policies`. If you don't pass any, it will successfully deploy a bootstrap stack that doesn't actually work. In effect, you are forced to constantly look up and copy/paste the ARN for `AdministratorAccess` (because that's effectively what people need to use anyway). We don't want to default to this policy for them, because it equates to handing over the keys to your account to another account, and you need to be fully aware that you're doing that. In the case of bootstrapping an account just for use "by itself", however (which is the 90% use case for bootstrapping), the trust boundary is very clear and there's no risk of privilege escalation between accounts (there might still be risk of privilege escalation between different people using different IAM users in the same AWS account, but that is not a recommended setup). Add an optimization where in the case of a "simple", non-cross account bootstrap, we'll default to the AdministratorAccess ARN for you. Once you establish `--trust` with another account, we'll still force you to spell out the execution policy you'll want to use though. Fixes #8571. Also in this PR: - The `blockPublicAccessConfiguration` would be reset on every re-bootstrap, instead of reusing the previous setting. - The `enableTerminationProtection` would be reset on every re-bootstrap, instead of reusing the previous setting.
@rix0rrr Do you have a timeline when this will be the default bootstrap when executing |
When "enough" people have tried it and used it that we can confidently recommend everyone use it in favor of the old way. Also I would like to implement context queries and bake that for a while, and then if we haven't had issues in--say--a month, I'd feel comfortable flipping the switch. |
What do you mean by "context queries"? I am using the new bootstrap and it is perfectly possible to use lookups. I thought only pipelines will not work but normal |
Well the context queries don't use the new bootstrapping roles yet, which is mostly fine if you stay in-account but no longer fine once you try to do it cross-account. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving as-is with two minor and one slightly less minor comment. Expecting these to be fixed before a second approval is given, so not explicitly tagging pr/do-not-merge.
const cloudFormationExecutionPolicies = params.cloudFormationExecutionPolicies ?? current.parameters.CloudFormationExecutionPolicies?.split(',') ?? []; | ||
|
||
if (trustedAccounts.length > 0 && cloudFormationExecutionPolicies.length === 0) { | ||
throw new Error(`You need to pass \'--cloudformation-execution-policies\' when trusting other accounts using \'--trust\' (${trustedAccounts}). Try a managed policy of the form \'arn:aws:iam::aws:policy/<PolicyName>\'.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw new Error(`You need to pass \'--cloudformation-execution-policies\' when trusting other accounts using \'--trust\' (${trustedAccounts}). Try a managed policy of the form \'arn:aws:iam::aws:policy/<PolicyName>\'.`); | |
throw new Error(`You need to pass '--cloudformation-execution-policies' when trusting other accounts using '--trust' (${trustedAccounts}). Try a managed policy of the form 'arn:aws:iam::aws:policy/<PolicyName>'.`); |
// Would leave AdministratorAccess policies with a trust relationship, without the user explicitly | ||
// approving the trust policy. | ||
const implicitPolicy = `arn:${await current.partition()}:iam::aws:policy/AdministratorAccess`; | ||
warning(`Defaulting execution policy to '${implicitPolicy}'. Pass \'--cloudformation-execution-policies\' to customize.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning(`Defaulting execution policy to '${implicitPolicy}'. Pass \'--cloudformation-execution-policies\' to customize.`); | |
warning(`Defaulting execution policy to '${implicitPolicy}'. Pass '--cloudformation-execution-policies' to customize.`); |
return deployStack({ | ||
stack: assembly.getStackByName(this.toolkitStackName), | ||
resolvedEnvironment: this.resolvedEnvironment, | ||
sdk: await this.sdkProvider.forEnvironment(this.resolvedEnvironment, Mode.ForWriting), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sdk: await this.sdkProvider.forEnvironment(this.resolvedEnvironment, Mode.ForWriting), | |
sdk: await this.sdk, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no problems with this change from a security perspective.
@rix0rrr one question. Do I see correctly that this PR contains 2 changes? One is the "defaulting to AdminAccess" part, and the other is corrected validation that takes parameters into account when performing it?
If that's the case, any chance of splitting these into 2 PRs? It's pretty hard to understand exactly what's happening here... For example, I'm pretty sure the changes in toolkit-info.ts
and cdk.ts
are not related to the defaulting, but I'm not 100% sure...?
Yeah it's old, and I long ago extracted the other part into a separate PR. Updated it now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks fine, but some of the code is a little mysterious to me still.
# The CLI will prevent this case from occurring | ||
- Ref: AWS::NoValue | ||
# The CLI will advertise that we picked this implicitly | ||
- - Fn::Sub: "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope you've verified this is the correct way to have a one-element array in YAML... this format is still a mystery to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know. It is correct though:
- - Fn::Sub: '....'
▲ ▲ ▲
│ │ └─── This makes the list element an object
│ │
│ └─── This starts a new list (because there's no bullet underneath it's a single element)
│
└───── This is the Else branch of the { Fn::If: [Cond, Then, Else] }
// we inferred it or whether the user told us, and the sequence: | ||
// | ||
// $ cdk bootstrap | ||
// $ cdk bootstrap --trust 1234 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't understand this comment... cdk bootstrap --trust 1234
should fail, right? Because we require passing --cloudformation-execution-policies
when you pass --trust
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the missing piece of context here might be that:
$ cdk bootstrap --cloudformation-execution-policies arn:aws:.../BloopAccess
$ cdk bootstrap --trust 1234
Should be valid, while:
$ cdk bootstrap
$ cdk bootstrap --trust 1234
Should not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... I'm starting to get a little uneasy about how complicated this is becoming.
For example, the following sequence:
$ cdk bootstrap --trust 1234 --cloudformation-execution-policies SomeLimitedPolicy
$ cdk bootstrap --trust 9876 --cloudformation-execution-policies AdminPolicy
Is it actually obvious to the user that with the second command they've just changed the trust to account 1234 from a limited policy to admin access?
CloudFormationExecutionPolicies: '', | ||
}), | ||
})); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like we're missing a test for the positive case (no --trust
or --cloudformation-execution-policies
passed) that checks the template? Maybe an integ test?
Approved by AppSec |
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
The current bootstrapping experience has sharp edges. It requires you
to pass
--cloudformation-execution-policies
in all cases, even ifyou just want a "simple", same-account bootstrap stack. If you bootstrap
your own accounts, you probably don't have a centralized SecOps
team that is limiting you, and you're probably intending to deploy
everything using the CDK, which means you're looking for AdministratorAccess.
In effect, you are forced to constantly Google and copy/paste the ARN
for
AdministratorAccess
(because who can remember that)and it's a bad experience.
In the case of bootstrapping an account just for use "by itself",
however (which is the 90% use case for bootstrapping),
the trust boundary is very clear and there's no risk of privilege
escalation between accounts.
Add an optimization where in the case of a "simple", non-cross account
bootstrap, we'll default to the AdministratorAccess ARN for you.
Once you establish
--trust
with another account, we'll stillforce you to spell out the execution policy you'll want to use though.
Fixes #8571.
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license