Skip to content

Commit 94eb047

Browse files
committed
Extract aws region from the URL
Signed-off-by: Taras <9948629+taraspos@users.noreply.github.com>
1 parent 0f15fd1 commit 94eb047

4 files changed

Lines changed: 108 additions & 14 deletions

File tree

auth/aws/provider.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"errors"
2323
"fmt"
2424
"net/http"
25+
"net/url"
2526
"os"
2627
"regexp"
2728
"strings"
@@ -410,29 +411,36 @@ func (signerHeaderHostOnly) IsSigned(h string) bool {
410411
return h == "host"
411412
}
412413

413-
// NewCodeCommitGitToken returns HTTPS Git credentials for AWS CodeCommit.
414-
func (Provider) NewCodeCommitGitCredentials(_ context.Context, accessTokens []auth.Token, opts ...auth.Option) (string, string, error) {
415-
var o auth.Options
416-
o.Apply(opts...)
417-
418-
gitURL := o.GitURL
414+
// GetRegionFromCodeCommitURL extracts the AWS region from a CodeCommit HTTPS
415+
// git URL (e.g. https://git-codecommit.us-east-1.amazonaws.com/...).
416+
// Returns an error if the URL is nil, not HTTPS, or not a valid CodeCommit URL.
417+
// https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-git
418+
func GetRegionFromCodeCommitURL(gitURL *url.URL) (string, error) {
419419
if gitURL == nil {
420-
return "", "", fmt.Errorf("Git URL must be specified for AWS CodeCommit authentication")
420+
return "", fmt.Errorf("Git URL must be specified for AWS CodeCommit authentication")
421421
}
422422
if !strings.EqualFold(gitURL.Scheme, "https") {
423-
return "", "", fmt.Errorf("AWS CodeCommit authentication requires an HTTPS Git URL")
423+
return "", fmt.Errorf("AWS CodeCommit authentication requires an HTTPS Git URL")
424424
}
425-
426425
urlSplit := strings.Split(gitURL.Hostname(), ".")
427-
428-
// https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-git
429426
if len(urlSplit) < 4 ||
430427
!(strings.HasPrefix(gitURL.Hostname(), "git-codecommit.") || strings.HasPrefix(gitURL.Hostname(), "git-codecommit-fips.")) ||
431428
!(strings.HasSuffix(gitURL.Hostname(), ".amazonaws.com") || strings.HasSuffix(gitURL.Hostname(), ".amazonaws.com.cn")) {
432-
return "", "", fmt.Errorf("invalid AWS CodeCommit Git URL: %s", gitURL.Host)
429+
return "", fmt.Errorf("invalid AWS CodeCommit Git URL: %s", gitURL.Host)
433430
}
431+
return urlSplit[1], nil
432+
}
434433

435-
region := urlSplit[1]
434+
// NewCodeCommitGitToken returns HTTPS Git credentials for AWS CodeCommit.
435+
func (Provider) NewCodeCommitGitCredentials(_ context.Context, accessTokens []auth.Token, opts ...auth.Option) (string, string, error) {
436+
var o auth.Options
437+
o.Apply(opts...)
438+
439+
gitURL := o.GitURL
440+
region, err := GetRegionFromCodeCommitURL(gitURL)
441+
if err != nil {
442+
return "", "", err
443+
}
436444
if len(accessTokens) == 0 {
437445
return "", "", fmt.Errorf("AWS access token is required for region %q", region)
438446
}

auth/aws/provider_test.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func TestProvider_NewControllerToken(t *testing.T) {
8383
}
8484

8585
provider := aws.Provider{Implementation: impl}
86-
token, err := provider.NewControllerToken(context.Background(), opts...)
86+
token, err := provider.NewControllerToken(t.Context(), opts...)
8787

8888
if tt.err == "" {
8989
g.Expect(err).NotTo(HaveOccurred())
@@ -538,6 +538,63 @@ func TestProvider_GetAccessTokenOptionsForCluster(t *testing.T) {
538538
g.Expect(o.STSRegion).To(Equal("us-west-2"))
539539
}
540540

541+
func TestGetRegionFromCodeCommitURL(t *testing.T) {
542+
for _, tt := range []struct {
543+
name string
544+
gitURL string
545+
expectedRegion string
546+
err string
547+
}{
548+
{
549+
name: "valid CodeCommit URL",
550+
gitURL: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/test-repo",
551+
expectedRegion: "us-east-1",
552+
},
553+
{
554+
name: "valid CodeCommit FIPS URL",
555+
gitURL: "https://git-codecommit-fips.us-west-2.amazonaws.com/v1/repos/test-repo",
556+
expectedRegion: "us-west-2",
557+
},
558+
{
559+
name: "valid CodeCommit China URL",
560+
gitURL: "https://git-codecommit.cn-north-1.amazonaws.com.cn/v1/repos/test-repo",
561+
expectedRegion: "cn-north-1",
562+
},
563+
{
564+
name: "nil URL",
565+
err: "Git URL must be specified for AWS CodeCommit authentication",
566+
},
567+
{
568+
name: "non-HTTPS URL",
569+
gitURL: "http://git-codecommit.us-east-1.amazonaws.com/v1/repos/test-repo",
570+
err: "AWS CodeCommit authentication requires an HTTPS Git URL",
571+
},
572+
{
573+
name: "invalid CodeCommit URL",
574+
gitURL: "https://github.com/org/repo",
575+
err: "invalid AWS CodeCommit Git URL: github.com",
576+
},
577+
} {
578+
t.Run(tt.name, func(t *testing.T) {
579+
g := NewWithT(t)
580+
var parsedURL *url.URL
581+
if tt.gitURL != "" {
582+
var err error
583+
parsedURL, err = url.Parse(tt.gitURL)
584+
g.Expect(err).NotTo(HaveOccurred())
585+
}
586+
region, err := aws.GetRegionFromCodeCommitURL(parsedURL)
587+
if tt.err != "" {
588+
g.Expect(err).To(HaveOccurred())
589+
g.Expect(err.Error()).To(Equal(tt.err))
590+
} else {
591+
g.Expect(err).NotTo(HaveOccurred())
592+
g.Expect(region).To(Equal(tt.expectedRegion))
593+
}
594+
})
595+
}
596+
}
597+
541598
func TestProvider_NewCodeCommitGitCredentials(t *testing.T) {
542599
invalidToken := &generic.Token{Token: "invalid", ExpiresAt: time.Now().Add(time.Hour)}
543600
proxyUrl := url.URL{Scheme: "http", Host: "proxy.example.com"}

auth/utils/git.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ func GetGitCredentials(ctx context.Context, providerName string, opts ...auth.Op
5050
case aws.ProviderName:
5151
provider := aws.Provider{}
5252
awsOpts := slices.Clone(opts)
53+
54+
// Extract the region from the CodeCommit URL and inject it as STSRegion
55+
// before calling GetAccessToken. This will ensure that it's possible to call AWS SDK
56+
// even without AWS_REGION environment variable.
57+
var o auth.Options
58+
o.Apply(awsOpts...)
59+
if o.STSRegion == "" && o.GitURL != nil {
60+
if region, err := aws.GetRegionFromCodeCommitURL(o.GitURL); err == nil {
61+
awsOpts = append(awsOpts, auth.WithSTSRegion(region))
62+
}
63+
}
64+
5365
token, err := auth.GetAccessToken(ctx, provider, awsOpts...)
5466
if err != nil {
5567
return nil, err

auth/utils/git_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,21 @@ func TestGetGitCredentials(t *testing.T) {
6060
g.Expect(err.Error()).To(ContainSubstring("failed to create provider access token"))
6161
g.Expect(p).To(BeNil())
6262
})
63+
64+
t.Run("aws/region extracted from URL", func(t *testing.T) {
65+
// When no STSRegion is provided but a CodeCommit git URL is given, the
66+
// region should be extracted automatically so that object-level workload
67+
// identity (NewTokenForServiceAccount) receives a non-empty STSRegion.
68+
g := NewWithT(t)
69+
region := "eu-west-1"
70+
u, err := url.Parse(fmt.Sprintf("https://git-codecommit.%s.amazonaws.com/v1/repos/repo-name", region))
71+
g.Expect(err).ToNot(HaveOccurred())
72+
// No AWS_REGION env var set and no WithSTSRegion option – the region must
73+
// be derived from the URL. The call still fails (no real AWS credentials)
74+
opts := []auth.Option{auth.WithGitURL(*u)}
75+
p, err := authutils.GetGitCredentials(context.Background(), "aws", opts...)
76+
g.Expect(err).To(HaveOccurred())
77+
g.Expect(err.Error()).NotTo(ContainSubstring("an AWS region is required"))
78+
g.Expect(p).To(BeNil())
79+
})
6380
}

0 commit comments

Comments
 (0)