1
- import * as process from 'process' ;
2
-
3
1
import type { Binary , BSONSerializeOptions } from '../../bson' ;
4
2
import * as BSON from '../../bson' ;
5
- import { aws4 , type AWSCredentials , getAwsCredentialProvider } from '../../deps' ;
3
+ import { aws4 } from '../../deps' ;
6
4
import {
7
- MongoAWSError ,
8
5
MongoCompatibilityError ,
9
6
MongoMissingCredentialsError ,
10
7
MongoRuntimeError
11
8
} from '../../error' ;
12
- import { ByteUtils , maxWireVersion , ns , randomBytes , request } from '../../utils' ;
9
+ import { ByteUtils , maxWireVersion , ns , randomBytes } from '../../utils' ;
13
10
import { type AuthContext , AuthProvider } from './auth_provider' ;
11
+ import {
12
+ AWSSDKCredentialProvider ,
13
+ type AWSTempCredentials ,
14
+ AWSTemporaryCredentialProvider ,
15
+ LegacyAWSTemporaryCredentialProvider
16
+ } from './aws_temporary_credentials' ;
14
17
import { MongoCredentials } from './mongo_credentials' ;
15
18
import { AuthMechanism } from './providers' ;
16
19
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
- ] ) ;
39
20
const 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' ;
43
21
const bsonOptions : BSONSerializeOptions = {
44
22
useBigInt64 : false ,
45
23
promoteLongs : true ,
@@ -55,40 +33,13 @@ interface AWSSaslContinuePayload {
55
33
}
56
34
57
35
export class MongoDBAWS extends AuthProvider {
58
- static credentialProvider : ReturnType < typeof getAwsCredentialProvider > ;
59
- provider ?: ( ) => Promise < AWSCredentials > ;
60
-
36
+ private credentialFetcher : AWSTemporaryCredentialProvider ;
61
37
constructor ( ) {
62
38
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 ) ) ;
83
39
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 ( ) ;
92
43
}
93
44
94
45
override async auth ( authContext : AuthContext ) : Promise < void > {
@@ -109,7 +60,10 @@ export class MongoDBAWS extends AuthProvider {
109
60
}
110
61
111
62
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
+ ) ;
113
67
}
114
68
115
69
const { credentials } = authContext ;
@@ -202,17 +156,9 @@ export class MongoDBAWS extends AuthProvider {
202
156
}
203
157
}
204
158
205
- interface AWSTempCredentials {
206
- AccessKeyId ?: string ;
207
- SecretAccessKey ?: string ;
208
- Token ?: string ;
209
- RoleArn ?: string ;
210
- Expiration ?: Date ;
211
- }
212
-
213
159
async function makeTempCredentials (
214
160
credentials : MongoCredentials ,
215
- provider ?: ( ) => Promise < AWSCredentials >
161
+ awsCredentialFetcher : AWSTemporaryCredentialProvider
216
162
) : Promise < MongoCredentials > {
217
163
function makeMongoCredentialsFromAWSTemp ( creds : AWSTempCredentials ) {
218
164
// The AWS session token (creds.Token) may or may not be set.
@@ -230,62 +176,9 @@ async function makeTempCredentials(
230
176
}
231
177
} ) ;
232
178
}
179
+ const temporaryCredentials = await awsCredentialFetcher . getCredentials ( ) ;
233
180
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 ) ;
289
182
}
290
183
291
184
function deriveRegion ( host : string ) {
0 commit comments