Skip to content

Commit 02e8758

Browse files
authored
fix(bootstrap): add previous-parameters option to bootstrap command (#25219)
A recent change was made to explicitly set the `usePreviousParameters` when deploying the bootstrap template. This is because if a template is deployed once by a user with a set of parameters and then later by another user we shouldn't drop those previously set parameters. This PR adds the option for the user to control this behavior. If the user needs to turn this off they can provide the `--no-previous-parameters` option. fixes #23780 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 81beab3 commit 02e8758

File tree

6 files changed

+93
-2
lines changed

6 files changed

+93
-2
lines changed

packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts

+8
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,11 @@ export interface CdkModernBootstrapCommandOptions extends CommonCdkBootstrapComm
242242
* @default undefined
243243
*/
244244
readonly customPermissionsBoundary?: string;
245+
246+
/**
247+
* @default undefined
248+
*/
249+
readonly usePreviousParameters?: boolean;
245250
}
246251

247252
export class TestFixture extends ShellHelper {
@@ -359,6 +364,9 @@ export class TestFixture extends ShellHelper {
359364
} else if (options.examplePermissionsBoundary !== undefined) {
360365
args.push('--example-permissions-boundary');
361366
}
367+
if (options.usePreviousParameters === false) {
368+
args.push('--no-previous-parameters');
369+
}
362370

363371
return this.cdk(args, {
364372
...options.cliOptions,

packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/bootstrapping.integtest.ts

+52
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,58 @@ integTest('can use the custom permissions boundary to bootstrap', withoutBootstr
254254
expect(template).toContain('permission-boundary-name');
255255
}));
256256

257+
integTest('can remove customPermissionsBoundary', withoutBootstrap(async (fixture) => {
258+
const bootstrapStackName = fixture.bootstrapStackName;
259+
const policyName = `${bootstrapStackName}-pb`;
260+
let policyArn;
261+
try {
262+
const policy = await fixture.aws.iam('createPolicy', {
263+
PolicyName: policyName,
264+
PolicyDocument: JSON.stringify({
265+
Version: '2012-10-17',
266+
Statement: {
267+
Action: ['*'],
268+
Resource: ['*'],
269+
Effect: 'Allow',
270+
},
271+
}),
272+
});
273+
policyArn = policy.Policy?.Arn;
274+
await fixture.cdkBootstrapModern({
275+
// toolkitStackName doesn't matter for this particular invocation
276+
toolkitStackName: bootstrapStackName,
277+
customPermissionsBoundary: policyName,
278+
});
279+
280+
const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName });
281+
expect(
282+
response.Stacks?.[0].Parameters?.some(
283+
param => (param.ParameterKey === 'InputPermissionsBoundary' && param.ParameterValue === policyName),
284+
)).toEqual(true);
285+
286+
await fixture.cdkBootstrapModern({
287+
// toolkitStackName doesn't matter for this particular invocation
288+
toolkitStackName: bootstrapStackName,
289+
usePreviousParameters: false,
290+
});
291+
const response2 = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName });
292+
expect(
293+
response2.Stacks?.[0].Parameters?.some(
294+
param => (param.ParameterKey === 'InputPermissionsBoundary' && !param.ParameterValue),
295+
)).toEqual(true);
296+
297+
const region = fixture.aws.region;
298+
const account = await fixture.aws.account();
299+
const role = await fixture.aws.iam('getRole', { RoleName: `cdk-${fixture.qualifier}-cfn-exec-role-${account}-${region}` });
300+
expect(role.Role.PermissionsBoundary).toBeUndefined();
301+
302+
} finally {
303+
if (policyArn) {
304+
await fixture.aws.iam('deletePolicy', { PolicyArn: policyArn });
305+
}
306+
}
307+
}));
308+
257309
integTest('switch on termination protection, switch is left alone on re-bootstrap', withoutBootstrap(async (fixture) => {
258310
const bootstrapStackName = fixture.bootstrapStackName;
259311

packages/aws-cdk/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,26 @@ as, most likely, a permissions boundary is maintained and has dedicated conventi
609609
For more information on configuring permissions, including using permissions
610610
boundaries see the [Security And Safety Dev Guide](https://github.com/aws/aws-cdk/wiki/Security-And-Safety-Dev-Guide)
611611

612+
Once a bootstrap template has been deployed with a set of parameters, you must
613+
use the `--no-previous-parameters` CLI flag to change any of these parameters on
614+
future deployments.
615+
616+
> **Note** Please note that when you use this flag, you must resupply
617+
>*all* previously supplied parameters.
618+
619+
For example if you bootstrap with a custom permissions boundary
620+
621+
```console
622+
cdk bootstrap --custom-permissions-boundary my-permissions-boundary
623+
```
624+
625+
In order to remove that permissions boundary you have to specify the
626+
`--no-previous-parameters` option.
627+
628+
```console
629+
cdk bootstrap --no-previous-parameters
630+
```
631+
612632
### `cdk doctor`
613633

614634
Inspect the current command-line environment and configurations, and collect information that can be useful for

packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts

+9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ export interface BootstrapEnvironmentOptions {
4040
* @default true
4141
*/
4242
readonly terminationProtection?: boolean;
43+
44+
/**
45+
* Use previous values for unspecified parameters
46+
*
47+
* If not set, all parameters must be specified for every deployment.
48+
*
49+
* @default true
50+
*/
51+
usePreviousParameters?: boolean;
4352
}
4453

4554
/**

packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export class BootstrapStack {
119119
tags: options.tags,
120120
deploymentMethod: { method: 'change-set', execute: options.execute },
121121
parameters,
122-
usePreviousParameters: true,
122+
usePreviousParameters: options.usePreviousParameters ?? true,
123123
// Obviously we can't need a bootstrap stack to deploy a bootstrap stack
124124
toolkitInfo: ToolkitInfo.bootstraplessDeploymentsOnly(this.sdk),
125125
});

packages/aws-cdk/lib/cli.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ async function parseCommandLineArguments(args: string[]) {
109109
.option('termination-protection', { type: 'boolean', default: undefined, desc: 'Toggle CloudFormation termination protection on the bootstrap stacks' })
110110
.option('show-template', { type: 'boolean', desc: 'Instead of actual bootstrapping, print the current CLI\'s bootstrapping template to stdout for customization', default: false })
111111
.option('toolkit-stack-name', { type: 'string', desc: 'The name of the CDK toolkit stack to create', requiresArg: true })
112-
.option('template', { type: 'string', requiresArg: true, desc: 'Use the template from the given file instead of the built-in one (use --show-template to obtain an example)' }),
112+
.option('template', { type: 'string', requiresArg: true, desc: 'Use the template from the given file instead of the built-in one (use --show-template to obtain an example)' })
113+
.option('previous-parameters', { type: 'boolean', default: true, desc: 'Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled)' }),
113114
)
114115
.command('deploy [STACKS..]', 'Deploys the stack(s) named STACKS into your AWS account', (yargs: Argv) => yargs
115116
.option('all', { type: 'boolean', default: false, desc: 'Deploy all available stacks' })
@@ -499,6 +500,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
499500
execute: args.execute,
500501
tags: configuration.settings.get(['tags']),
501502
terminationProtection: args.terminationProtection,
503+
usePreviousParameters: args['previous-parameters'],
502504
parameters: {
503505
bucketName: configuration.settings.get(['toolkitBucket', 'bucketName']),
504506
kmsKeyId: configuration.settings.get(['toolkitBucket', 'kmsKeyId']),

0 commit comments

Comments
 (0)