1- import * as process from 'process' ;
2-
31import type { Binary , BSONSerializeOptions } from '../../bson' ;
42import * as BSON from '../../bson' ;
5- import { aws4 , type AWSCredentials , getAwsCredentialProvider } from '../../deps' ;
3+ import { aws4 } from '../../deps' ;
64import {
7- MongoAWSError ,
85 MongoCompatibilityError ,
96 MongoMissingCredentialsError ,
107 MongoRuntimeError
118} from '../../error' ;
12- import { ByteUtils , maxWireVersion , ns , randomBytes , request } from '../../utils' ;
9+ import { ByteUtils , maxWireVersion , ns , randomBytes } from '../../utils' ;
1310import { type AuthContext , AuthProvider } from './auth_provider' ;
11+ import {
12+ AWSSDKCredentialProvider ,
13+ type AWSTempCredentials ,
14+ AWSTemporaryCredentialProvider ,
15+ LegacyAWSTemporaryCredentialProvider
16+ } from './aws_temporary_credentials' ;
1417import { MongoCredentials } from './mongo_credentials' ;
1518import { AuthMechanism } from './providers' ;
1619
17- /**
18- * The following regions use the global AWS STS endpoint, sts.amazonaws.com, by default
19- * https://docs.aws.amazon.com/sdkref/latest/guide/feature-sts-regionalized-endpoints.html
20- */
21- const LEGACY_REGIONS = new Set ( [
22- 'ap-northeast-1' ,
23- 'ap-south-1' ,
24- 'ap-southeast-1' ,
25- 'ap-southeast-2' ,
26- 'aws-global' ,
27- 'ca-central-1' ,
28- 'eu-central-1' ,
29- 'eu-north-1' ,
30- 'eu-west-1' ,
31- 'eu-west-2' ,
32- 'eu-west-3' ,
33- 'sa-east-1' ,
34- 'us-east-1' ,
35- 'us-east-2' ,
36- 'us-west-1' ,
37- 'us-west-2'
38- ] ) ;
3920const ASCII_N = 110 ;
40- const AWS_RELATIVE_URI = 'http://169.254.170.2' ;
41- const AWS_EC2_URI = 'http://169.254.169.254' ;
42- const AWS_EC2_PATH = '/latest/meta-data/iam/security-credentials' ;
4321const bsonOptions : BSONSerializeOptions = {
4422 useBigInt64 : false ,
4523 promoteLongs : true ,
@@ -55,40 +33,13 @@ interface AWSSaslContinuePayload {
5533}
5634
5735export class MongoDBAWS extends AuthProvider {
58- static credentialProvider : ReturnType < typeof getAwsCredentialProvider > ;
59- provider ?: ( ) => Promise < AWSCredentials > ;
60-
36+ private credentialFetcher : AWSTemporaryCredentialProvider ;
6137 constructor ( ) {
6238 super ( ) ;
63- MongoDBAWS . credentialProvider ??= getAwsCredentialProvider ( ) ;
64-
65- let { AWS_STS_REGIONAL_ENDPOINTS = '' , AWS_REGION = '' } = process . env ;
66- AWS_STS_REGIONAL_ENDPOINTS = AWS_STS_REGIONAL_ENDPOINTS . toLowerCase ( ) ;
67- AWS_REGION = AWS_REGION . toLowerCase ( ) ;
68-
69- /** The option setting should work only for users who have explicit settings in their environment, the driver should not encode "defaults" */
70- const awsRegionSettingsExist =
71- AWS_REGION . length !== 0 && AWS_STS_REGIONAL_ENDPOINTS . length !== 0 ;
72-
73- /**
74- * If AWS_STS_REGIONAL_ENDPOINTS is set to regional, users are opting into the new behavior of respecting the region settings
75- *
76- * If AWS_STS_REGIONAL_ENDPOINTS is set to legacy, then "old" regions need to keep using the global setting.
77- * Technically the SDK gets this wrong, it reaches out to 'sts.us-east-1.amazonaws.com' when it should be 'sts.amazonaws.com'.
78- * That is not our bug to fix here. We leave that up to the SDK.
79- */
80- const useRegionalSts =
81- AWS_STS_REGIONAL_ENDPOINTS === 'regional' ||
82- ( AWS_STS_REGIONAL_ENDPOINTS === 'legacy' && ! LEGACY_REGIONS . has ( AWS_REGION ) ) ;
8339
84- if ( 'fromNodeProviderChain' in MongoDBAWS . credentialProvider ) {
85- this . provider =
86- awsRegionSettingsExist && useRegionalSts
87- ? MongoDBAWS . credentialProvider . fromNodeProviderChain ( {
88- clientConfig : { region : AWS_REGION }
89- } )
90- : MongoDBAWS . credentialProvider . fromNodeProviderChain ( ) ;
91- }
40+ this . credentialFetcher = AWSTemporaryCredentialProvider . isAWSSDKInstalled
41+ ? new AWSSDKCredentialProvider ( )
42+ : new LegacyAWSTemporaryCredentialProvider ( ) ;
9243 }
9344
9445 override async auth ( authContext : AuthContext ) : Promise < void > {
@@ -109,7 +60,10 @@ export class MongoDBAWS extends AuthProvider {
10960 }
11061
11162 if ( ! authContext . credentials . username ) {
112- authContext . credentials = await makeTempCredentials ( authContext . credentials , this . provider ) ;
63+ authContext . credentials = await makeTempCredentials (
64+ authContext . credentials ,
65+ this . credentialFetcher
66+ ) ;
11367 }
11468
11569 const { credentials } = authContext ;
@@ -202,17 +156,9 @@ export class MongoDBAWS extends AuthProvider {
202156 }
203157}
204158
205- interface AWSTempCredentials {
206- AccessKeyId ?: string ;
207- SecretAccessKey ?: string ;
208- Token ?: string ;
209- RoleArn ?: string ;
210- Expiration ?: Date ;
211- }
212-
213159async function makeTempCredentials (
214160 credentials : MongoCredentials ,
215- provider ?: ( ) => Promise < AWSCredentials >
161+ awsCredentialFetcher : AWSTemporaryCredentialProvider
216162) : Promise < MongoCredentials > {
217163 function makeMongoCredentialsFromAWSTemp ( creds : AWSTempCredentials ) {
218164 // The AWS session token (creds.Token) may or may not be set.
@@ -230,62 +176,9 @@ async function makeTempCredentials(
230176 }
231177 } ) ;
232178 }
179+ const temporaryCredentials = await awsCredentialFetcher . getCredentials ( ) ;
233180
234- // Check if the AWS credential provider from the SDK is present. If not,
235- // use the old method.
236- if ( provider && ! ( 'kModuleError' in MongoDBAWS . credentialProvider ) ) {
237- /*
238- * Creates a credential provider that will attempt to find credentials from the
239- * following sources (listed in order of precedence):
240- *
241- * - Environment variables exposed via process.env
242- * - SSO credentials from token cache
243- * - Web identity token credentials
244- * - Shared credentials and config ini files
245- * - The EC2/ECS Instance Metadata Service
246- */
247- try {
248- const creds = await provider ( ) ;
249- return makeMongoCredentialsFromAWSTemp ( {
250- AccessKeyId : creds . accessKeyId ,
251- SecretAccessKey : creds . secretAccessKey ,
252- Token : creds . sessionToken ,
253- Expiration : creds . expiration
254- } ) ;
255- } catch ( error ) {
256- throw new MongoAWSError ( error . message ) ;
257- }
258- } else {
259- // If the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
260- // is set then drivers MUST assume that it was set by an AWS ECS agent
261- if ( process . env . AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ) {
262- return makeMongoCredentialsFromAWSTemp (
263- await request ( `${ AWS_RELATIVE_URI } ${ process . env . AWS_CONTAINER_CREDENTIALS_RELATIVE_URI } ` )
264- ) ;
265- }
266-
267- // Otherwise assume we are on an EC2 instance
268-
269- // get a token
270- const token = await request ( `${ AWS_EC2_URI } /latest/api/token` , {
271- method : 'PUT' ,
272- json : false ,
273- headers : { 'X-aws-ec2-metadata-token-ttl-seconds' : 30 }
274- } ) ;
275-
276- // get role name
277- const roleName = await request ( `${ AWS_EC2_URI } /${ AWS_EC2_PATH } ` , {
278- json : false ,
279- headers : { 'X-aws-ec2-metadata-token' : token }
280- } ) ;
281-
282- // get temp credentials
283- const creds = await request ( `${ AWS_EC2_URI } /${ AWS_EC2_PATH } /${ roleName } ` , {
284- headers : { 'X-aws-ec2-metadata-token' : token }
285- } ) ;
286-
287- return makeMongoCredentialsFromAWSTemp ( creds ) ;
288- }
181+ return makeMongoCredentialsFromAWSTemp ( temporaryCredentials ) ;
289182}
290183
291184function deriveRegion ( host : string ) {
0 commit comments