diff --git a/src/auth/awsclient.ts b/src/auth/awsclient.ts index b2bfdcee..561954bb 100644 --- a/src/auth/awsclient.ts +++ b/src/auth/awsclient.ts @@ -58,6 +58,15 @@ interface AwsSecurityCredentials { Expiration: string; } +/** + * Interface defining the AWS security-credentials retrieved from environment variables. + */ +interface AwsSecurityCredentialsFromEnvironment { + accessKeyId: string; + secretAccessKey: string; + token?: string; +} + /** * AWS external account client. This is used for AWS workloads, where * AWS STS GetCallerIdentity serialized signed requests are exchanged for @@ -101,7 +110,7 @@ export class AwsClient extends BaseExternalAccountClient { this.awsRequestSigner = null; this.region = ''; - // data validators + // Data validators. this.validateEnvironmentId(); this.validateMetadataServerURLs(); } @@ -170,6 +179,9 @@ export class AwsClient extends BaseExternalAccountClient { const metadataHeaders: Headers = {}; // Only retrieve the IMDSv2 session token if both the security credentials and region are // not retrievable through the environment. + // The credential config contains all the URLs by default but clients may be running this + // where the metadata server is not available and returning the credentials through the environment. + // Removing this check may break them. if (this.shouldUseMetadataServer() && this.imdsV2SessionTokenUrl) { metadataHeaders['x-aws-ec2-metadata-token'] = await this.getImdsV2SessionToken(); @@ -179,16 +191,8 @@ export class AwsClient extends BaseExternalAccountClient { this.awsRequestSigner = new AwsRequestSigner(async () => { // Check environment variables for permanent credentials first. // https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html - if ( - process.env['AWS_ACCESS_KEY_ID'] && - process.env['AWS_SECRET_ACCESS_KEY'] - ) { - return { - accessKeyId: process.env['AWS_ACCESS_KEY_ID']!, - secretAccessKey: process.env['AWS_SECRET_ACCESS_KEY']!, - // This is normally not available for permanent credentials. - token: process.env['AWS_SESSION_TOKEN'], - }; + if (this.securityCredentialsFromEnvironment) { + return this.securityCredentialsFromEnvironment; } // Since the role on a VM can change, we don't need to cache it. const roleName = await this.getAwsRoleName(metadataHeaders); @@ -275,8 +279,8 @@ export class AwsClient extends BaseExternalAccountClient { private async getAwsRegion(headers: Headers): Promise { // Priority order for region determination: // AWS_REGION > AWS_DEFAULT_REGION > metadata server. - if (process.env['AWS_REGION'] || process.env['AWS_DEFAULT_REGION']) { - return (process.env['AWS_REGION'] || process.env['AWS_DEFAULT_REGION'])!; + if (this.regionFromEnvironment) { + return this.regionFromEnvironment; } if (!this.regionUrl) { throw new Error( @@ -339,22 +343,34 @@ export class AwsClient extends BaseExternalAccountClient { } private shouldUseMetadataServer(): boolean { + // The metadata server must be used when either the AWS region or AWS security + // credentials cannot be retrieved through their defined environment variables. return ( - !this.canRetrieveRegionFromEnvironment() || - !this.canRetrieveSecurityCredentialsFromEnvironment() + !this.regionFromEnvironment || !this.securityCredentialsFromEnvironment ); } - private canRetrieveRegionFromEnvironment(): boolean { + private get regionFromEnvironment(): string | undefined { // The AWS region can be provided through AWS_REGION or AWS_DEFAULT_REGION. // Only one is required. - return !!(process.env['AWS_REGION'] || process.env['AWS_DEFAULT_REGION']); + return process.env['AWS_REGION'] || process.env['AWS_DEFAULT_REGION']; } - private canRetrieveSecurityCredentialsFromEnvironment(): boolean { + private get securityCredentialsFromEnvironment(): + | AwsSecurityCredentialsFromEnvironment + | undefined { + let awsSecurityCredentials; // Check if both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are available. - return !!( - process.env['AWS_ACCESS_KEY_ID'] && process.env['AWS_SECRET_ACCESS_KEY'] - ); + if ( + process.env['AWS_ACCESS_KEY_ID'] && + process.env['AWS_SECRET_ACCESS_KEY'] + ) { + awsSecurityCredentials = { + accessKeyId: process.env['AWS_ACCESS_KEY_ID'], + secretAccessKey: process.env['AWS_SECRET_ACCESS_KEY'], + token: process.env['AWS_SESSION_TOKEN'], + }; + } + return awsSecurityCredentials; } }