63
63
"Accept-Encoding" : []string {"identity" },
64
64
"Accept" : []string {"application/vnd.coreos.ignition+json;version=3.3.0, */*;q=0.1" },
65
65
}
66
+
67
+ // We could derive this info from aws-sdk-go/aws/endpoints/defaults.go,
68
+ // but hardcoding it allows us to unit-test that specific regions
69
+ // are used for hinting
70
+ awsPartitionRegionHints = map [string ]string {
71
+ "aws" : "us-east-1" ,
72
+ "aws-cn" : "cn-north-1" ,
73
+ "aws-us-gov" : "us-gov-west-1" ,
74
+ }
66
75
)
67
76
68
77
// Fetcher holds settings for fetching resources from URLs
@@ -409,7 +418,7 @@ func (f *Fetcher) fetchFromS3(u url.URL, dest s3target, opts FetchOptions) error
409
418
sess := f .AWSSession .Copy ()
410
419
411
420
// Determine the bucket and key based on the URL scheme
412
- var bucket , key , region string
421
+ var bucket , key , region , regionHint string
413
422
var err error
414
423
switch u .Scheme {
415
424
case "s3" :
@@ -420,7 +429,7 @@ func (f *Fetcher) fetchFromS3(u url.URL, dest s3target, opts FetchOptions) error
420
429
// Parse the bucket and key from the ARN Resource.
421
430
// Also set the region for accesspoints.
422
431
// S3 bucket ARNs don't include the region field.
423
- bucket , key , region , err = f .parseARN (fullURL )
432
+ bucket , key , region , regionHint , err = f .parseARN (fullURL )
424
433
if err != nil {
425
434
return err
426
435
}
@@ -430,14 +439,25 @@ func (f *Fetcher) fetchFromS3(u url.URL, dest s3target, opts FetchOptions) error
430
439
431
440
// Determine the partition and region this bucket is in
432
441
if region == "" {
433
- regionHint := "us-east-1"
434
- if f .S3RegionHint != "" {
442
+ // We didn't get an accesspoint ARN, so we don't know the
443
+ // region directly. Maybe we computed a region hint from
444
+ // the ARN partition field?
445
+ if regionHint == "" {
446
+ // Nope; we got an unknown ARN partition value or an
447
+ // s3:// URL. Maybe we're running in AWS and can
448
+ // assume the same partition we're running in?
435
449
regionHint = f .S3RegionHint
436
450
}
451
+ if regionHint == "" {
452
+ // Nope; assume aws partition.
453
+ regionHint = "us-east-1"
454
+ }
455
+ // Use the region hint to ask the correct partition for the
456
+ // bucket's region.
437
457
region , err = s3manager .GetBucketRegion (ctx , sess , bucket , regionHint )
438
458
if err != nil {
439
459
if aerr , ok := err .(awserr.Error ); ok && aerr .Code () == "NotFound" {
440
- return fmt .Errorf ("couldn't determine the region for bucket %q: %v" , u . Host , err )
460
+ return fmt .Errorf ("couldn't determine the region for bucket %q: %v" , bucket , err )
441
461
}
442
462
return err
443
463
}
@@ -547,21 +567,24 @@ func (f *Fetcher) decompressCopyHashAndVerify(dest io.Writer, src io.Reader, opt
547
567
}
548
568
549
569
// parseARN is a custom wrapper around arn.Parse(); it takes arnURL, a full ARN URL,
550
- // and returns a bucket, a key, a potentially empty region, or an error if the ARN
551
- // is invalid or not for an S3 object.
570
+ // and returns a bucket, a key, a potentially empty region, and a
571
+ // potentially empty region hint for use in region detection; or an error if
572
+ // the ARN is invalid or not for an S3 object.
552
573
// If the given arnURL is an accesspoint ARN, the region is set.
553
574
// The region is empty for S3 bucket ARNs because they don't include the region field.
554
- func (f * Fetcher ) parseARN (arnURL string ) (string , string , string , error ) {
575
+ func (f * Fetcher ) parseARN (arnURL string ) (string , string , string , string , error ) {
555
576
if ! arn .IsARN (arnURL ) {
556
- return "" , "" , "" , configErrors .ErrInvalidS3ARN
577
+ return "" , "" , "" , "" , configErrors .ErrInvalidS3ARN
557
578
}
558
579
s3arn , err := arn .Parse (arnURL )
559
580
if err != nil {
560
- return "" , "" , "" , err
581
+ return "" , "" , "" , "" , err
561
582
}
562
583
if s3arn .Service != "s3" {
563
- return "" , "" , "" , configErrors .ErrInvalidS3ARN
584
+ return "" , "" , "" , "" , configErrors .ErrInvalidS3ARN
564
585
}
586
+ // empty if unrecognized partition
587
+ regionHint := awsPartitionRegionHints [s3arn .Partition ]
565
588
// Split the ARN bucket (or accesspoint) and key by separating on slashes.
566
589
// See https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-paths for more info.
567
590
urlSplit := strings .Split (arnURL , "/" )
@@ -570,7 +593,7 @@ func (f *Fetcher) parseARN(arnURL string) (string, string, string, error) {
570
593
if strings .HasPrefix (s3arn .Resource , "accesspoint/" ) {
571
594
// urlSplit must consist of arn, name of accesspoint, and key
572
595
if len (urlSplit ) < 3 {
573
- return "" , "" , "" , configErrors .ErrInvalidS3ARN
596
+ return "" , "" , "" , "" , configErrors .ErrInvalidS3ARN
574
597
}
575
598
576
599
// When using GetObjectInput with an access point,
@@ -579,11 +602,11 @@ func (f *Fetcher) parseARN(arnURL string) (string, string, string, error) {
579
602
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html
580
603
bucket := strings .Join (urlSplit [:2 ], "/" )
581
604
key := strings .Join (urlSplit [2 :], "/" )
582
- return bucket , key , s3arn .Region , nil
605
+ return bucket , key , s3arn .Region , regionHint , nil
583
606
}
584
607
// urlSplit must consist of name of bucket and key
585
608
if len (urlSplit ) < 2 {
586
- return "" , "" , "" , configErrors .ErrInvalidS3ARN
609
+ return "" , "" , "" , "" , configErrors .ErrInvalidS3ARN
587
610
}
588
611
589
612
// Parse out the bucket name in order to find the region with s3manager.GetBucketRegion.
@@ -592,5 +615,5 @@ func (f *Fetcher) parseARN(arnURL string) (string, string, string, error) {
592
615
bucketUrlSplit := strings .Split (urlSplit [0 ], ":" )
593
616
bucket := bucketUrlSplit [len (bucketUrlSplit )- 1 ]
594
617
key := strings .Join (urlSplit [1 :], "/" )
595
- return bucket , key , "" , nil
618
+ return bucket , key , "" , regionHint , nil
596
619
}
0 commit comments