Skip to content

MIGRATION ISSUE: GetBucketRegion in v2 requires valid credentials #3077

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
2 tasks done
Juneezee opened this issue Apr 29, 2025 · 2 comments · Fixed by #3081
Closed
2 tasks done

MIGRATION ISSUE: GetBucketRegion in v2 requires valid credentials #3077

Juneezee opened this issue Apr 29, 2025 · 2 comments · Fixed by #3081
Labels
needs-triage This issue or PR still needs to be triaged. v1-v2-inconsistency v1-v2-inconsistency Behavior has changed from v1 to v2, or feature is missing altogether

Comments

@Juneezee
Copy link
Contributor

Pre-Migration Checklist

Go Version Used

Go 1.24

Describe the Migration Issue

Originally posted in trufflesecurity/trufflehog#4069 (comment).


I discovered an undocumented behavioral difference between V1’s GetBucketRegionWithClient and V2's GetBucketRegion.

Specifically, V1’s GetBucketRegionWithClient does not return an error when credentials are invalid, whereas V2’s GetBucketRegion fails under the same conditions.

In the following code examples, I used a fake access key, fake secret key, and a fake role ARN.

Code Comparison

GetBucketRegionWithClient in V1

package main

import (
	"context"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"github.com/aws/aws-sdk-go/service/sts"
)

func main() {
	ctx := context.Background()

	cfg := &aws.Config{
		Region:      aws.String("us-east-1"),
		Credentials: credentials.NewStaticCredentials("fakeDummy", "fakeDummy", ""),
	}
	sess, err := session.NewSession(cfg)
	if err != nil {
		log.Fatal(err)
	}

	stsClient := sts.New(sess)
	cfg.Credentials = stscreds.NewCredentialsWithClient(stsClient, "000000000:role/service-role/fake-non-existent-role")

	s3Client := s3.New(sess)

	region, err := s3manager.GetBucketRegionWithClient(ctx, s3Client, "truffletestbucket-s3-role-assumption")
	log.Println("Region: ", region)
	log.Println("Err: ", err)
}

GetBucketRegion in V2

package main

import (
	"context"
	"log"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/credentials"
	"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
	s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
	"github.com/aws/aws-sdk-go-v2/service/s3"
	"github.com/aws/aws-sdk-go-v2/service/sts"
)

func main() {
	ctx := context.Background()

	cfg, err := config.LoadDefaultConfig(ctx,
		config.WithRegion("us-east-1"),
		config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("fakeDummy", "fakeDummy", "")),
	)
	if err != nil {
		log.Fatal(err)
	}

	stsClient := sts.NewFromConfig(cfg)
	provider := stscreds.NewAssumeRoleProvider(stsClient, "arn:aws:iam::000000000:role/service-role/fake-non-existent-role")
	cfg.Credentials = aws.NewCredentialsCache(provider)

	s3Client := s3.NewFromConfig(cfg)

	region, err := s3manager.GetBucketRegion(ctx, s3Client, "truffletestbucket-s3-role-assumption")
	log.Println("Region: ", region)
	log.Println("Err: ", err)
}

Observed Differences/Errors

V1 Code Snippet Output

Running the V1 code snippet above produces the following output:

2025/04/19 19:04:01 Region:  us-east-2
2025/04/19 19:04:01 Err:  <nil>

Upon inspecting the source code of V1's GetBucketRegionWithClient, we can see that it bypasses the configured credentials and issues the HeadBucket request using credentials.AnonymousCredentials:

func GetBucketRegionWithClient(ctx aws.Context, svc s3iface.S3API, bucket string, opts ...request.Option) (string, error) {
	req, _ := svc.HeadBucketRequest(&s3.HeadBucketInput{
		Bucket: aws.String(bucket),
	})
	req.Config.S3ForcePathStyle = aws.Bool(true)

	req.Config.Credentials = credentials.AnonymousCredentials

V2 Code Snippet Output

Running the V2 code snippet above code results in the following output:

2025/04/19 19:03:17 Region:
2025/04/19 19:03:17 Err:  operation error S3: HeadBucket, get identity: get credentials: failed to refresh cached credentials, operation error STS: AssumeRole, https response error StatusCode: 403, RequestID: 331c40dd-d8c4-42ca-9105-fcff18f9a8fb, api error InvalidClientTokenId: The security token included in the request is invalid.

The error originates from the following call chain:

  1. https://github.com/aws/aws-sdk-go-v2/blob/service/s3/v1.79.2/service/s3/auth.go#L274-L283
  2. https://github.com/aws/aws-sdk-go-v2/blob/v1.36.3/internal/auth/smithy/credentials_adapter.go#L40-L43

Additional Context

It turns out that valid credentials are not required to retrieve a bucket's region using the HeadBucket API.

A simple HEAD request returns the x-amz-bucket-region header, even when the response status is 403 Forbidden:

curl --head truffletestbucket-s3-role-assumption.s3.amazonaws.com

HTTP/1.1 403 Forbidden
x-amz-bucket-region: us-east-2
x-amz-request-id: 7E2S67HYJWFER9XD
x-amz-id-2: ZRbFyUcIJDb7y15lJvnG9M2vGqF55h7NQLaYJvQFh2CQTsMsCZDpwHa1VIQGHIHd52sOwaJwJ3vYDkxULXKp+tlDH1l5lD2Tr5dbpV+CS/E=
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sat, 19 Apr 2025 11:47:05 GMT
Server: AmazonS3

This matches the test case for TestGetBucketRegion_Exists, where we expect the bucket region is included in the header when the response is 403 Forbidden.

{
RespRegion: "bucket-region",
StatusCode: 403,
},

@Juneezee Juneezee added needs-triage This issue or PR still needs to be triaged. v1-v2-inconsistency v1-v2-inconsistency Behavior has changed from v1 to v2, or feature is missing altogether labels Apr 29, 2025
@wty-Bryant
Copy link
Contributor

Hi, we have confirmed that there's an anonymous credential config miss from v1 to v2 though it has been covered in v2's comment.
We are working on a patch pr now

Copy link

github-actions bot commented May 5, 2025

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-triage This issue or PR still needs to be triaged. v1-v2-inconsistency v1-v2-inconsistency Behavior has changed from v1 to v2, or feature is missing altogether
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants