-
Notifications
You must be signed in to change notification settings - Fork 288
/
Copy pathregional_registry.go
169 lines (144 loc) Β· 5.58 KB
/
regional_registry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package curatedpackages
import (
"context"
"fmt"
"io"
"net/http"
"os"
"strings"
"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/service/ecr"
)
// RegistryAccessTester test if AWS credentials has valid permission to access an ECR registry.
type RegistryAccessTester interface {
Test(ctx context.Context, accessKey, secret, region, awsConfig, registry string) error
}
// DefaultRegistryAccessTester the default implementation of RegistryAccessTester.
type DefaultRegistryAccessTester struct{}
// Test if the AWS static credential or sharedConfig has valid permission to access an ECR registry.
func (r *DefaultRegistryAccessTester) Test(ctx context.Context, accessKey, secret, region, awsConfig, registry string) (err error) {
authTokenProvider := &DefaultRegistryAuthTokenProvider{}
var authToken string
if len(awsConfig) > 0 {
authToken, err = authTokenProvider.GetTokenByAWSConfig(ctx, awsConfig)
} else {
authToken, err = authTokenProvider.GetTokenByAWSKeySecret(ctx, accessKey, secret, region)
}
if err != nil {
return err
}
return TestRegistryWithAuthToken(authToken, registry, http.DefaultClient.Do)
}
// TestRegistryWithAuthToken test if the registry can be acccessed with auth token.
func TestRegistryWithAuthToken(authToken, registry string, do Do) error {
manifestPath := "/v2/eks-anywhere-packages/manifests/latest"
req, err := http.NewRequest("GET", "https://"+registry+manifestPath, nil)
if err != nil {
return err
}
req.Header.Add("Authorization", "Basic "+authToken)
resp2, err := do(req)
if err != nil {
return err
}
bodyBytes, err := io.ReadAll(resp2.Body)
// 404 means the IAM policy is good, so 404 is good here
if resp2.StatusCode != 200 && resp2.StatusCode != 404 {
return fmt.Errorf("%s\n, %v", string(bodyBytes), err)
}
return nil
}
// GetRegionalRegistry get the regional registry corresponding to defaultRegistry in a specific region.
func GetRegionalRegistry(defaultRegistry, region string) string {
if strings.Contains(defaultRegistry, devRegionalPublicRegistryAlias) {
return devRegionalPrivateRegistryURI
}
if strings.Contains(defaultRegistry, stagingPublicRegistryAlias) {
return stagingRegionalPrivateRegistryURI
}
return prodRegionalPrivateRegistryURIByRegion[region]
}
// RegistryAuthTokenProvider provides auth token for registry access.
type RegistryAuthTokenProvider interface {
GetTokenByAWSConfig(ctx context.Context, awsConfig string) (string, error)
GetTokenByAWSKeySecret(ctx context.Context, key, secret, region string) (string, error)
}
// DefaultRegistryAuthTokenProvider provides auth token for AWS ECR registry access.
type DefaultRegistryAuthTokenProvider struct{}
// GetTokenByAWSConfig get auth token by AWS config.
func (d *DefaultRegistryAuthTokenProvider) GetTokenByAWSConfig(ctx context.Context, awsConfig string) (string, error) {
cfg, err := ParseAWSConfig(ctx, awsConfig)
if err != nil {
return "", err
}
return getAuthorizationToken(*cfg)
}
// ParseAWSConfig parse AWS config from string.
func ParseAWSConfig(ctx context.Context, awsConfig string) (*aws.Config, error) {
file, err := os.CreateTemp("", "eksa-temp-aws-config-*")
if err != nil {
return nil, err
}
if _, err := file.Write([]byte(awsConfig)); err != nil {
return nil, err
}
defer os.Remove(file.Name())
if err != nil {
return nil, err
}
cfg, err := config.LoadDefaultConfig(ctx,
config.WithSharedConfigFiles([]string{file.Name()}),
)
if err != nil {
return nil, err
}
return &cfg, nil
}
// GetAWSConfigFromKeySecret get AWS config from key, secret and region.
func GetAWSConfigFromKeySecret(ctx context.Context, key, secret, region string) (*aws.Config, error) {
cfg, err := config.LoadDefaultConfig(ctx,
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(key, secret, "")),
config.WithRegion(region),
)
if err != nil {
return nil, err
}
return &cfg, nil
}
// GetTokenByAWSKeySecret get auth token by AWS key and secret.
func (d *DefaultRegistryAuthTokenProvider) GetTokenByAWSKeySecret(ctx context.Context, key, secret, region string) (string, error) {
cfg, err := GetAWSConfigFromKeySecret(ctx, key, secret, region)
if err != nil {
return "", err
}
return getAuthorizationToken(*cfg)
}
func getAuthorizationToken(cfg aws.Config) (string, error) {
ecrClient := ecr.NewFromConfig(cfg)
out, err := ecrClient.GetAuthorizationToken(context.Background(), &ecr.GetAuthorizationTokenInput{})
if err != nil {
return "", fmt.Errorf("ecrClient cannot get authorization token: %w", err)
}
authToken := out.AuthorizationData[0].AuthorizationToken
return *authToken, nil
}
// Do is a function type that takes a http request and returns a http response.
type Do func(req *http.Request) (*http.Response, error)
// TestRegistryAccessWithAWSConfig test if the AWS config has valid permission to access container registry.
func TestRegistryAccessWithAWSConfig(ctx context.Context, awsConfig, registry string, tokenProvider RegistryAuthTokenProvider, do Do) error {
token, err := tokenProvider.GetTokenByAWSConfig(ctx, awsConfig)
if err != nil {
return err
}
return TestRegistryWithAuthToken(token, registry, do)
}
// TestRegistryAccessWithAWSKeySecret test if the AWS key and secret has valid permission to access container registry.
func TestRegistryAccessWithAWSKeySecret(ctx context.Context, key, secret, region, registry string, tokenProvider RegistryAuthTokenProvider, do Do) error {
token, err := tokenProvider.GetTokenByAWSKeySecret(ctx, key, secret, region)
if err != nil {
return err
}
return TestRegistryWithAuthToken(token, registry, do)
}