@@ -26,22 +26,28 @@ import (
26
26
"golang.org/x/oauth2"
27
27
)
28
28
29
- type awsSecurityCredentials struct {
30
- AccessKeyID string `json:"AccessKeyID"`
29
+ // AwsSecurityCredentials models AWS security credentials.
30
+ type AwsSecurityCredentials struct {
31
+ // AccessKeyId is the AWS Access Key ID - Required.
32
+ AccessKeyID string `json:"AccessKeyID"`
33
+ // SecretAccessKey is the AWS Secret Access Key - Required.
31
34
SecretAccessKey string `json:"SecretAccessKey"`
32
- SecurityToken string `json:"Token"`
35
+ // SessionToken is the AWS Session token. This should be provided for temporary AWS security credentials - Optional.
36
+ SessionToken string `json:"Token"`
33
37
}
34
38
35
39
// awsRequestSigner is a utility class to sign http requests using a AWS V4 signature.
36
40
type awsRequestSigner struct {
37
41
RegionName string
38
- AwsSecurityCredentials awsSecurityCredentials
42
+ AwsSecurityCredentials * AwsSecurityCredentials
39
43
}
40
44
41
45
// getenv aliases os.Getenv for testing
42
46
var getenv = os .Getenv
43
47
44
48
const (
49
+ defaultRegionalCredentialVerificationUrl = "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
50
+
45
51
// AWS Signature Version 4 signing algorithm identifier.
46
52
awsAlgorithm = "AWS4-HMAC-SHA256"
47
53
@@ -197,8 +203,8 @@ func (rs *awsRequestSigner) SignRequest(req *http.Request) error {
197
203
198
204
signedRequest .Header .Add ("host" , requestHost (req ))
199
205
200
- if rs .AwsSecurityCredentials .SecurityToken != "" {
201
- signedRequest .Header .Add (awsSecurityTokenHeader , rs .AwsSecurityCredentials .SecurityToken )
206
+ if rs .AwsSecurityCredentials .SessionToken != "" {
207
+ signedRequest .Header .Add (awsSecurityTokenHeader , rs .AwsSecurityCredentials .SessionToken )
202
208
}
203
209
204
210
if signedRequest .Header .Get ("date" ) == "" {
@@ -251,16 +257,18 @@ func (rs *awsRequestSigner) generateAuthentication(req *http.Request, timestamp
251
257
}
252
258
253
259
type awsCredentialSource struct {
254
- EnvironmentID string
255
- RegionURL string
256
- RegionalCredVerificationURL string
257
- CredVerificationURL string
258
- IMDSv2SessionTokenURL string
259
- TargetResource string
260
- requestSigner * awsRequestSigner
261
- region string
262
- ctx context.Context
263
- client * http.Client
260
+ environmentID string
261
+ regionURL string
262
+ regionalCredVerificationURL string
263
+ credVerificationURL string
264
+ imdsv2SessionTokenURL string
265
+ targetResource string
266
+ requestSigner * awsRequestSigner
267
+ region string
268
+ ctx context.Context
269
+ client * http.Client
270
+ awsSecurityCredentialsSupplier AwsSecurityCredentialsSupplier
271
+ supplierOptions SupplierOptions
264
272
}
265
273
266
274
type awsRequestHeader struct {
@@ -292,18 +300,25 @@ func canRetrieveSecurityCredentialFromEnvironment() bool {
292
300
return getenv (awsAccessKeyId ) != "" && getenv (awsSecretAccessKey ) != ""
293
301
}
294
302
295
- func shouldUseMetadataServer () bool {
296
- return ! canRetrieveRegionFromEnvironment () || ! canRetrieveSecurityCredentialFromEnvironment ()
303
+ func ( cs awsCredentialSource ) shouldUseMetadataServer () bool {
304
+ return cs . awsSecurityCredentialsSupplier == nil && ( ! canRetrieveRegionFromEnvironment () || ! canRetrieveSecurityCredentialFromEnvironment () )
297
305
}
298
306
299
307
func (cs awsCredentialSource ) credentialSourceType () string {
308
+ if cs .awsSecurityCredentialsSupplier != nil {
309
+ return "programmatic"
310
+ }
300
311
return "aws"
301
312
}
302
313
303
314
func (cs awsCredentialSource ) subjectToken () (string , error ) {
315
+ // Set Defaults
316
+ if cs .regionalCredVerificationURL == "" {
317
+ cs .regionalCredVerificationURL = defaultRegionalCredentialVerificationUrl
318
+ }
304
319
if cs .requestSigner == nil {
305
320
headers := make (map [string ]string )
306
- if shouldUseMetadataServer () {
321
+ if cs . shouldUseMetadataServer () {
307
322
awsSessionToken , err := cs .getAWSSessionToken ()
308
323
if err != nil {
309
324
return "" , err
@@ -318,8 +333,8 @@ func (cs awsCredentialSource) subjectToken() (string, error) {
318
333
if err != nil {
319
334
return "" , err
320
335
}
321
-
322
- if cs . region , err = cs . getRegion ( headers ); err != nil {
336
+ cs . region , err = cs . getRegion ( headers )
337
+ if err != nil {
323
338
return "" , err
324
339
}
325
340
@@ -331,16 +346,16 @@ func (cs awsCredentialSource) subjectToken() (string, error) {
331
346
332
347
// Generate the signed request to AWS STS GetCallerIdentity API.
333
348
// Use the required regional endpoint. Otherwise, the request will fail.
334
- req , err := http .NewRequest ("POST" , strings .Replace (cs .RegionalCredVerificationURL , "{region}" , cs .region , 1 ), nil )
349
+ req , err := http .NewRequest ("POST" , strings .Replace (cs .regionalCredVerificationURL , "{region}" , cs .region , 1 ), nil )
335
350
if err != nil {
336
351
return "" , err
337
352
}
338
353
// The full, canonical resource name of the workload identity pool
339
354
// provider, with or without the HTTPS prefix.
340
355
// Including this header as part of the signature is recommended to
341
356
// ensure data integrity.
342
- if cs .TargetResource != "" {
343
- req .Header .Add ("x-goog-cloud-target-resource" , cs .TargetResource )
357
+ if cs .targetResource != "" {
358
+ req .Header .Add ("x-goog-cloud-target-resource" , cs .targetResource )
344
359
}
345
360
cs .requestSigner .SignRequest (req )
346
361
@@ -387,11 +402,11 @@ func (cs awsCredentialSource) subjectToken() (string, error) {
387
402
}
388
403
389
404
func (cs * awsCredentialSource ) getAWSSessionToken () (string , error ) {
390
- if cs .IMDSv2SessionTokenURL == "" {
405
+ if cs .imdsv2SessionTokenURL == "" {
391
406
return "" , nil
392
407
}
393
408
394
- req , err := http .NewRequest ("PUT" , cs .IMDSv2SessionTokenURL , nil )
409
+ req , err := http .NewRequest ("PUT" , cs .imdsv2SessionTokenURL , nil )
395
410
if err != nil {
396
411
return "" , err
397
412
}
@@ -410,25 +425,29 @@ func (cs *awsCredentialSource) getAWSSessionToken() (string, error) {
410
425
}
411
426
412
427
if resp .StatusCode != 200 {
413
- return "" , fmt .Errorf ("oauth2/google: unable to retrieve AWS session token - %s" , string (respBody ))
428
+ return "" , fmt .Errorf ("oauth2/google/externalaccount : unable to retrieve AWS session token - %s" , string (respBody ))
414
429
}
415
430
416
431
return string (respBody ), nil
417
432
}
418
433
419
434
func (cs * awsCredentialSource ) getRegion (headers map [string ]string ) (string , error ) {
435
+ if cs .awsSecurityCredentialsSupplier != nil {
436
+ return cs .awsSecurityCredentialsSupplier .AwsRegion (cs .ctx , cs .supplierOptions )
437
+ }
420
438
if canRetrieveRegionFromEnvironment () {
421
439
if envAwsRegion := getenv (awsRegion ); envAwsRegion != "" {
440
+ cs .region = envAwsRegion
422
441
return envAwsRegion , nil
423
442
}
424
443
return getenv ("AWS_DEFAULT_REGION" ), nil
425
444
}
426
445
427
- if cs .RegionURL == "" {
428
- return "" , errors .New ("oauth2/google: unable to determine AWS region" )
446
+ if cs .regionURL == "" {
447
+ return "" , errors .New ("oauth2/google/externalaccount : unable to determine AWS region" )
429
448
}
430
449
431
- req , err := http .NewRequest ("GET" , cs .RegionURL , nil )
450
+ req , err := http .NewRequest ("GET" , cs .regionURL , nil )
432
451
if err != nil {
433
452
return "" , err
434
453
}
@@ -449,7 +468,7 @@ func (cs *awsCredentialSource) getRegion(headers map[string]string) (string, err
449
468
}
450
469
451
470
if resp .StatusCode != 200 {
452
- return "" , fmt .Errorf ("oauth2/google: unable to retrieve AWS region - %s" , string (respBody ))
471
+ return "" , fmt .Errorf ("oauth2/google/externalaccount : unable to retrieve AWS region - %s" , string (respBody ))
453
472
}
454
473
455
474
// This endpoint will return the region in format: us-east-2b.
@@ -461,12 +480,15 @@ func (cs *awsCredentialSource) getRegion(headers map[string]string) (string, err
461
480
return string (respBody [:respBodyEnd ]), nil
462
481
}
463
482
464
- func (cs * awsCredentialSource ) getSecurityCredentials (headers map [string ]string ) (result awsSecurityCredentials , err error ) {
483
+ func (cs * awsCredentialSource ) getSecurityCredentials (headers map [string ]string ) (result * AwsSecurityCredentials , err error ) {
484
+ if cs .awsSecurityCredentialsSupplier != nil {
485
+ return cs .awsSecurityCredentialsSupplier .AwsSecurityCredentials (cs .ctx , cs .supplierOptions )
486
+ }
465
487
if canRetrieveSecurityCredentialFromEnvironment () {
466
- return awsSecurityCredentials {
488
+ return & AwsSecurityCredentials {
467
489
AccessKeyID : getenv (awsAccessKeyId ),
468
490
SecretAccessKey : getenv (awsSecretAccessKey ),
469
- SecurityToken : getenv (awsSessionToken ),
491
+ SessionToken : getenv (awsSessionToken ),
470
492
}, nil
471
493
}
472
494
@@ -481,20 +503,20 @@ func (cs *awsCredentialSource) getSecurityCredentials(headers map[string]string)
481
503
}
482
504
483
505
if credentials .AccessKeyID == "" {
484
- return result , errors .New ("oauth2/google: missing AccessKeyId credential" )
506
+ return result , errors .New ("oauth2/google/externalaccount : missing AccessKeyId credential" )
485
507
}
486
508
487
509
if credentials .SecretAccessKey == "" {
488
- return result , errors .New ("oauth2/google: missing SecretAccessKey credential" )
510
+ return result , errors .New ("oauth2/google/externalaccount : missing SecretAccessKey credential" )
489
511
}
490
512
491
- return credentials , nil
513
+ return & credentials , nil
492
514
}
493
515
494
- func (cs * awsCredentialSource ) getMetadataSecurityCredentials (roleName string , headers map [string ]string ) (awsSecurityCredentials , error ) {
495
- var result awsSecurityCredentials
516
+ func (cs * awsCredentialSource ) getMetadataSecurityCredentials (roleName string , headers map [string ]string ) (AwsSecurityCredentials , error ) {
517
+ var result AwsSecurityCredentials
496
518
497
- req , err := http .NewRequest ("GET" , fmt .Sprintf ("%s/%s" , cs .CredVerificationURL , roleName ), nil )
519
+ req , err := http .NewRequest ("GET" , fmt .Sprintf ("%s/%s" , cs .credVerificationURL , roleName ), nil )
498
520
if err != nil {
499
521
return result , err
500
522
}
@@ -516,19 +538,19 @@ func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string, h
516
538
}
517
539
518
540
if resp .StatusCode != 200 {
519
- return result , fmt .Errorf ("oauth2/google: unable to retrieve AWS security credentials - %s" , string (respBody ))
541
+ return result , fmt .Errorf ("oauth2/google/externalaccount : unable to retrieve AWS security credentials - %s" , string (respBody ))
520
542
}
521
543
522
544
err = json .Unmarshal (respBody , & result )
523
545
return result , err
524
546
}
525
547
526
548
func (cs * awsCredentialSource ) getMetadataRoleName (headers map [string ]string ) (string , error ) {
527
- if cs .CredVerificationURL == "" {
528
- return "" , errors .New ("oauth2/google: unable to determine the AWS metadata server security credentials endpoint" )
549
+ if cs .credVerificationURL == "" {
550
+ return "" , errors .New ("oauth2/google/externalaccount : unable to determine the AWS metadata server security credentials endpoint" )
529
551
}
530
552
531
- req , err := http .NewRequest ("GET" , cs .CredVerificationURL , nil )
553
+ req , err := http .NewRequest ("GET" , cs .credVerificationURL , nil )
532
554
if err != nil {
533
555
return "" , err
534
556
}
@@ -549,7 +571,7 @@ func (cs *awsCredentialSource) getMetadataRoleName(headers map[string]string) (s
549
571
}
550
572
551
573
if resp .StatusCode != 200 {
552
- return "" , fmt .Errorf ("oauth2/google: unable to retrieve AWS role name - %s" , string (respBody ))
574
+ return "" , fmt .Errorf ("oauth2/google/externalaccount : unable to retrieve AWS role name - %s" , string (respBody ))
553
575
}
554
576
555
577
return string (respBody ), nil
0 commit comments