Skip to content
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(cli): can't bootstrap environment not in app #7510

Merged
merged 4 commits into from
Apr 24, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/@aws-cdk/cx-api/lib/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ export class EnvironmentUtils {
return { account, region, name: environment };
}

/**
* Build an environment object from an account and region
*/
public static make(account: string, region: string): Environment {
return { account, region, name: this.format(account, region) };
}

/**
* Format an environment string from an account and region
*/
public static format(account: string, region: string): string {
return `aws://${account}/${region}`;
}
Expand Down
23 changes: 14 additions & 9 deletions packages/aws-cdk/bin/cdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ async function parseCommandLineArguments() {
.option('tags', { type: 'array', alias: 't', desc: 'Tags to add for the stack (KEY=VALUE)', nargs: 1, requiresArg: true, default: [] })
.option('execute', {type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true})
.option('trust', { type: 'array', desc: 'The (space-separated) list of AWS account IDs that should be trusted to perform deployments into this environment', default: [], hidden: true })
.option('cloudformation-execution-policies', { type: 'array', desc: 'The (space-separated) list of Managed Policy ARNs that should be attached to the role performing deployments into this environment. Required if --trust was passed', default: [], hidden: true }),
.option('cloudformation-execution-policies', { type: 'array', desc: 'The (space-separated) list of Managed Policy ARNs that should be attached to the role performing deployments into this environment. Required if --trust was passed', default: [], hidden: true })
.option('force', { alias: 'f', type: 'boolean', desc: 'Always bootstrap even if it would downgrade template version', default: false }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense to protect against it, but what's the use case behind forcing a bootstrap and the implication of using a downgraded template version?

when would it be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to prevent people from doing what they're trying to do, in case we get it wrong (for whatever reason).

Just feels like any protection should have an 'override' feature'.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough

)
.command('deploy [STACKS..]', 'Deploys the stack(s) named STACKS into your AWS account', yargs => yargs
.option('build-exclude', { type: 'array', alias: 'E', nargs: 1, desc: 'Do not rebuild asset with the given ID. Can be specified multiple times.', default: [] })
Expand Down Expand Up @@ -209,14 +210,18 @@ async function initCommandLine() {
});

case 'bootstrap':
return await cli.bootstrap(args.ENVIRONMENTS, toolkitStackName, args.roleArn, !!process.env.CDK_NEW_BOOTSTRAP, {
bucketName: configuration.settings.get(['toolkitBucket', 'bucketName']),
kmsKeyId: configuration.settings.get(['toolkitBucket', 'kmsKeyId']),
tags: configuration.settings.get(['tags']),
execute: args.execute,
trustedAccounts: args.trust,
cloudFormationExecutionPolicies: args.cloudformationExecutionPolicies,
});
return await cli.bootstrap(args.ENVIRONMENTS, toolkitStackName,
args.roleArn,
!!process.env.CDK_NEW_BOOTSTRAP,
argv.force,
{
bucketName: configuration.settings.get(['toolkitBucket', 'bucketName']),
kmsKeyId: configuration.settings.get(['toolkitBucket', 'kmsKeyId']),
tags: configuration.settings.get(['tags']),
execute: args.execute,
trustedAccounts: args.trust,
cloudFormationExecutionPolicies: args.cloudformationExecutionPolicies,
});

case 'deploy':
const parameterMap: { [name: string]: string | undefined } = {};
Expand Down
28 changes: 10 additions & 18 deletions packages/aws-cdk/lib/api/aws-auth/sdk-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ export class SdkProvider {
* The `region` and `accountId` parameters are interpreted as in `resolveEnvironment()` (which is to
* say, `undefined` doesn't do what you expect).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment needs updating

*/
public async forEnvironment(accountId: string | undefined, region: string | undefined, mode: Mode): Promise<ISDK> {
const env = await this.resolveEnvironment(accountId, region);
public async forEnvironment(environment: cxapi.Environment, mode: Mode): Promise<ISDK> {
const env = await this.resolveEnvironment(environment);
const creds = await this.obtainCredentials(env.account, mode);
return new SDK(creds, env.region, this.sdkOptions);
}
Expand Down Expand Up @@ -153,27 +153,19 @@ export class SdkProvider {
* `undefined` actually means `undefined`, and is NOT changed to default values! Only the magic values UNKNOWN_REGION
* and UNKNOWN_ACCOUNT will be replaced with looked-up values!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

*/
public async resolveEnvironment(accountId: string | undefined, region: string | undefined) {
region = region !== cxapi.UNKNOWN_REGION ? region : this.defaultRegion;
accountId = accountId !== cxapi.UNKNOWN_ACCOUNT ? accountId : (await this.defaultAccount())?.accountId;
public async resolveEnvironment(env: cxapi.Environment): Promise<cxapi.Environment> {
const region = env.region !== cxapi.UNKNOWN_REGION ? env.region : this.defaultRegion;
const account = env.account !== cxapi.UNKNOWN_ACCOUNT ? env.account : (await this.defaultAccount())?.accountId;

if (!region) {
throw new Error('AWS region must be configured either when you configure your CDK stack or through the environment');
}
Comment on lines -160 to -162
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this dead code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep


if (!accountId) {
if (!account) {
throw new Error('Unable to resolve AWS account to use. It must be either configured when you define your CDK or through the environment');
}

const environment: cxapi.Environment = {
region, account: accountId, name: cxapi.EnvironmentUtils.format(accountId, region),
return {
region,
account,
name: cxapi.EnvironmentUtils.format(account, region),
};

return environment;
}

public async resolveEnvironmentObject(env: cxapi.Environment) {
return this.resolveEnvironment(env.account, env.region);
Comment on lines -175 to -176
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there was nothing using this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was one place, but this was the method that resolveEnvironment should have been all along.

}

/**
Expand Down
161 changes: 0 additions & 161 deletions packages/aws-cdk/lib/api/bootstrap-environment.ts

This file was deleted.

65 changes: 65 additions & 0 deletions packages/aws-cdk/lib/api/bootstrap/bootstrap-environment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as cxapi from '@aws-cdk/cx-api';
import * as path from 'path';
import { loadStructuredFile } from '../../serialize';
import { SdkProvider } from '../aws-auth';
import { DeployStackResult } from '../deploy-stack';
import { BootstrapEnvironmentOptions } from './bootstrap-props';
import { deployBootstrapStack } from './deploy-bootstrap';
import { legacyBootstrapTemplate } from './legacy-template';

// tslint:disable:max-line-length

/**
* Deploy legacy bootstrap stack
*
* @experimental
*/
export async function bootstrapEnvironment(environment: cxapi.Environment, sdkProvider: SdkProvider, options: BootstrapEnvironmentOptions): Promise<DeployStackResult> {
const params = options.parameters ?? {};

if (params.trustedAccounts?.length) {
throw new Error('--trust can only be passed for the new bootstrap experience.');
}
if (params.cloudFormationExecutionPolicies?.length) {
throw new Error('--cloudformation-execution-policies can only be passed for the new bootstrap experience.');
}

return deployBootstrapStack(
legacyBootstrapTemplate(params),
{},
environment,
sdkProvider,
options);
}

/**
* Deploy CI/CD-ready bootstrap stack from template
*
* @experimental
*/
export async function bootstrapEnvironment2(
environment: cxapi.Environment,
sdkProvider: SdkProvider,
options: BootstrapEnvironmentOptions): Promise<DeployStackResult> {

const params = options.parameters ?? {};

if (params.trustedAccounts?.length && !params.cloudFormationExecutionPolicies?.length) {
throw new Error('--cloudformation-execution-policies are required if --trust has been passed!');
}

const bootstrapTemplatePath = path.join(__dirname, 'bootstrap-template.yaml');
const bootstrapTemplate = await loadStructuredFile(bootstrapTemplatePath);

return deployBootstrapStack(
bootstrapTemplate,
{
FileAssetsBucketName: params.bucketName,
FileAssetsBucketKmsKeyId: params.kmsKeyId,
TrustedAccounts: params.trustedAccounts?.join(','),
CloudFormationExecutionPolicies: params.cloudFormationExecutionPolicies?.join(','),
},
environment,
sdkProvider,
options);
}
55 changes: 0 additions & 55 deletions packages/aws-cdk/lib/api/bootstrap/bootstrap-environment2.ts

This file was deleted.

Loading