mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 07:57:07 +00:00
126 lines
3.4 KiB
Go
126 lines
3.4 KiB
Go
|
package notaryv2
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/kyverno/kyverno/pkg/registryclient"
|
||
|
notationregistry "github.com/notaryproject/notation-go/registry"
|
||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||
|
"github.com/pkg/errors"
|
||
|
"oras.land/oras-go/v2/registry"
|
||
|
"oras.land/oras-go/v2/registry/remote"
|
||
|
"oras.land/oras-go/v2/registry/remote/auth"
|
||
|
)
|
||
|
|
||
|
func parseReference(ctx context.Context, ref string, registryClient registryclient.Client) (notationregistry.Repository, registry.Reference, error) {
|
||
|
parsedRef, err := registry.ParseReference(ref)
|
||
|
if err != nil {
|
||
|
return nil, registry.Reference{}, errors.Wrapf(err, "failed to parse registry reference %s", ref)
|
||
|
}
|
||
|
|
||
|
authClient, plainHTTP, err := getAuthClient(ctx, parsedRef, registryClient)
|
||
|
if err != nil {
|
||
|
return nil, registry.Reference{}, err
|
||
|
}
|
||
|
|
||
|
repo, err := remote.NewRepository(ref)
|
||
|
if err != nil {
|
||
|
return nil, registry.Reference{}, errors.Wrapf(err, "failed to initialize repository")
|
||
|
}
|
||
|
|
||
|
repo.PlainHTTP = plainHTTP
|
||
|
repo.Client = authClient
|
||
|
repository := notationregistry.NewRepository(repo)
|
||
|
|
||
|
parsedRef, err = resolveDigest(repository, parsedRef)
|
||
|
if err != nil {
|
||
|
return nil, registry.Reference{}, errors.Wrapf(err, "failed to resolve digest")
|
||
|
}
|
||
|
|
||
|
return repository, parsedRef, nil
|
||
|
}
|
||
|
|
||
|
type imageResource struct {
|
||
|
ref registry.Reference
|
||
|
}
|
||
|
|
||
|
func (ir *imageResource) String() string {
|
||
|
return ir.ref.String()
|
||
|
}
|
||
|
|
||
|
func (ir *imageResource) RegistryStr() string {
|
||
|
return ir.ref.Registry
|
||
|
}
|
||
|
|
||
|
func getAuthClient(ctx context.Context, ref registry.Reference, rc registryclient.Client) (*auth.Client, bool, error) {
|
||
|
if err := rc.RefreshKeychainPullSecrets(ctx); err != nil {
|
||
|
return nil, false, errors.Wrapf(err, "failed to refresh image pull secrets")
|
||
|
}
|
||
|
|
||
|
authn, err := rc.Keychain().Resolve(&imageResource{ref})
|
||
|
if err != nil {
|
||
|
return nil, false, errors.Wrapf(err, "failed to resolve auth for %s", ref.String())
|
||
|
}
|
||
|
|
||
|
authConfig, err := authn.Authorization()
|
||
|
if err != nil {
|
||
|
return nil, false, errors.Wrapf(err, "failed to get auth config for %s", ref.String())
|
||
|
}
|
||
|
|
||
|
credentials := auth.Credential{
|
||
|
Username: authConfig.Username,
|
||
|
Password: authConfig.Password,
|
||
|
AccessToken: authConfig.IdentityToken,
|
||
|
RefreshToken: authConfig.RegistryToken,
|
||
|
}
|
||
|
|
||
|
authClient := &auth.Client{
|
||
|
Credential: func(ctx context.Context, registry string) (auth.Credential, error) {
|
||
|
switch registry {
|
||
|
default:
|
||
|
return credentials, nil
|
||
|
}
|
||
|
},
|
||
|
Cache: auth.NewCache(),
|
||
|
ClientID: "notation",
|
||
|
}
|
||
|
|
||
|
authClient.SetUserAgent("kyverno.io")
|
||
|
return authClient, false, nil
|
||
|
}
|
||
|
|
||
|
func resolveDigest(repo notationregistry.Repository, ref registry.Reference) (registry.Reference, error) {
|
||
|
if isDigestReference(ref.String()) {
|
||
|
return ref, nil
|
||
|
}
|
||
|
|
||
|
// Resolve tag reference to digest reference.
|
||
|
manifestDesc, err := getManifestDescriptorFromReference(repo, ref.String())
|
||
|
if err != nil {
|
||
|
return registry.Reference{}, err
|
||
|
}
|
||
|
|
||
|
ref.Reference = manifestDesc.Digest.String()
|
||
|
return ref, nil
|
||
|
}
|
||
|
|
||
|
func isDigestReference(reference string) bool {
|
||
|
parts := strings.SplitN(reference, "/", 2)
|
||
|
if len(parts) == 1 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
index := strings.Index(parts[1], "@")
|
||
|
return index != -1
|
||
|
}
|
||
|
|
||
|
func getManifestDescriptorFromReference(repo notationregistry.Repository, reference string) (ocispec.Descriptor, error) {
|
||
|
ref, err := registry.ParseReference(reference)
|
||
|
if err != nil {
|
||
|
return ocispec.Descriptor{}, err
|
||
|
}
|
||
|
|
||
|
return repo.Resolve(context.Background(), ref.ReferenceOrDefault())
|
||
|
}
|