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 23 commits into
base: master
Choose a base branch
from
Open

Add suport for ECR repositorires #244

wants to merge 23 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)?$

Copy link
Author

Choose a reason for hiding this comment

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

Done
But i used regexp only

}
}

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

Copy link
Author

@scaps1 scaps1 Nov 18, 2024

Choose a reason for hiding this comment

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

Yeah, i know, it's something like temp naming was but I couldn't think of a better 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?

Copy link
Author

Choose a reason for hiding this comment

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

Done

}

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.

Copy link
Author

@scaps1 scaps1 Nov 18, 2024

Choose a reason for hiding this comment

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

I think we can init it only once in NewProvider block before caching client because it's needed only for it

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.

Copy link
Author

Choose a reason for hiding this comment

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

deprecated

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?

Copy link
Author

Choose a reason for hiding this comment

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

Done

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?

Copy link
Author

@scaps1 scaps1 Nov 15, 2024

Choose a reason for hiding this comment

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

Is this an authn.Keychain implementation?

Yes it is

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.

Copy link
Author

Choose a reason for hiding this comment

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

Done

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)

Copy link
Author

Choose a reason for hiding this comment

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

Done

Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
Signed-off-by: alexey.komyakov <[email protected]>
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