diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index e73e37f8ff994..9aaaa73f05721 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -729,7 +729,7 @@ async function initCommandLine() { */ async function populateDefaultEnvironmentIfNeeded(context: any) { if (!(cxapi.DEFAULT_REGION_CONTEXT_KEY in context)) { - context[cxapi.DEFAULT_REGION_CONTEXT_KEY] = aws.defaultRegion(); + context[cxapi.DEFAULT_REGION_CONTEXT_KEY] = await aws.defaultRegion(); debug(`Setting "${cxapi.DEFAULT_REGION_CONTEXT_KEY}" context to`, context[cxapi.DEFAULT_REGION_CONTEXT_KEY]); } diff --git a/packages/aws-cdk/lib/api/util/sdk.ts b/packages/aws-cdk/lib/api/util/sdk.ts index cfcde34f1cd14..49e24cb84658a 100644 --- a/packages/aws-cdk/lib/api/util/sdk.ts +++ b/packages/aws-cdk/lib/api/util/sdk.ts @@ -1,5 +1,6 @@ import { Environment} from '@aws-cdk/cx-api'; import AWS = require('aws-sdk'); +import fs = require('fs-extra'); import os = require('os'); import path = require('path'); import { debug } from '../../logging'; @@ -22,13 +23,12 @@ export class SDK { private defaultAccountId?: string = undefined; private readonly userAgent: string; private readonly accountCache = new AccountAccessKeyCache(); - private readonly defaultCredentialProvider: AWS.CredentialProviderChain; + private defaultCredentialProvider?: AWS.CredentialProviderChain; 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}`; - this.defaultCredentialProvider = makeCLICompatibleCredentialProvider(profile); } public async cloudFormation(environment: Environment, mode: Mode): Promise { @@ -63,8 +63,8 @@ export class SDK { }); } - public defaultRegion(): string | undefined { - return getCLICompatibleDefaultRegion(this.profile); + public async defaultRegion(): Promise { + return await getCLICompatibleDefaultRegion(this.profile); } public async defaultAccount(): Promise { @@ -78,6 +78,9 @@ export class SDK { private async lookupDefaultAccount() { try { debug('Resolving default credentials'); + if (!this.defaultCredentialProvider) { + this.defaultCredentialProvider = await makeCLICompatibleCredentialProvider(this.profile); + } const creds = await this.defaultCredentialProvider.resolvePromise(); const accessKeyId = creds.accessKeyId; if (!accessKeyId) { @@ -147,7 +150,7 @@ export class SDK { * file location is not given (SDK expects explicit environment variable with name). * - AWS_DEFAULT_PROFILE is also inspected for profile name (not just AWS_PROFILE). */ -function makeCLICompatibleCredentialProvider(profile: string | undefined) { +async function makeCLICompatibleCredentialProvider(profile: string | undefined) { profile = profile || process.env.AWS_PROFILE || process.env.AWS_DEFAULT_PROFILE || 'default'; // Need to construct filename ourselves, without appropriate environment variables @@ -157,7 +160,7 @@ function makeCLICompatibleCredentialProvider(profile: string | undefined) { return new AWS.CredentialProviderChain([ () => new AWS.EnvironmentCredentials('AWS'), () => new AWS.EnvironmentCredentials('AMAZON'), - () => new AWS.SharedIniFileCredentials({ profile, filename }), + ...(await fs.pathExists(filename) ? [() => new AWS.SharedIniFileCredentials({ profile, filename })] : []), () => { // Calling private API if ((AWS.ECSCredentials.prototype as any).isConfiguredForEcsCredentials()) { @@ -181,7 +184,7 @@ function makeCLICompatibleCredentialProvider(profile: string | undefined) { * - AWS_DEFAULT_PROFILE and AWS_DEFAULT_REGION are also used as environment * variables to be used to determine the region. */ -function getCLICompatibleDefaultRegion(profile: string | undefined): string | undefined { +async function getCLICompatibleDefaultRegion(profile: string | undefined): Promise { profile = profile || process.env.AWS_PROFILE || process.env.AWS_DEFAULT_PROFILE || 'default'; // Defaults inside constructor @@ -195,9 +198,9 @@ function getCLICompatibleDefaultRegion(profile: string | undefined): string | un while (!region && toCheck.length > 0) { const configFile = new SharedIniFile(toCheck.shift()); - const section = configFile.getProfile(profile); + const section = await configFile.getProfile(profile); region = section && section.region; } return region; -} \ No newline at end of file +} diff --git a/packages/aws-cdk/lib/api/util/sdk_ini_file.ts b/packages/aws-cdk/lib/api/util/sdk_ini_file.ts index fc21bac2b0e49..826a5a5ffe992 100644 --- a/packages/aws-cdk/lib/api/util/sdk_ini_file.ts +++ b/packages/aws-cdk/lib/api/util/sdk_ini_file.ts @@ -6,6 +6,7 @@ */ import AWS = require('aws-sdk'); +import fs = require('fs-extra'); import os = require('os'); import path = require('path'); @@ -25,8 +26,8 @@ export class SharedIniFile { this.filename = options.filename || this.getDefaultFilepath(); } - public getProfile(profile: string) { - this.ensureFileLoaded(); + public async getProfile(profile: string) { + await this.ensureFileLoaded(); const profileIndex = profile !== (AWS as any).util.defaultProfile && this.isConfig ? 'profile ' + profile : profile; @@ -42,11 +43,11 @@ export class SharedIniFile { ); } - private ensureFileLoaded() { + private async ensureFileLoaded() { if (!this.parsedContents) { - this.parsedContents = (AWS as any).util.ini.parse( - (AWS as any).util.readFileSync(this.filename) - ); + this.parsedContents = await fs.pathExists(this.filename) + ? (AWS as any).util.ini.parse(await fs.readFile(this.filename)) + : {}; } } -} \ No newline at end of file +}