Implement OCI auth for cloud providers
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
This commit is contained in:
parent
8cc8798e6e
commit
63c94397f7
|
@ -50,6 +50,8 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/oci"
|
||||
"github.com/fluxcd/pkg/oci/auth/login"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
helper "github.com/fluxcd/pkg/runtime/controller"
|
||||
"github.com/fluxcd/pkg/runtime/events"
|
||||
|
@ -64,14 +66,6 @@ import (
|
|||
"github.com/fluxcd/source-controller/internal/util"
|
||||
)
|
||||
|
||||
const (
|
||||
ClientCert = "certFile"
|
||||
ClientKey = "keyFile"
|
||||
CACert = "caFile"
|
||||
OCISourceKey = "org.opencontainers.image.source"
|
||||
OCIRevisionKey = "org.opencontainers.image.revision"
|
||||
)
|
||||
|
||||
// ociRepositoryReadyCondition contains the information required to summarize a
|
||||
// v1beta2.OCIRepository Ready Condition.
|
||||
var ociRepositoryReadyCondition = summarize.Conditions{
|
||||
|
@ -297,7 +291,9 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
|
|||
ctxTimeout, cancel := context.WithTimeout(ctx, obj.Spec.Timeout.Duration)
|
||||
defer cancel()
|
||||
|
||||
// Generate the registry credential keychain
|
||||
options := r.craneOptions(ctxTimeout)
|
||||
|
||||
// Generate the registry credential keychain either from static credentials or using cloud OIDC
|
||||
keychain, err := r.keychain(ctx, obj)
|
||||
if err != nil {
|
||||
e := serror.NewGeneric(
|
||||
|
@ -307,6 +303,22 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
|
|||
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
|
||||
return sreconcile.ResultEmpty, e
|
||||
}
|
||||
options = append(options, crane.WithAuthFromKeychain(keychain))
|
||||
|
||||
if obj.Spec.Provider != sourcev1.GenericOCIProvider {
|
||||
auth, authErr := r.oidcAuth(ctxTimeout, obj)
|
||||
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
|
||||
e := serror.NewGeneric(
|
||||
fmt.Errorf("failed to get credential from %s: %w", obj.Spec.Provider, authErr),
|
||||
sourcev1.AuthenticationFailedReason,
|
||||
)
|
||||
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
|
||||
return sreconcile.ResultEmpty, e
|
||||
}
|
||||
if auth != nil {
|
||||
options = append(options, crane.WithAuth(auth))
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the transport for remote operations
|
||||
transport, err := r.transport(ctx, obj)
|
||||
|
@ -318,9 +330,12 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
|
|||
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
|
||||
return sreconcile.ResultEmpty, e
|
||||
}
|
||||
if transport != nil {
|
||||
options = append(options, crane.WithTransport(transport))
|
||||
}
|
||||
|
||||
// Determine which artifact revision to pull
|
||||
url, err := r.getArtifactURL(ctxTimeout, obj, keychain, transport)
|
||||
url, err := r.getArtifactURL(obj, options)
|
||||
if err != nil {
|
||||
e := serror.NewGeneric(
|
||||
fmt.Errorf("failed to determine the artifact address for '%s': %w", obj.Spec.URL, err),
|
||||
|
@ -330,7 +345,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
|
|||
}
|
||||
|
||||
// Pull artifact from the remote container registry
|
||||
img, err := crane.Pull(url, r.craneOptions(ctxTimeout, keychain, transport)...)
|
||||
img, err := crane.Pull(url, options...)
|
||||
if err != nil {
|
||||
e := serror.NewGeneric(
|
||||
fmt.Errorf("failed to pull artifact from '%s': %w", obj.Spec.URL, err),
|
||||
|
@ -437,12 +452,16 @@ func (r *OCIRepositoryReconciler) parseRepositoryURL(obj *sourcev1.OCIRepository
|
|||
return "", err
|
||||
}
|
||||
|
||||
imageName := strings.TrimPrefix(url, ref.Context().RegistryStr())
|
||||
if s := strings.Split(imageName, ":"); len(s) > 1 {
|
||||
return "", fmt.Errorf("URL must not contain a tag; remove ':%s'", s[1])
|
||||
}
|
||||
|
||||
return ref.Context().Name(), nil
|
||||
}
|
||||
|
||||
// getArtifactURL determines which tag or digest should be used and returns the OCI artifact FQN.
|
||||
func (r *OCIRepositoryReconciler) getArtifactURL(ctx context.Context,
|
||||
obj *sourcev1.OCIRepository, keychain authn.Keychain, transport http.RoundTripper) (string, error) {
|
||||
func (r *OCIRepositoryReconciler) getArtifactURL(obj *sourcev1.OCIRepository, options []crane.Option) (string, error) {
|
||||
url, err := r.parseRepositoryURL(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -454,7 +473,7 @@ func (r *OCIRepositoryReconciler) getArtifactURL(ctx context.Context,
|
|||
}
|
||||
|
||||
if obj.Spec.Reference.SemVer != "" {
|
||||
tag, err := r.getTagBySemver(ctx, url, obj.Spec.Reference.SemVer, keychain, transport)
|
||||
tag, err := r.getTagBySemver(url, obj.Spec.Reference.SemVer, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -471,9 +490,8 @@ func (r *OCIRepositoryReconciler) getArtifactURL(ctx context.Context,
|
|||
|
||||
// getTagBySemver call the remote container registry, fetches all the tags from the repository,
|
||||
// and returns the latest tag according to the semver expression.
|
||||
func (r *OCIRepositoryReconciler) getTagBySemver(ctx context.Context,
|
||||
url, exp string, keychain authn.Keychain, transport http.RoundTripper) (string, error) {
|
||||
tags, err := crane.ListTags(url, r.craneOptions(ctx, keychain, transport)...)
|
||||
func (r *OCIRepositoryReconciler) getTagBySemver(url, exp string, options []crane.Option) (string, error) {
|
||||
tags, err := crane.ListTags(url, options...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -567,20 +585,20 @@ func (r *OCIRepositoryReconciler) transport(ctx context.Context, obj *sourcev1.O
|
|||
transport := remote.DefaultTransport.Clone()
|
||||
tlsConfig := transport.TLSClientConfig
|
||||
|
||||
if clientCert, ok := certSecret.Data[ClientCert]; ok {
|
||||
if clientCert, ok := certSecret.Data[oci.ClientCert]; ok {
|
||||
// parse and set client cert and secret
|
||||
if clientKey, ok := certSecret.Data[ClientKey]; ok {
|
||||
if clientKey, ok := certSecret.Data[oci.ClientKey]; ok {
|
||||
cert, err := tls.X509KeyPair(clientCert, clientKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
|
||||
} else {
|
||||
return nil, fmt.Errorf("'%s' found in secret, but no %s", ClientCert, ClientKey)
|
||||
return nil, fmt.Errorf("'%s' found in secret, but no %s", oci.ClientCert, oci.ClientKey)
|
||||
}
|
||||
}
|
||||
|
||||
if caCert, ok := certSecret.Data[CACert]; ok {
|
||||
if caCert, ok := certSecret.Data[oci.CACert]; ok {
|
||||
syscerts, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -592,20 +610,34 @@ func (r *OCIRepositoryReconciler) transport(ctx context.Context, obj *sourcev1.O
|
|||
|
||||
}
|
||||
|
||||
// oidcAuth generates the OIDC credential authenticator based on the specified cloud provider.
|
||||
func (r *OCIRepositoryReconciler) oidcAuth(ctx context.Context, obj *sourcev1.OCIRepository) (authn.Authenticator, error) {
|
||||
url := strings.TrimPrefix(obj.Spec.URL, sourcev1.OCIRepositoryPrefix)
|
||||
ref, err := name.ParseReference(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URL '%s': %w", obj.Spec.URL, err)
|
||||
}
|
||||
|
||||
opts := login.ProviderOptions{}
|
||||
switch obj.Spec.Provider {
|
||||
case sourcev1.AmazonOCIProvider:
|
||||
opts.AwsAutoLogin = true
|
||||
case sourcev1.AzureOCIProvider:
|
||||
opts.AzureAutoLogin = true
|
||||
case sourcev1.GoogleOCIProvider:
|
||||
opts.GcpAutoLogin = true
|
||||
}
|
||||
|
||||
return login.NewManager().Login(ctx, url, ref, opts)
|
||||
}
|
||||
|
||||
// craneOptions sets the auth headers, timeout and user agent
|
||||
// for all operations against remote container registries.
|
||||
func (r *OCIRepositoryReconciler) craneOptions(ctx context.Context,
|
||||
keychain authn.Keychain, transport http.RoundTripper) []crane.Option {
|
||||
func (r *OCIRepositoryReconciler) craneOptions(ctx context.Context) []crane.Option {
|
||||
options := []crane.Option{
|
||||
crane.WithContext(ctx),
|
||||
crane.WithUserAgent("flux/v2"),
|
||||
crane.WithAuthFromKeychain(keychain),
|
||||
crane.WithUserAgent(oci.UserAgent),
|
||||
}
|
||||
|
||||
if transport != nil {
|
||||
options = append(options, crane.WithTransport(transport))
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
|
@ -834,10 +866,10 @@ func (r *OCIRepositoryReconciler) notify(ctx context.Context,
|
|||
// enrich message with upstream annotations if found
|
||||
if info := newObj.GetArtifact().Metadata; info != nil {
|
||||
var source, revision string
|
||||
if val, ok := info[OCISourceKey]; ok {
|
||||
if val, ok := info[oci.SourceAnnotation]; ok {
|
||||
source = val
|
||||
}
|
||||
if val, ok := info[OCIRevisionKey]; ok {
|
||||
if val, ok := info[oci.RevisionAnnotation]; ok {
|
||||
revision = val
|
||||
}
|
||||
if source != "" && revision != "" {
|
||||
|
|
|
@ -36,11 +36,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
|
||||
"github.com/darkowlzz/controller-check/status"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/oci"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
"github.com/fluxcd/pkg/untar"
|
||||
|
@ -54,8 +52,10 @@ import (
|
|||
gcrv1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
@ -172,8 +172,8 @@ func TestOCIRepository_Reconcile(t *testing.T) {
|
|||
g.Expect(obj.Status.Artifact.Revision).To(Equal(tt.digest))
|
||||
|
||||
// Check if the metadata matches the expected annotations
|
||||
g.Expect(obj.Status.Artifact.Metadata[OCISourceKey]).To(ContainSubstring("podinfo"))
|
||||
g.Expect(obj.Status.Artifact.Metadata[OCIRevisionKey]).To(ContainSubstring(tt.tag))
|
||||
g.Expect(obj.Status.Artifact.Metadata[oci.SourceAnnotation]).To(ContainSubstring("podinfo"))
|
||||
g.Expect(obj.Status.Artifact.Metadata[oci.RevisionAnnotation]).To(ContainSubstring(tt.tag))
|
||||
|
||||
// Check if the artifact storage path matches the expected file path
|
||||
localPath := testStorage.LocalPath(*obj.Status.Artifact)
|
||||
|
@ -516,7 +516,9 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
|
|||
Storage: testStorage,
|
||||
}
|
||||
|
||||
repoURL, err := r.getArtifactURL(ctx, obj, nil, nil)
|
||||
opts := r.craneOptions(ctx)
|
||||
opts = append(opts, crane.WithAuthFromKeychain(authn.DefaultKeychain))
|
||||
repoURL, err := r.getArtifactURL(obj, opts)
|
||||
g.Expect(err).To(BeNil())
|
||||
|
||||
assertConditions := tt.assertConditions
|
||||
|
@ -566,9 +568,9 @@ func TestOCIRepository_CertSecret(t *testing.T) {
|
|||
|
||||
tlsSecretClientCert := corev1.Secret{
|
||||
StringData: map[string]string{
|
||||
CACert: string(rootCertPEM),
|
||||
ClientCert: string(clientCertPEM),
|
||||
ClientKey: string(clientKeyPEM),
|
||||
oci.CACert: string(rootCertPEM),
|
||||
oci.ClientCert: string(clientCertPEM),
|
||||
oci.ClientKey: string(clientKeyPEM),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -601,9 +603,9 @@ func TestOCIRepository_CertSecret(t *testing.T) {
|
|||
digest: pi.digest,
|
||||
certSecret: &corev1.Secret{
|
||||
StringData: map[string]string{
|
||||
CACert: string(rootCertPEM),
|
||||
ClientCert: string(clientCertPEM),
|
||||
ClientKey: string("invalid-key"),
|
||||
oci.CACert: string(rootCertPEM),
|
||||
oci.ClientCert: string(clientCertPEM),
|
||||
oci.ClientKey: string("invalid-key"),
|
||||
},
|
||||
},
|
||||
expectreadyconition: false,
|
||||
|
@ -1049,7 +1051,9 @@ func TestOCIRepository_getArtifactURL(t *testing.T) {
|
|||
obj.Spec.Reference = tt.reference
|
||||
}
|
||||
|
||||
got, err := r.getArtifactURL(ctx, obj, authn.DefaultKeychain, nil)
|
||||
opts := r.craneOptions(ctx)
|
||||
opts = append(opts, crane.WithAuthFromKeychain(authn.DefaultKeychain))
|
||||
got, err := r.getArtifactURL(obj, opts)
|
||||
if tt.wantErr {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
return
|
||||
|
@ -1266,8 +1270,8 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) {
|
|||
Revision: "xxx",
|
||||
Checksum: "yyy",
|
||||
Metadata: map[string]string{
|
||||
OCISourceKey: "https://github.com/stefanprodan/podinfo",
|
||||
OCIRevisionKey: "6.1.8/b3b00fe35424a45d373bf4c7214178bc36fd7872",
|
||||
oci.SourceAnnotation: "https://github.com/stefanprodan/podinfo",
|
||||
oci.RevisionAnnotation: "6.1.8/b3b00fe35424a45d373bf4c7214178bc36fd7872",
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -1438,8 +1442,8 @@ func pushMultiplePodinfoImages(serverURL string, versions ...string) (map[string
|
|||
|
||||
func setPodinfoImageAnnotations(img gcrv1.Image, tag string) gcrv1.Image {
|
||||
metadata := map[string]string{
|
||||
OCISourceKey: "https://github.com/stefanprodan/podinfo",
|
||||
OCIRevisionKey: fmt.Sprintf("%s/SHA", tag),
|
||||
oci.SourceAnnotation: "https://github.com/stefanprodan/podinfo",
|
||||
oci.RevisionAnnotation: fmt.Sprintf("%s/SHA", tag),
|
||||
}
|
||||
return mutate.Annotations(img, metadata).(gcrv1.Image)
|
||||
}
|
||||
|
|
|
@ -101,6 +101,33 @@ container image repository in the format `oci://<host>:<port>/<org-name>/<repo-n
|
|||
|
||||
**Note:** that specifying a tag or digest is not in accepted for this field.
|
||||
|
||||
### Provider
|
||||
|
||||
`.spec.provider` is an optional field that allows specifying an OIDC provider used for
|
||||
authentication purposes.
|
||||
|
||||
Supported options are:
|
||||
|
||||
- `generic`
|
||||
- `aws`
|
||||
- `azure`
|
||||
- `gcp`
|
||||
|
||||
The `generic` provider can be used for public repositories or when
|
||||
static credentials are used for authentication, either with
|
||||
`spec.secretRef` or `spec.serviceAccountName`.
|
||||
If you do not specify `.spec.provider`, it defaults to `generic`.
|
||||
|
||||
The `aws` provider can be used when the source-controller service account
|
||||
is associate with an AWS IAM Role using IRSA that grants read-only access to ECR.
|
||||
|
||||
The `azure` provider can be used when the source-controller pods are associate
|
||||
with an Azure AAD Pod Identity that grants read-only access to ACR.
|
||||
|
||||
The `gcp` provider can be used when the source-controller service account
|
||||
is associate with a GCP IAM Role using Workload Identity that grants
|
||||
read-only access to Artifact Registry.
|
||||
|
||||
### Secret reference
|
||||
|
||||
`.spec.secretRef.name` is an optional field to specify a name reference to a
|
||||
|
|
14
go.mod
14
go.mod
|
@ -27,7 +27,7 @@ require (
|
|||
github.com/ProtonMail/go-crypto v0.0.0-20220623141421-5afb4c282135
|
||||
github.com/cyphar/filepath-securejoin v0.2.3
|
||||
github.com/darkowlzz/controller-check v0.0.0-20220325122359-11f5827b7981
|
||||
github.com/distribution/distribution/v3 v3.0.0-20220702071910-8857a1948739
|
||||
github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f
|
||||
github.com/docker/cli v20.10.17+incompatible
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021
|
||||
|
@ -37,6 +37,7 @@ require (
|
|||
github.com/fluxcd/pkg/gitutil v0.1.0
|
||||
github.com/fluxcd/pkg/helmtestserver v0.7.4
|
||||
github.com/fluxcd/pkg/lockedfile v0.1.0
|
||||
github.com/fluxcd/pkg/oci v0.2.0
|
||||
github.com/fluxcd/pkg/runtime v0.16.2
|
||||
github.com/fluxcd/pkg/ssh v0.5.0
|
||||
github.com/fluxcd/pkg/testserver v0.2.0
|
||||
|
@ -55,7 +56,7 @@ require (
|
|||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/spf13/pflag v1.0.5
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60
|
||||
golang.org/x/net v0.0.0-20220708220712-1185a9018129
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
||||
google.golang.org/api v0.86.0
|
||||
gotest.tools v2.2.0+incompatible
|
||||
|
@ -108,6 +109,7 @@ require (
|
|||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.53 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.15.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.3 // indirect
|
||||
|
@ -218,7 +220,7 @@ require (
|
|||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
|
@ -229,7 +231,7 @@ require (
|
|||
github.com/russross/blackfriday v1.6.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cobra v1.5.0 // indirect
|
||||
github.com/stretchr/testify v1.7.4 // indirect
|
||||
|
@ -247,8 +249,8 @@ require (
|
|||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92 // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||
|
|
25
go.sum
25
go.sum
|
@ -179,6 +179,8 @@ github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde/go.mod h1:oG9D
|
|||
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.44.53 h1:2MErE8gRyBLuE1fuH2Sqlj1xoN3S6/jXb0aO/A1jGfk=
|
||||
github.com/aws/aws-sdk-go v1.44.53/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.7.1/go.mod h1:L5LuPC1ZgDr2xQS7AmIec/Jlc7O/Y1u2KxJyNVab250=
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.4 h1:swQTEQUyJF/UkEA94/Ga55miiKFoXmm/Zd67XHgmjSg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.4/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
||||
|
@ -317,8 +319,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20220702071910-8857a1948739 h1:fOBqIwS8s+ircSm/N6VQcIZPaFoomoAWgxwG2Ssp15I=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20220702071910-8857a1948739/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f h1:3NCYdjXycNd/Xn/iICZzmxkiDX1e1cjTHjbMAz+wRVk=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4=
|
||||
github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c=
|
||||
github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
|
||||
github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
|
@ -397,6 +399,8 @@ github.com/fluxcd/pkg/helmtestserver v0.7.4 h1:/Xj2+XLz7wr38MI3uPYvVAsZB9wQOq6rp
|
|||
github.com/fluxcd/pkg/helmtestserver v0.7.4/go.mod h1:aL5V4o8wUOMqeHMfjbVHS057E3ejzHMRVMqEbsK9FUQ=
|
||||
github.com/fluxcd/pkg/lockedfile v0.1.0 h1:YsYFAkd6wawMCcD74ikadAKXA4s2sukdxrn7w8RB5eo=
|
||||
github.com/fluxcd/pkg/lockedfile v0.1.0/go.mod h1:EJLan8t9MiOcgTs8+puDjbE6I/KAfHbdvIy9VUgIjm8=
|
||||
github.com/fluxcd/pkg/oci v0.2.0 h1:pvLF6iKmSj9u48Da7qlBDVIiH2NLOrbFUFE4Yr431Lc=
|
||||
github.com/fluxcd/pkg/oci v0.2.0/go.mod h1:c1pj9E/G5927gSa6ooACAyZe+HwjgmPk9johL7oXDHw=
|
||||
github.com/fluxcd/pkg/runtime v0.16.2 h1:CexfMmJK+r12sHTvKWyAax0pcPomjd6VnaHXcxjUrRY=
|
||||
github.com/fluxcd/pkg/runtime v0.16.2/go.mod h1:OHSKsrO+T+Ym8WZRS2oidrnauWRARuE2nfm8ewevm7M=
|
||||
github.com/fluxcd/pkg/ssh v0.5.0 h1:jE9F2XvUXC2mgseeXMATvO014fLqdB30/VzlPLKsk20=
|
||||
|
@ -1004,8 +1008,9 @@ github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1H
|
|||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pjbgf/git2go/v33 v33.0.9-nothread-check h1:gSK7FaLECIM3VSuBOAsVZQtWd+51iTB5lv9RyxhOYMk=
|
||||
github.com/pjbgf/git2go/v33 v33.0.9-nothread-check/go.mod h1:KdpqkU+6+++4oHna/MIOgx4GCQ92IPCdpVRMRI80J+4=
|
||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
|
||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -1100,8 +1105,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
|
|||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
|
@ -1405,8 +1411,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
|||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 h1:8NSylCMxLW4JvserAndSgFL7aPli6A68yf0bYFTcWCM=
|
||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
|
||||
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -1428,8 +1434,9 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
|
|||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92 h1:oVlhw3Oe+1reYsE2Nqu19PDJfLzwdU3QUUrG86rLK68=
|
||||
golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -1520,6 +1527,7 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -1547,8 +1555,9 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
|
Loading…
Reference in New Issue