1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-05 15:37:19 +00:00
kyverno/pkg/registryclient/client.go
Jim Bugwadia 29997fe446
Notary v2 (#6011)
* fix make debug-deploy

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* improve log messages

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* initial update

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* initial update

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* update registry credentials handling order

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* comment out ACR helper - breaks anonymous image pull

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* merge main and refactor verifiers

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix opt init

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* remove local address

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* update to NotaryV2 RC

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix fmt

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* update deps

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* format imports

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* remove env and no-op statement

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix merge issues

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix linter issue

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* remove unused field

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* make fmt

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* renable ACR credential helper

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* Update .vscode/launch.json

Signed-off-by: shuting <shutting06@gmail.com>

---------

Signed-off-by: Jim Bugwadia <jim@nirmata.com>
Signed-off-by: shuting <shutting06@gmail.com>
Co-authored-by: shuting <shuting@nirmata.com>
Co-authored-by: shuting <shutting06@gmail.com>
2023-02-20 16:26:10 +00:00

199 lines
6 KiB
Go

package registryclient
import (
"context"
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
"time"
"github.com/awslabs/amazon-ecr-credential-helper/ecr-login"
"github.com/chrismellard/docker-credential-acr-env/pkg/credhelper"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/authn/github"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/google"
gcrremote "github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/kyverno/kyverno/pkg/tracing"
"github.com/sigstore/cosign/pkg/oci/remote"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
corev1listers "k8s.io/client-go/listers/core/v1"
)
var (
baseKeychain = authn.NewMultiKeychain(
authn.DefaultKeychain,
google.Keychain,
authn.NewKeychainFromHelper(ecr.NewECRHelper(ecr.WithLogger(io.Discard))),
authn.NewKeychainFromHelper(credhelper.NewACRCredentialsHelper()),
github.Keychain,
)
defaultTransport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
// By default we wrap the transport in retries, so reduce the
// default dial timeout to 5s to avoid 5x 30s of connection
// timeouts when doing the "ping" on certain http registries.
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
)
// Client provides registry related objects.
type Client interface {
// Keychain provides the configured credentials
Keychain() authn.Keychain
// getTransport provides transport object.
getTransport() http.RoundTripper
// FetchImageDescriptor fetches Descriptor from registry with given imageRef
// and provides access to metadata about remote artifact.
FetchImageDescriptor(context.Context, string) (*gcrremote.Descriptor, error)
// BuildRemoteOption builds remote.Option based on client.
BuildRemoteOption(context.Context) remote.Option
// RefreshKeychainPullSecrets loads fresh data from pull secrets (if non-empty) and updates Keychain.
RefreshKeychainPullSecrets(ctx context.Context) error
}
type client struct {
keychain authn.Keychain
transport http.RoundTripper
pullSecretRefresher func(context.Context, *client) error
}
type config struct {
keychain authn.Keychain
transport *http.Transport
pullSecretRefresher func(context.Context, *client) error
tracing bool
}
// Option is an option to initialize registry client.
type Option = func(*config) error
// New creates a new Client with options
func New(options ...Option) (Client, error) {
cfg := &config{
keychain: baseKeychain,
transport: defaultTransport,
}
for _, opt := range options {
if err := opt(cfg); err != nil {
return nil, err
}
}
c := &client{
keychain: cfg.keychain,
transport: cfg.transport,
pullSecretRefresher: cfg.pullSecretRefresher,
}
if cfg.tracing {
c.transport = tracing.Transport(cfg.transport, otelhttp.WithFilter(tracing.RequestFilterIsInSpan))
}
return c, nil
}
// New creates a new Client with options
func NewOrDie(options ...Option) Client {
c, err := New(options...)
if err != nil {
panic(err)
}
return c
}
// WithKeychainPullSecrets provides initialize registry client option that allows to use pull secrets.
func WithKeychainPullSecrets(ctx context.Context, lister corev1listers.SecretNamespaceLister, imagePullSecrets ...string) Option {
return func(c *config) error {
c.pullSecretRefresher = func(ctx context.Context, c *client) error {
freshKeychain, err := generateKeychainForPullSecrets(ctx, lister, imagePullSecrets...)
if err != nil {
return err
}
c.keychain = authn.NewMultiKeychain(
baseKeychain,
freshKeychain,
)
return nil
}
return nil
}
}
// WithKeychainPullSecrets provides initialize registry client option that allows to use insecure registries.
func WithAllowInsecureRegistry() Option {
return func(c *config) error {
c.transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec
return nil
}
}
// WithLocalKeychain provides initialize keychain with the default local keychain.
func WithLocalKeychain() Option {
return func(c *config) error {
c.pullSecretRefresher = nil
c.keychain = authn.DefaultKeychain
return nil
}
}
// WithTracing enables tracing in the http client.
func WithTracing() Option {
return func(c *config) error {
c.tracing = true
return nil
}
}
// BuildRemoteOption builds remote.Option based on client.
func (c *client) BuildRemoteOption(ctx context.Context) remote.Option {
return remote.WithRemoteOptions(
gcrremote.WithAuthFromKeychain(c.keychain),
gcrremote.WithTransport(c.transport),
gcrremote.WithContext(ctx),
)
}
// FetchImageDescriptor fetches Descriptor from registry with given imageRef
// and provides access to metadata about remote artifact.
func (c *client) FetchImageDescriptor(ctx context.Context, imageRef string) (*gcrremote.Descriptor, error) {
if err := c.RefreshKeychainPullSecrets(ctx); err != nil {
return nil, fmt.Errorf("failed to refresh image pull secrets, error: %v", err)
}
parsedRef, err := name.ParseReference(imageRef)
if err != nil {
return nil, fmt.Errorf("failed to parse image reference: %s, error: %v", imageRef, err)
}
desc, err := gcrremote.Get(parsedRef, gcrremote.WithAuthFromKeychain(c.keychain), gcrremote.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("failed to fetch image reference: %s, error: %v", imageRef, err)
}
return desc, nil
}
// refreshKeychainPullSecrets loads fresh data from pull secrets (if non-empty) and updates Keychain.
func (c *client) RefreshKeychainPullSecrets(ctx context.Context) error {
if c.pullSecretRefresher == nil {
return nil
}
return c.pullSecretRefresher(ctx, c)
}
func (c *client) Keychain() authn.Keychain {
return c.keychain
}
func (c *client) getTransport() http.RoundTripper {
return c.transport
}