Skip to content

Commit

Permalink
fix(bootstrap): add previous-parameters option to bootstrap command (
Browse files Browse the repository at this point in the history
…#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*
  • Loading branch information
corymhall authored Apr 21, 2023
1 parent 81beab3 commit 02e8758
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 2 deletions.
8 changes: 8 additions & 0 deletions packages/@aws-cdk-testing/cli-integ/lib/with-cdk-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ export interface CdkModernBootstrapCommandOptions extends CommonCdkBootstrapComm
* @default undefined
*/
readonly customPermissionsBoundary?: string;

/**
* @default undefined
*/
readonly usePreviousParameters?: boolean;
}

export class TestFixture extends ShellHelper {
Expand Down Expand Up @@ -359,6 +364,9 @@ export class TestFixture extends ShellHelper {
} else if (options.examplePermissionsBoundary !== undefined) {
args.push('--example-permissions-boundary');
}
if (options.usePreviousParameters === false) {
args.push('--no-previous-parameters');
}

return this.cdk(args, {
...options.cliOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,58 @@ integTest('can use the custom permissions boundary to bootstrap', withoutBootstr
expect(template).toContain('permission-boundary-name');
}));

integTest('can remove customPermissionsBoundary', withoutBootstrap(async (fixture) => {
const bootstrapStackName = fixture.bootstrapStackName;
const policyName = `${bootstrapStackName}-pb`;
let policyArn;
try {
const policy = await fixture.aws.iam('createPolicy', {
PolicyName: policyName,
PolicyDocument: JSON.stringify({
Version: '2012-10-17',
Statement: {
Action: ['*'],
Resource: ['*'],
Effect: 'Allow',
},
}),
});
policyArn = policy.Policy?.Arn;
await fixture.cdkBootstrapModern({
// toolkitStackName doesn't matter for this particular invocation
toolkitStackName: bootstrapStackName,
customPermissionsBoundary: policyName,
});

const response = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName });
expect(
response.Stacks?.[0].Parameters?.some(
param => (param.ParameterKey === 'InputPermissionsBoundary' && param.ParameterValue === policyName),
)).toEqual(true);

await fixture.cdkBootstrapModern({
// toolkitStackName doesn't matter for this particular invocation
toolkitStackName: bootstrapStackName,
usePreviousParameters: false,
});
const response2 = await fixture.aws.cloudFormation('describeStacks', { StackName: bootstrapStackName });
expect(
response2.Stacks?.[0].Parameters?.some(
param => (param.ParameterKey === 'InputPermissionsBoundary' && !param.ParameterValue),
)).toEqual(true);

const region = fixture.aws.region;
const account = await fixture.aws.account();
const role = await fixture.aws.iam('getRole', { RoleName: `cdk-${fixture.qualifier}-cfn-exec-role-${account}-${region}` });
expect(role.Role.PermissionsBoundary).toBeUndefined();

} finally {
if (policyArn) {
await fixture.aws.iam('deletePolicy', { PolicyArn: policyArn });
}
}
}));

integTest('switch on termination protection, switch is left alone on re-bootstrap', withoutBootstrap(async (fixture) => {
const bootstrapStackName = fixture.bootstrapStackName;

Expand Down
20 changes: 20 additions & 0 deletions packages/aws-cdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,26 @@ as, most likely, a permissions boundary is maintained and has dedicated conventi
For more information on configuring permissions, including using permissions
boundaries see the [Security And Safety Dev Guide](https://github.com/aws/aws-cdk/wiki/Security-And-Safety-Dev-Guide)

Once a bootstrap template has been deployed with a set of parameters, you must
use the `--no-previous-parameters` CLI flag to change any of these parameters on
future deployments.

> **Note** Please note that when you use this flag, you must resupply
>*all* previously supplied parameters.
For example if you bootstrap with a custom permissions boundary

```console
cdk bootstrap --custom-permissions-boundary my-permissions-boundary
```

In order to remove that permissions boundary you have to specify the
`--no-previous-parameters` option.

```console
cdk bootstrap --no-previous-parameters
```

### `cdk doctor`

Inspect the current command-line environment and configurations, and collect information that can be useful for
Expand Down
9 changes: 9 additions & 0 deletions packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ export interface BootstrapEnvironmentOptions {
* @default true
*/
readonly terminationProtection?: boolean;

/**
* Use previous values for unspecified parameters
*
* If not set, all parameters must be specified for every deployment.
*
* @default true
*/
usePreviousParameters?: boolean;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class BootstrapStack {
tags: options.tags,
deploymentMethod: { method: 'change-set', execute: options.execute },
parameters,
usePreviousParameters: true,
usePreviousParameters: options.usePreviousParameters ?? true,
// Obviously we can't need a bootstrap stack to deploy a bootstrap stack
toolkitInfo: ToolkitInfo.bootstraplessDeploymentsOnly(this.sdk),
});
Expand Down
4 changes: 3 additions & 1 deletion packages/aws-cdk/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ async function parseCommandLineArguments(args: string[]) {
.option('termination-protection', { type: 'boolean', default: undefined, desc: 'Toggle CloudFormation termination protection on the bootstrap stacks' })
.option('show-template', { type: 'boolean', desc: 'Instead of actual bootstrapping, print the current CLI\'s bootstrapping template to stdout for customization', default: false })
.option('toolkit-stack-name', { type: 'string', desc: 'The name of the CDK toolkit stack to create', requiresArg: true })
.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)' }),
.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)' })
.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)' }),
)
.command('deploy [STACKS..]', 'Deploys the stack(s) named STACKS into your AWS account', (yargs: Argv) => yargs
.option('all', { type: 'boolean', default: false, desc: 'Deploy all available stacks' })
Expand Down Expand Up @@ -499,6 +500,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
execute: args.execute,
tags: configuration.settings.get(['tags']),
terminationProtection: args.terminationProtection,
usePreviousParameters: args['previous-parameters'],
parameters: {
bucketName: configuration.settings.get(['toolkitBucket', 'bucketName']),
kmsKeyId: configuration.settings.get(['toolkitBucket', 'kmsKeyId']),
Expand Down

0 comments on commit 02e8758

Please sign in to comment.