Enable caching contextual Login Credentials
Provide an optional Cache to the Login Manager used to retrive contextual login credentials. Signed-off-by: Soule BA <bah.soule@gmail.com>
This commit is contained in:
parent
59ad5a72ee
commit
5ecc6b10a8
4
go.mod
4
go.mod
|
@ -22,13 +22,14 @@ require (
|
|||
github.com/fluxcd/cli-utils v0.36.0-flux.7
|
||||
github.com/fluxcd/pkg/apis/event v0.9.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.5.0
|
||||
github.com/fluxcd/pkg/cache v0.0.1
|
||||
github.com/fluxcd/pkg/git v0.19.0
|
||||
github.com/fluxcd/pkg/git/gogit v0.19.0
|
||||
github.com/fluxcd/pkg/gittestserver v0.12.0
|
||||
github.com/fluxcd/pkg/helmtestserver v0.18.0
|
||||
github.com/fluxcd/pkg/lockedfile v0.3.0
|
||||
github.com/fluxcd/pkg/masktoken v0.4.0
|
||||
github.com/fluxcd/pkg/oci v0.37.1
|
||||
github.com/fluxcd/pkg/oci v0.38.0
|
||||
github.com/fluxcd/pkg/runtime v0.47.1
|
||||
github.com/fluxcd/pkg/sourceignore v0.7.0
|
||||
github.com/fluxcd/pkg/ssh v0.13.0
|
||||
|
@ -314,7 +315,6 @@ require (
|
|||
github.com/spf13/cobra v1.8.0 // indirect
|
||||
github.com/spf13/viper v1.18.2 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.2.0 // indirect
|
||||
github.com/stretchr/objx v0.5.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
|
|
10
go.sum
10
go.sum
|
@ -342,6 +342,8 @@ github.com/fluxcd/pkg/apis/event v0.9.0 h1:iKxU+3v/3bAuC1C1iXg1mjbIiaEQet7WETh8l
|
|||
github.com/fluxcd/pkg/apis/event v0.9.0/go.mod h1:5LjcTeppPMEyOgtTbIP7q2GbVwIRUfujIxynIjHBV/k=
|
||||
github.com/fluxcd/pkg/apis/meta v1.5.0 h1:/G82d2Az5D9op3F+wJUpD8jw/eTV0suM6P7+cSURoUM=
|
||||
github.com/fluxcd/pkg/apis/meta v1.5.0/go.mod h1:Y3u7JomuuKtr5fvP1Iji2/50FdRe5GcBug2jawNVkdM=
|
||||
github.com/fluxcd/pkg/cache v0.0.1 h1:aeDQm4D37btj6I01p6ZKW6JNOZm3CIYN5PaVzyhHr38=
|
||||
github.com/fluxcd/pkg/cache v0.0.1/go.mod h1:R3TJIK9XaohHNc3BeqfZX/UivMrx8Xz6ihGoVAjh75k=
|
||||
github.com/fluxcd/pkg/git v0.19.0 h1:zIv+GAT0ieIUpnGBVi3Bhax/qq4Rr28BW7Jv4DTt6zE=
|
||||
github.com/fluxcd/pkg/git v0.19.0/go.mod h1:wkqUOSrTjtsVVk/gC6/7RxVpi9GcqAA+7O5HVJF5S14=
|
||||
github.com/fluxcd/pkg/git/gogit v0.19.0 h1:SdoNAmC/HTPXniQjp609X59rCsBiA+Sdq1Hv8SnYC6I=
|
||||
|
@ -354,8 +356,8 @@ github.com/fluxcd/pkg/lockedfile v0.3.0 h1:tZkBAffcxyt4zMigHIKc54cKgN5I/kFF005gy
|
|||
github.com/fluxcd/pkg/lockedfile v0.3.0/go.mod h1:5iCYXAs953LlXZq7nTId9ZSGnHVvTfZ0mDmrDE49upk=
|
||||
github.com/fluxcd/pkg/masktoken v0.4.0 h1:pRItymXzW8dhT9Fd4XfnbrgKeySPeeLCrr6W1pgrUbM=
|
||||
github.com/fluxcd/pkg/masktoken v0.4.0/go.mod h1:MP1nCsr2tJbH8hnhZP4+7TfTR0ggrKOJgi9Bo7Mj/6M=
|
||||
github.com/fluxcd/pkg/oci v0.37.1 h1:p4rfCHZlBWL+Q5Xey51iiBRmoje0IevCBT0/r8iae3M=
|
||||
github.com/fluxcd/pkg/oci v0.37.1/go.mod h1:LrVuX6VACenJ5ycQJxec+I7YJegCsE4nzRUV+6RuxcY=
|
||||
github.com/fluxcd/pkg/oci v0.38.0 h1:a9pCdqiUPZ7YOnYDXVXCxELBU0r6xbDnGv4C6YUz7vU=
|
||||
github.com/fluxcd/pkg/oci v0.38.0/go.mod h1:mYVSxnpVutRmWu6mpwxm7hXFn6qdhLEjspL04ej/WZU=
|
||||
github.com/fluxcd/pkg/runtime v0.47.1 h1:Q1tAFsp92uurWyoEe52AmMC4k+6DYTPBrUQDs+nz/9c=
|
||||
github.com/fluxcd/pkg/runtime v0.47.1/go.mod h1:97a+PqpWMgQsoqh91uH3EQz+/DC7Uxc8xcu/rDHFC5c=
|
||||
github.com/fluxcd/pkg/sourceignore v0.7.0 h1:qQrB2o543wA1o4vgR62ufwkAaDp8+f8Wdj1HKDlmDrU=
|
||||
|
@ -911,8 +913,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
|
||||
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
|
|
@ -47,7 +47,7 @@ func NewCacheRecorder() *CacheRecorder {
|
|||
return &CacheRecorder{
|
||||
cacheEventsCounter: prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "gotk_cache_events_total",
|
||||
Name: "gotk_sc_cache_events_total",
|
||||
Help: "Total number of cache retrieval events for a Gitops Toolkit resource reconciliation.",
|
||||
},
|
||||
[]string{"event_type", "name", "namespace"},
|
||||
|
|
|
@ -138,8 +138,9 @@ type HelmChartReconciler struct {
|
|||
Getters helmgetter.Providers
|
||||
ControllerName string
|
||||
|
||||
Cache *cache.Cache
|
||||
TTL time.Duration
|
||||
OIDCAuthenticator *soci.OIDCAuthenticator
|
||||
Cache *cache.Cache
|
||||
TTL time.Duration
|
||||
*cache.CacheRecorder
|
||||
|
||||
patchOptions []patch.Option
|
||||
|
@ -527,7 +528,8 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
|
|||
return chartRepoConfigErrorReturn(err, obj)
|
||||
}
|
||||
|
||||
clientOpts, certsTmpDir, err := getter.GetClientOpts(ctxTimeout, r.Client, repo, normalizedURL)
|
||||
clientOpts, certsTmpDir, err := getter.GetClientOptsWithOIDCAuth(ctxTimeout,
|
||||
r.Client, r.OIDCAuthenticator, repo, normalizedURL)
|
||||
if err != nil && !errors.Is(err, getter.ErrDeprecatedTLSConfig) {
|
||||
e := serror.NewGeneric(
|
||||
err,
|
||||
|
@ -1012,8 +1014,9 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
|
|||
}
|
||||
obj = &sourcev1.HelmRepository{
|
||||
Spec: sourcev1.HelmRepositorySpec{
|
||||
URL: url,
|
||||
Timeout: &metav1.Duration{Duration: 60 * time.Second},
|
||||
URL: url,
|
||||
Timeout: &metav1.Duration{Duration: 60 * time.Second},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1022,7 +1025,8 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
|
|||
ctxTimeout, cancel := context.WithTimeout(ctx, obj.GetTimeout())
|
||||
defer cancel()
|
||||
|
||||
clientOpts, certsTmpDir, err := getter.GetClientOpts(ctxTimeout, r.Client, obj, normalizedURL)
|
||||
clientOpts, certsTmpDir, err := getter.GetClientOptsWithOIDCAuth(ctxTimeout, r.Client,
|
||||
r.OIDCAuthenticator, obj, normalizedURL)
|
||||
if err != nil && !errors.Is(err, getter.ErrDeprecatedTLSConfig) {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1129,8 +1129,9 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) {
|
|||
GenerateName: "helmrepository-",
|
||||
},
|
||||
Spec: sourcev1.HelmRepositorySpec{
|
||||
URL: server.URL(),
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
URL: server.URL(),
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
Status: sourcev1.HelmRepositoryStatus{
|
||||
Artifact: &sourcev1.Artifact{
|
||||
|
@ -2647,11 +2648,14 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
authenticator, er := oci.NewOIDCAuthenticator(oci.WithCacheCapacity(1))
|
||||
g.Expect(er).NotTo(HaveOccurred())
|
||||
r := &HelmChartReconciler{
|
||||
Client: clientBuilder.Build(),
|
||||
EventRecorder: record.NewFakeRecorder(32),
|
||||
Getters: testGetters,
|
||||
RegistryClientGenerator: registry.ClientGenerator,
|
||||
OIDCAuthenticator: authenticator,
|
||||
patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"),
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ import (
|
|||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
"github.com/fluxcd/source-controller/internal/cache"
|
||||
intdigest "github.com/fluxcd/source-controller/internal/digest"
|
||||
"github.com/fluxcd/source-controller/internal/helm/getter"
|
||||
|
@ -819,6 +820,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
|
|||
Spec: sourcev1.HelmRepositorySpec{
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ type OCIRepositoryReconciler struct {
|
|||
Storage *Storage
|
||||
ControllerName string
|
||||
requeueDependency time.Duration
|
||||
OIDCAuthenticator *soci.OIDCAuthenticator
|
||||
|
||||
patchOptions []patch.Option
|
||||
}
|
||||
|
@ -355,7 +356,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
|
|||
|
||||
if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != ociv1.GenericOCIProvider && ok {
|
||||
var authErr error
|
||||
auth, authErr = soci.OIDCAuth(ctxTimeout, obj.Spec.URL, obj.Spec.Provider)
|
||||
auth, authErr = r.OIDCAuthenticator.Authorization(ctxTimeout, obj.Spec.URL, obj.Spec.Provider)
|
||||
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
|
||||
e := serror.NewGeneric(
|
||||
fmt.Errorf("failed to get credential from %s: %w", obj.Spec.Provider, authErr),
|
||||
|
|
|
@ -69,8 +69,10 @@ import (
|
|||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
ociv1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
intdigest "github.com/fluxcd/source-controller/internal/digest"
|
||||
serror "github.com/fluxcd/source-controller/internal/error"
|
||||
soci "github.com/fluxcd/source-controller/internal/oci"
|
||||
snotation "github.com/fluxcd/source-controller/internal/oci/notation"
|
||||
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
|
||||
)
|
||||
|
@ -795,11 +797,15 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
|
|||
obj.Spec.Insecure = true
|
||||
}
|
||||
|
||||
authenticator, er := soci.NewOIDCAuthenticator(soci.WithCacheCapacity(1))
|
||||
g.Expect(er).NotTo(HaveOccurred())
|
||||
|
||||
r := &OCIRepositoryReconciler{
|
||||
Client: clientBuilder.Build(),
|
||||
EventRecorder: record.NewFakeRecorder(32),
|
||||
Storage: testStorage,
|
||||
patchOptions: getPatchOptions(ociRepositoryReadyCondition.Owned, "sc"),
|
||||
Client: clientBuilder.Build(),
|
||||
EventRecorder: record.NewFakeRecorder(32),
|
||||
Storage: testStorage,
|
||||
OIDCAuthenticator: authenticator,
|
||||
patchOptions: getPatchOptions(ociRepositoryReadyCondition.Owned, "sc"),
|
||||
}
|
||||
|
||||
opts := makeRemoteOptions(ctx, makeTransport(tt.insecure), authn.DefaultKeychain, nil)
|
||||
|
@ -1147,6 +1153,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) {
|
|||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Insecure: true,
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1398,6 +1405,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi
|
|||
},
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1718,6 +1726,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes
|
|||
},
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -2042,6 +2051,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing
|
|||
},
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -2265,6 +2275,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi
|
|||
},
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
Reference: tt.reference,
|
||||
},
|
||||
}
|
||||
|
@ -2448,6 +2459,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) {
|
|||
Reference: &ociv1.OCIRepositoryRef{Tag: "6.1.5"},
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
Insecure: true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -64,13 +64,17 @@ func (o ClientOpts) MustLoginToRegistry() bool {
|
|||
return len(o.RegLoginOpts) > 0 && o.RegLoginOpts[0] != nil
|
||||
}
|
||||
|
||||
// GetClientOpts uses the provided HelmRepository object and a normalized
|
||||
// GetClientOptsWithOIDCAuth uses the provided HelmRepository object and a normalized
|
||||
// URL to construct a HelmClientOpts object. If obj is an OCI HelmRepository,
|
||||
// then the returned options object will also contain the required registry
|
||||
// auth mechanisms.
|
||||
// A temporary directory is created to store the certs files if needed and its path is returned along with the options object. It is the
|
||||
// caller's responsibility to clean up the directory.
|
||||
func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepository, url string) (*ClientOpts, string, error) {
|
||||
func GetClientOptsWithOIDCAuth(ctx context.Context, c client.Client, oidcAuthenticator *soci.OIDCAuthenticator,
|
||||
obj *sourcev1.HelmRepository, url string) (*ClientOpts, string, error) {
|
||||
if obj.Spec.Provider != sourcev1beta2.GenericOCIProvider && oidcAuthenticator == nil {
|
||||
return nil, "", fmt.Errorf("OIDC authenticator is not configured")
|
||||
}
|
||||
hrOpts := &ClientOpts{
|
||||
GetterOpts: []helmgetter.Option{
|
||||
helmgetter.WithURL(url),
|
||||
|
@ -137,7 +141,7 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepos
|
|||
}
|
||||
}
|
||||
} else if obj.Spec.Provider != sourcev1beta2.GenericOCIProvider && obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI && ociRepo {
|
||||
authenticator, authErr := soci.OIDCAuth(ctx, obj.Spec.URL, obj.Spec.Provider)
|
||||
authenticator, authErr := oidcAuthenticator.Authorization(ctx, obj.Spec.URL, obj.Spec.Provider)
|
||||
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
|
||||
return nil, "", fmt.Errorf("failed to get credential from '%s': %w", obj.Spec.Provider, authErr)
|
||||
}
|
||||
|
@ -179,6 +183,16 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepos
|
|||
return hrOpts, dir, err
|
||||
}
|
||||
|
||||
// GetClientOpts uses the provided HelmRepository object and a normalized
|
||||
// URL to construct a HelmClientOpts object. If obj is an OCI HelmRepository,
|
||||
// then the returned options object will also contain the required registry
|
||||
// auth mechanisms.
|
||||
// A temporary directory is created to store the certs files if needed and its path is returned along with the options object. It is the
|
||||
// caller's responsibility to clean up the directory.
|
||||
func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepository, url string) (*ClientOpts, string, error) {
|
||||
return GetClientOptsWithOIDCAuth(ctx, c, nil, obj, url)
|
||||
}
|
||||
|
||||
func fetchSecret(ctx context.Context, c client.Client, name, namespace string) (*corev1.Secret, error) {
|
||||
key := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
helmv1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
func TestGetClientOpts(t *testing.T) {
|
||||
|
@ -143,6 +144,7 @@ func TestGetClientOpts(t *testing.T) {
|
|||
Duration: time.Second,
|
||||
},
|
||||
Insecure: tt.insecure,
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
},
|
||||
}
|
||||
if tt.oci {
|
||||
|
@ -249,7 +251,8 @@ func TestGetClientOpts_registryTLSLoginOption(t *testing.T) {
|
|||
Timeout: &metav1.Duration{
|
||||
Duration: time.Second,
|
||||
},
|
||||
Type: helmv1.HelmRepositoryTypeOCI,
|
||||
Provider: sourcev1beta2.GenericOCIProvider,
|
||||
Type: helmv1.HelmRepositoryTypeOCI,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -20,14 +20,30 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/cache"
|
||||
"github.com/fluxcd/pkg/oci/auth/login"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
const (
|
||||
// We want to cache the authenticators for the 3rd party providers
|
||||
// There are at least 3 providers (aws, azure, gcp), but there could be more
|
||||
// e.g. alibaba, ibm, etc. But realistically, we can expect the number of
|
||||
// providers to be less than 10.
|
||||
DefaultAuthCacheCapacity = 10
|
||||
// The cache cleanup interval, to remove expired entries
|
||||
// 1 minute is a reasonable interval for authentication tokens.
|
||||
// We don't want to be aggressive with the cleanup, as the tokens
|
||||
// are valid for a longer period of time usually.
|
||||
defaultAuthCacheInterval = time.Minute
|
||||
)
|
||||
|
||||
// Anonymous is an authn.AuthConfig that always returns an anonymous
|
||||
// authenticator. It is useful for registries that do not require authentication
|
||||
// or when the credentials are not known.
|
||||
|
@ -39,15 +55,62 @@ func (a Anonymous) Resolve(_ authn.Resource) (authn.Authenticator, error) {
|
|||
return authn.Anonymous, nil
|
||||
}
|
||||
|
||||
// OIDCAuth generates the OIDC credential authenticator based on the specified cloud provider.
|
||||
func OIDCAuth(ctx context.Context, url, provider string) (authn.Authenticator, error) {
|
||||
// OIDCAuthenticatorOptionFunc is a functional option for the OIDCAuthenticator.
|
||||
type OIDCAuthenticatorOptionFunc func(opts *oidcAuthenticatorOptions)
|
||||
|
||||
type oidcAuthenticatorOptions struct {
|
||||
capacity int
|
||||
}
|
||||
|
||||
// WithCacheCapacity sets the capacity of the cache.
|
||||
func WithCacheCapacity(capacity int) OIDCAuthenticatorOptionFunc {
|
||||
return func(opts *oidcAuthenticatorOptions) {
|
||||
opts.capacity = capacity
|
||||
}
|
||||
}
|
||||
|
||||
// OIDCAuthenticator holds a manager for the OIDC authenticators.
|
||||
// It caches the authenticators to avoid re-authenticating for the same URL.
|
||||
type OIDCAuthenticator struct {
|
||||
manager *login.Manager
|
||||
cache cache.Expirable[cache.StoreObject[authn.Authenticator]]
|
||||
}
|
||||
|
||||
// NewOIDCAuthenticator returns a new OIDCAuthenticator.
|
||||
// The capacity is the number of authenticators to cache.
|
||||
// If the capacity is less than or equal to 0, the cache is disabled.
|
||||
func NewOIDCAuthenticator(opts ...OIDCAuthenticatorOptionFunc) (*OIDCAuthenticator, error) {
|
||||
o := &oidcAuthenticatorOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
|
||||
var (
|
||||
c cache.Expirable[cache.StoreObject[authn.Authenticator]]
|
||||
err error
|
||||
)
|
||||
if o.capacity > 0 {
|
||||
c, err = cache.New(o.capacity, cache.StoreObjectKeyFunc,
|
||||
cache.WithCleanupInterval[cache.StoreObject[authn.Authenticator]](defaultAuthCacheInterval),
|
||||
cache.WithMetricsRegisterer[cache.StoreObject[authn.Authenticator]](metrics.Registry))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create cache: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
manager := login.NewManager()
|
||||
return &OIDCAuthenticator{cache: c, manager: manager}, nil
|
||||
}
|
||||
|
||||
// Authorization returns an authenticator for the OIDC credentials.
|
||||
func (o *OIDCAuthenticator) Authorization(ctx context.Context, url, provider string) (authn.Authenticator, error) {
|
||||
u := strings.TrimPrefix(url, sourcev1.OCIRepositoryPrefix)
|
||||
ref, err := name.ParseReference(u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URL '%s': %w", u, err)
|
||||
}
|
||||
|
||||
opts := login.ProviderOptions{}
|
||||
opts := login.ProviderOptions{Cache: o.cache}
|
||||
switch provider {
|
||||
case sourcev1.AmazonOCIProvider:
|
||||
opts.AwsAutoLogin = true
|
||||
|
@ -57,5 +120,5 @@ func OIDCAuth(ctx context.Context, url, provider string) (authn.Authenticator, e
|
|||
opts.GcpAutoLogin = true
|
||||
}
|
||||
|
||||
return login.NewManager().Login(ctx, u, ref, opts)
|
||||
return o.manager.Login(ctx, u, ref, opts)
|
||||
}
|
||||
|
|
31
main.go
31
main.go
|
@ -50,7 +50,7 @@ import (
|
|||
"github.com/fluxcd/pkg/runtime/pprof"
|
||||
"github.com/fluxcd/pkg/runtime/probes"
|
||||
|
||||
"github.com/fluxcd/source-controller/api/v1"
|
||||
v1 "github.com/fluxcd/source-controller/api/v1"
|
||||
"github.com/fluxcd/source-controller/api/v1beta2"
|
||||
|
||||
// +kubebuilder:scaffold:imports
|
||||
|
@ -61,6 +61,7 @@ import (
|
|||
"github.com/fluxcd/source-controller/internal/features"
|
||||
"github.com/fluxcd/source-controller/internal/helm"
|
||||
"github.com/fluxcd/source-controller/internal/helm/registry"
|
||||
"github.com/fluxcd/source-controller/internal/oci"
|
||||
)
|
||||
|
||||
const controllerName = "source-controller"
|
||||
|
@ -187,6 +188,8 @@ func main() {
|
|||
mustSetupHelmLimits(helmIndexLimit, helmChartLimit, helmChartFileLimit)
|
||||
helmIndexCache, helmIndexCacheItemTTL := mustInitHelmCache(helmCacheMaxSize, helmCacheTTL, helmCachePurgeInterval)
|
||||
|
||||
authenticator := mustInitOIDCAuthenticator()
|
||||
|
||||
ctx := ctrl.SetupSignalHandler()
|
||||
|
||||
if err := (&controller.GitRepositoryReconciler{
|
||||
|
@ -228,6 +231,7 @@ func main() {
|
|||
EventRecorder: eventRecorder,
|
||||
Metrics: metrics,
|
||||
ControllerName: controllerName,
|
||||
OIDCAuthenticator: authenticator,
|
||||
Cache: helmIndexCache,
|
||||
TTL: helmIndexCacheItemTTL,
|
||||
CacheRecorder: cacheRecorder,
|
||||
|
@ -252,11 +256,12 @@ func main() {
|
|||
}
|
||||
|
||||
if err := (&controller.OCIRepositoryReconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Storage: storage,
|
||||
EventRecorder: eventRecorder,
|
||||
ControllerName: controllerName,
|
||||
Metrics: metrics,
|
||||
Client: mgr.GetClient(),
|
||||
Storage: storage,
|
||||
EventRecorder: eventRecorder,
|
||||
ControllerName: controllerName,
|
||||
Metrics: metrics,
|
||||
OIDCAuthenticator: authenticator,
|
||||
}).SetupWithManagerAndOptions(mgr, controller.OCIRepositoryReconcilerOptions{
|
||||
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
|
||||
}); err != nil {
|
||||
|
@ -406,6 +411,20 @@ func mustInitHelmCache(maxSize int, itemTTL, purgeInterval string) (*cache.Cache
|
|||
return cache.New(maxSize, interval), ttl
|
||||
}
|
||||
|
||||
func mustInitOIDCAuthenticator() *oci.OIDCAuthenticator {
|
||||
capacity := oci.DefaultAuthCacheCapacity
|
||||
disabled, found := os.LookupEnv("LOGIN_CACHE_DISABLED")
|
||||
if found && disabled == "true" {
|
||||
capacity = -1
|
||||
}
|
||||
authenticator, err := oci.NewOIDCAuthenticator(oci.WithCacheCapacity(capacity))
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to initialise OIDC authenticator")
|
||||
os.Exit(1)
|
||||
}
|
||||
return authenticator
|
||||
}
|
||||
|
||||
func mustInitStorage(path string, storageAdvAddr string, artifactRetentionTTL time.Duration, artifactRetentionRecords int, artifactDigestAlgo string) *controller.Storage {
|
||||
if storageAdvAddr == "" {
|
||||
storageAdvAddr = determineAdvStorageAddr(storageAdvAddr)
|
||||
|
|
Loading…
Reference in New Issue