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

feat(aws-cdk): add support for HTTPS_PROXY #666

Merged
merged 4 commits into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
36 changes: 23 additions & 13 deletions docs/src/tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,31 @@ Below are the actions you can take on your CDK app:
init [TEMPLATE] Create a new, empty CDK project from a template.
Invoked without TEMPLATE, the app template will be
used.
doctor Check your set-up for potential problems

Options:
--help Show help [boolean]
--app, -a REQUIRED: Command-line of cloud executable (e.g. "node
bin/my-app.js") [string]
--context, -c Add contextual string parameter. [array]
--plugin, -p Name or path of a node package that extend the CDK features.
Can be specified multiple times [array]
--rename Rename stack name if different then the one defined in the
cloud executable [string]
--trace Print trace for stack warnings [boolean]
--strict Do not construct stacks with warnings [boolean]
--json, -j Use JSON output instead of YAML [boolean]
--verbose, -v Show debug logs [boolean]
--version Show version number [boolean]
--app, -a REQUIRED: Command-line for executing your CDK app (e.g.
"node bin/my-app.js") [string]
--context, -c Add contextual string parameter. [array]
--plugin, -p Name or path of a node package that extend the CDK
features. Can be specified multiple times [array]
--rename Rename stack name if different then the one defined in
the cloud executable [string]
--trace Print trace for stack warnings [boolean]
--strict Do not construct stacks with warnings [boolean]
--ignore-errors Ignores synthesis errors, which will likely produce an
invalid output [boolean] [default: false]
--json, -j Use JSON output instead of YAML [boolean]
--verbose, -v Show debug logs [boolean]
--profile Use the indicated AWS profile as the default environment
[string]
--proxy Use the indicated proxy. Will read from HTTPS_PROXY
environment variable if not specified. [string]
--version-reporting Disable insersion of the CDKMetadata resource in
synthesized templates [boolean]
--version Show version number [boolean]
--help Show help [boolean]


If your app has a single stack, there is no need to specify the stack name

Expand Down
3 changes: 2 additions & 1 deletion packages/aws-cdk/bin/cdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ async function parseCommandLineArguments() {
.option('json', { type: 'boolean', alias: 'j', desc: 'Use JSON output instead of YAML' })
.option('verbose', { type: 'boolean', alias: 'v', desc: 'Show debug logs' })
.option('profile', { type: 'string', desc: 'Use the indicated AWS profile as the default environment' })
.option('proxy', { type: 'string', desc: 'Use the indicated proxy. Will read from HTTPS_PROXY environment variable if not specified.' })
// tslint:disable-next-line:max-line-length
.option('version-reporting', { type: 'boolean', desc: 'Disable insersion of the CDKMetadata resource in synthesized templates', default: undefined })
.command([ 'list', 'ls' ], 'Lists all stacks in the app', yargs => yargs
Expand Down Expand Up @@ -108,7 +109,7 @@ async function initCommandLine() {

debug('Command line arguments:', argv);

const aws = new SDK(argv.profile);
const aws = new SDK(argv.profile, argv.proxy);

const availableContextProviders: contextplugins.ProviderMap = {
'availability-zones': new contextplugins.AZContextProviderPlugin(aws),
Expand Down
59 changes: 47 additions & 12 deletions packages/aws-cdk/lib/api/util/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,50 +19,61 @@ import { SharedIniFile } from './sdk_ini_file';
* to the requested account.
*/
export class SDK {
private readonly userAgent: string;
private readonly defaultAwsAccount: DefaultAWSAccount;
private readonly credentialsCache: CredentialsCache;
private readonly defaultClientArgs: any = {};

constructor(private readonly profile: string | undefined) {
// Find the package.json from the main toolkit
const pkg = (require.main as any).require('../package.json');
this.userAgent = `${pkg.name}/${pkg.version}`;

constructor(private readonly profile: string | undefined, proxyAddress: string | undefined) {
const defaultCredentialProvider = makeCLICompatibleCredentialProvider(profile);

this.defaultAwsAccount = new DefaultAWSAccount(defaultCredentialProvider);
this.credentialsCache = new CredentialsCache(this.defaultAwsAccount, defaultCredentialProvider);

// Find the package.json from the main toolkit
const pkg = (require.main as any).require('../package.json');
this.defaultClientArgs.userAgent = `${pkg.name}/${pkg.version}`;

// https://aws.amazon.com/blogs/developer/using-the-aws-sdk-for-javascript-from-behind-a-proxy/
if (proxyAddress === undefined) {
proxyAddress = httpsProxyFromEnvironment();
}
if (proxyAddress) { // Ignore empty string on purpose
debug('Using proxy server: %s', proxyAddress);
this.defaultClientArgs.httpOptions = {
agent: require('proxy-agent')(proxyAddress)
};
}
}

public async cloudFormation(environment: Environment, mode: Mode): Promise<AWS.CloudFormation> {
return new AWS.CloudFormation({
region: environment.region,
credentials: await this.credentialsCache.get(environment.account, mode),
customUserAgent: this.userAgent
...this.defaultClientArgs
});
}

public async ec2(awsAccountId: string | undefined, region: string | undefined, mode: Mode): Promise<AWS.EC2> {
return new AWS.EC2({
region,
credentials: await this.credentialsCache.get(awsAccountId, mode),
customUserAgent: this.userAgent
...this.defaultClientArgs
});
}

public async ssm(awsAccountId: string | undefined, region: string | undefined, mode: Mode): Promise<AWS.SSM> {
return new AWS.SSM({
region,
credentials: await this.credentialsCache.get(awsAccountId, mode),
customUserAgent: this.userAgent
...this.defaultClientArgs
});
}

public async s3(environment: Environment, mode: Mode): Promise<AWS.S3> {
return new AWS.S3({
region: environment.region,
credentials: await this.credentialsCache.get(environment.account, mode),
customUserAgent: this.userAgent
...this.defaultClientArgs
});
}

Expand Down Expand Up @@ -109,7 +120,11 @@ class CredentialsCache {
const defaultAccount = await this.defaultAwsAccount.get();
if (!awsAccountId || awsAccountId === defaultAccount) {
debug(`Using default AWS SDK credentials for account ${awsAccountId}`);
return this.defaultCredentialProvider;

// CredentialProviderChain extends Credentials, but that is a lie.
// https://github.com/aws/aws-sdk-js/issues/2235
// Call resolve() instead.
return (await this.defaultCredentialProvider).resolvePromise();
eladb marked this conversation as resolved.
Show resolved Hide resolved
}

const triedSources: CredentialProviderSource[] = [];
Expand All @@ -122,7 +137,14 @@ class CredentialsCache {
triedSources.push(source);
if (!(await source.canProvideCredentials(awsAccountId))) { continue; }
debug(`Using ${source.name} credentials for account ${awsAccountId}`);
return await source.getProvider(awsAccountId, mode);
const providerOrCreds = await source.getProvider(awsAccountId, mode);

// Backwards compatibility: if the plugin returns a ProviderChain, resolve that chain.
// Otherwise it must have returned credentials.
if ((providerOrCreds as any).resolvePromise) {
return await (providerOrCreds as any).resolvePromise();
}
return providerOrCreds;
}
const sourceNames = ['default credentials'].concat(triedSources.map(s => s.name)).join(', ');
throw new Error(`Need to perform AWS calls for account ${awsAccountId}, but no credentials found. Tried: ${sourceNames}.`);
Expand Down Expand Up @@ -256,3 +278,16 @@ async function getCLICompatibleDefaultRegion(profile: string | undefined): Promi

return region;
}

/**
* Find and return the configured HTTPS proxy address
*/
function httpsProxyFromEnvironment(): string | undefined {
if (process.env.https_proxy) {
return process.env.https_proxy;
}
if (process.env.HTTPS_PROXY) {
return process.env.HTTPS_PROXY;
}
return undefined;
}
1 change: 1 addition & 0 deletions packages/aws-cdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"json-diff": "^0.3.1",
"minimatch": ">=3.0",
"promptly": "^0.2.0",
"proxy-agent": "^3.0.1",
"request": "^2.83.0",
"source-map-support": "^0.5.6",
"yamljs": "^0.2.0",
Expand Down