Skip to content
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

Add suport for ECR repositorires #244

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open

Add suport for ECR repositorires #244

wants to merge 20 commits into from

Conversation

scaps1
Copy link

@scaps1 scaps1 commented Oct 23, 2024

Some users prefer to use in EKS clusters ECR without service accounts to authorize but with native support from ECR using IAM policies to provide credentials for their projects.
Exporter can't get any credentials from SA or from Secrets and falls with 401 Unauthorized exception.
This PR adds new libraries from AWS for work with their authorization methods.

Signed-off-by: alexey.komyakov <[email protected]>
@scaps1 scaps1 self-assigned this Oct 23, 2024
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
@scaps1 scaps1 marked this pull request as ready for review October 25, 2024 09:56
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
@scaps1 scaps1 marked this pull request as draft October 30, 2024 13:54
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
@scaps1 scaps1 requested a review from nabokihms November 8, 2024 09:44
@scaps1 scaps1 marked this pull request as ready for review November 8, 2024 09:44
keyChain, err := rc.providerRegistry.GetAuthKeychain(imageName)
if err != nil {
logrus.Warn("error while getting keychain for: ", err)
return store.UnknownError

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest returning a more specific authentication error, similar to the implementation here:

availMode = store.AuthnFailure
.
This would help clarify the nature of the failure, but I’m open to feedback if there’s a better approach.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you're right.
Changed in last commit.


func (p ProviderRegistry) GetAuthKeychain(registryStr string) (authn.Keychain, error) {
switch {
case strings.Contains(registryStr, "amazonaws.com"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets user url.Parse here and than check the URL with more accurate regex ^([0-9]{12})\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com(\.cn)?$

}
}

func (p Provider) GetAuthKeychain(registryStr string) (authn.Keychain, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (p Provider) GetAuthKeychain(registryStr string) (authn.Keychain, error) {
func (p Provider) GetAuthKeychain(registry string) (authn.Keychain, error) {

NIT: you do not need to add a variable type to a name

return nil, err
}

client := ecr.NewFromConfig(cfg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the client be cached in provider or do we need to reinitialize it on each execution?

}

func awsRegionalClient(ctx context.Context, region string) (*ecr.Client, error) {
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume config also cannot be changed and thus be cached.

return &customKeychain{authenticator: auth}, nil
}

func parseECRDetails(registryStr string) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to use regex with a capture group to highlight that we are extracting a region here.

Also please provide an example of an address of a ECR registry.

The name is also not good, lets use something like parseECRRegion.

Comment on lines +18 to +23
func NewProviderChain(pullSecretsGetter func(image string) []corev1.Secret) ProviderRegistry {
return map[string]Provider{
"amazon": amazon.NewProvider(),
"k8s": k8s.NewProvider(pullSecretsGetter),
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that the generic chain accepts kubernetes specific options Can we avoid it by initializing each provider separately?

Comment on lines +71 to +77
type customKeychain struct {
authenticator authn.Authenticator
}

func (kc *customKeychain) Resolve(_ authn.Resource) (authn.Authenticator, error) {
return kc.authenticator, nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this? The name is too broad. Is this an authn.Keychain implementation?

return nil, fmt.Errorf("error loading AWS config: %w", err)
}

authTokenOutput, err := ecrClient.GetAuthorizationToken(context.TODO(), &ecr.GetAuthorizationTokenInput{})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is GetAuthorizationToken called for each image request?

AuthorizationData has the expiresAt field, so I assume we can cache the token till this time and avoid flooding AWS with requests.

Comment on lines 258 to +264

pullSecretsGetter := func(image string) []corev1.Secret {
return rc.controllerIndexers.GetImagePullSecrets(image)
}
pc := providers.NewProviderChain(pullSecretsGetter)
rc.providerRegistry = pc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pullSecretsGetter := func(image string) []corev1.Secret {
return rc.controllerIndexers.GetImagePullSecrets(image)
}
pc := providers.NewProviderChain(pullSecretsGetter)
rc.providerRegistry = pc
rc.providerRegistry = providers.NewProviderChain(rc.controllerIndexers.GetImagePullSecrets)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants