diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 8c3d9f3309d11..6e4eacb20293e 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -36,6 +36,7 @@ async function parseCommandLineArguments() { .option('verbose', { type: 'boolean', alias: 'v', desc: 'Show debug logs', default: false }) .option('profile', { type: 'string', desc: 'Use the indicated AWS profile as the default environment', requiresArg: true }) .option('proxy', { type: 'string', desc: 'Use the indicated proxy. Will read from HTTPS_PROXY environment variable if not specified.', requiresArg: true }) + .option('ca-bundle-path', { type: 'string', desc: 'Path to CA certificate to use when validating HTTPS requests. Will read from AWS_CA_BUNDLE environment variable if not specified.', requiresArg: true }) .option('ec2creds', { type: 'boolean', alias: 'i', default: undefined, desc: 'Force trying to fetch EC2 instance credentials. Default: guess EC2 instance status.' }) .option('version-reporting', { type: 'boolean', desc: 'Include the "AWS::CDK::Metadata" resource in synthesized templates (enabled by default)', default: undefined }) .option('path-metadata', { type: 'boolean', desc: 'Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default)', default: true }) @@ -107,6 +108,7 @@ async function initCommandLine() { const aws = new SDK({ profile: argv.profile, proxyAddress: argv.proxy, + caBundlePath: argv['ca-bundle-path'], ec2creds: argv.ec2creds, }); diff --git a/packages/aws-cdk/lib/api/util/sdk.ts b/packages/aws-cdk/lib/api/util/sdk.ts index 0546987b7dcd4..8ecb566450c28 100644 --- a/packages/aws-cdk/lib/api/util/sdk.ts +++ b/packages/aws-cdk/lib/api/util/sdk.ts @@ -2,6 +2,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as AWS from 'aws-sdk'; import * as child_process from 'child_process'; import * as fs from 'fs-extra'; +import * as https from 'https'; import * as os from 'os'; import * as path from 'path'; import * as util from 'util'; @@ -53,6 +54,13 @@ export interface SDKOptions { * @default Automatically determine. */ ec2creds?: boolean; + + /** + * A path to a certificate bundle that contains a cert to be trusted. + * + * @default No certificate bundle + */ + caBundlePath?: string; } /** @@ -88,23 +96,7 @@ export class SDK implements ISDK { const defaultCredentialProvider = makeCLICompatibleCredentialProvider(options.profile, options.ec2creds); - // Find the package.json from the main toolkit - const pkg = (require.main as any).require('../package.json'); - AWS.config.update({ - customUserAgent: `${pkg.name}/${pkg.version}` - }); - - // https://aws.amazon.com/blogs/developer/using-the-aws-sdk-for-javascript-from-behind-a-proxy/ - if (options.proxyAddress === undefined) { - options.proxyAddress = httpsProxyFromEnvironment(); - } - if (options.proxyAddress) { // Ignore empty string on purpose - debug('Using proxy server: %s', options.proxyAddress); - AWS.config.update({ - // eslint-disable-next-line @typescript-eslint/no-require-imports - httpOptions: { agent: require('proxy-agent')(options.proxyAddress) } - }); - } + this.configureSDKHttpOptions(options); this.defaultAwsAccount = new DefaultAWSAccount(defaultCredentialProvider, getCLICompatibleDefaultRegionGetter(this.profile)); this.credentialsCache = new CredentialsCache(this.defaultAwsAccount, defaultCredentialProvider); @@ -196,6 +188,29 @@ export class SDK implements ISDK { return environment; } + private async configureSDKHttpOptions(options: SDKOptions) { + const config: {[k: string]: any} = {}; + const httpOptions: {[k: string]: any} = {}; + // Find the package.json from the main toolkit + const pkg = (require.main as any).require('../package.json'); + config.customUserAgent = `${pkg.name}/${pkg.version}`; + + // https://aws.amazon.com/blogs/developer/using-the-aws-sdk-for-javascript-from-behind-a-proxy/ + options.proxyAddress = options.proxyAddress || httpsProxyFromEnvironment(); + options.caBundlePath = options.caBundlePath || caBundlePathFromEnvironment(); + + if (options.proxyAddress) { // Ignore empty string on purpose + debug('Using proxy server: %s', options.proxyAddress); + httpOptions.proxy = options.proxyAddress; + } + if (options.caBundlePath) { + debug('Using ca bundle path: %s', options.caBundlePath); + httpOptions.agent = new https.Agent({ca: await readIfPossible(options.caBundlePath)}); + } + config.httpOptions = httpOptions; + + AWS.config.update(config); + } } /** @@ -438,6 +453,19 @@ function httpsProxyFromEnvironment(): string | undefined { return undefined; } +/** + * Find and return a CA certificate bundle path to be passed into the SDK. + */ +function caBundlePathFromEnvironment(): string | undefined { + if (process.env.aws_ca_bundle) { + return process.env.aws_ca_bundle; + } + if (process.env.AWS_CA_BUNDLE) { + return process.env.AWS_CA_BUNDLE; + } + return undefined; +} + /** * Return whether it looks like we'll have ECS credentials available */ diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index f1c456eadae1b..de81ee942db80 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -82,7 +82,6 @@ "json-diff": "^0.5.4", "minimatch": ">=3.0", "promptly": "^3.0.3", - "proxy-agent": "^3.1.1", "request": "^2.88.0", "semver": "^7.1.1", "source-map-support": "^0.5.16",