Skip to content

Commit 5ecc6b1

Browse files
committed
Enable caching contextual Login Credentials
Provide an optional Cache to the Login Manager used to retrive contextual login credentials. Signed-off-by: Soule BA <[email protected]>
1 parent 59ad5a7 commit 5ecc6b1

12 files changed

+158
-34
lines changed

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ require (
2222
github.com/fluxcd/cli-utils v0.36.0-flux.7
2323
github.com/fluxcd/pkg/apis/event v0.9.0
2424
github.com/fluxcd/pkg/apis/meta v1.5.0
25+
github.com/fluxcd/pkg/cache v0.0.1
2526
github.com/fluxcd/pkg/git v0.19.0
2627
github.com/fluxcd/pkg/git/gogit v0.19.0
2728
github.com/fluxcd/pkg/gittestserver v0.12.0
2829
github.com/fluxcd/pkg/helmtestserver v0.18.0
2930
github.com/fluxcd/pkg/lockedfile v0.3.0
3031
github.com/fluxcd/pkg/masktoken v0.4.0
31-
github.com/fluxcd/pkg/oci v0.37.1
32+
github.com/fluxcd/pkg/oci v0.38.0
3233
github.com/fluxcd/pkg/runtime v0.47.1
3334
github.com/fluxcd/pkg/sourceignore v0.7.0
3435
github.com/fluxcd/pkg/ssh v0.13.0
@@ -314,7 +315,6 @@ require (
314315
github.com/spf13/cobra v1.8.0 // indirect
315316
github.com/spf13/viper v1.18.2 // indirect
316317
github.com/spiffe/go-spiffe/v2 v2.2.0 // indirect
317-
github.com/stretchr/objx v0.5.1 // indirect
318318
github.com/subosito/gotenv v1.6.0 // indirect
319319
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
320320
github.com/thales-e-security/pool v0.0.2 // indirect

go.sum

+6-4
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ github.com/fluxcd/pkg/apis/event v0.9.0 h1:iKxU+3v/3bAuC1C1iXg1mjbIiaEQet7WETh8l
342342
github.com/fluxcd/pkg/apis/event v0.9.0/go.mod h1:5LjcTeppPMEyOgtTbIP7q2GbVwIRUfujIxynIjHBV/k=
343343
github.com/fluxcd/pkg/apis/meta v1.5.0 h1:/G82d2Az5D9op3F+wJUpD8jw/eTV0suM6P7+cSURoUM=
344344
github.com/fluxcd/pkg/apis/meta v1.5.0/go.mod h1:Y3u7JomuuKtr5fvP1Iji2/50FdRe5GcBug2jawNVkdM=
345+
github.com/fluxcd/pkg/cache v0.0.1 h1:aeDQm4D37btj6I01p6ZKW6JNOZm3CIYN5PaVzyhHr38=
346+
github.com/fluxcd/pkg/cache v0.0.1/go.mod h1:R3TJIK9XaohHNc3BeqfZX/UivMrx8Xz6ihGoVAjh75k=
345347
github.com/fluxcd/pkg/git v0.19.0 h1:zIv+GAT0ieIUpnGBVi3Bhax/qq4Rr28BW7Jv4DTt6zE=
346348
github.com/fluxcd/pkg/git v0.19.0/go.mod h1:wkqUOSrTjtsVVk/gC6/7RxVpi9GcqAA+7O5HVJF5S14=
347349
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
354356
github.com/fluxcd/pkg/lockedfile v0.3.0/go.mod h1:5iCYXAs953LlXZq7nTId9ZSGnHVvTfZ0mDmrDE49upk=
355357
github.com/fluxcd/pkg/masktoken v0.4.0 h1:pRItymXzW8dhT9Fd4XfnbrgKeySPeeLCrr6W1pgrUbM=
356358
github.com/fluxcd/pkg/masktoken v0.4.0/go.mod h1:MP1nCsr2tJbH8hnhZP4+7TfTR0ggrKOJgi9Bo7Mj/6M=
357-
github.com/fluxcd/pkg/oci v0.37.1 h1:p4rfCHZlBWL+Q5Xey51iiBRmoje0IevCBT0/r8iae3M=
358-
github.com/fluxcd/pkg/oci v0.37.1/go.mod h1:LrVuX6VACenJ5ycQJxec+I7YJegCsE4nzRUV+6RuxcY=
359+
github.com/fluxcd/pkg/oci v0.38.0 h1:a9pCdqiUPZ7YOnYDXVXCxELBU0r6xbDnGv4C6YUz7vU=
360+
github.com/fluxcd/pkg/oci v0.38.0/go.mod h1:mYVSxnpVutRmWu6mpwxm7hXFn6qdhLEjspL04ej/WZU=
359361
github.com/fluxcd/pkg/runtime v0.47.1 h1:Q1tAFsp92uurWyoEe52AmMC4k+6DYTPBrUQDs+nz/9c=
360362
github.com/fluxcd/pkg/runtime v0.47.1/go.mod h1:97a+PqpWMgQsoqh91uH3EQz+/DC7Uxc8xcu/rDHFC5c=
361363
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+
911913
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
912914
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
913915
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
914-
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
915-
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
916+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
917+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
916918
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
917919
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
918920
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=

internal/cache/metrics.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func NewCacheRecorder() *CacheRecorder {
4747
return &CacheRecorder{
4848
cacheEventsCounter: prometheus.NewCounterVec(
4949
prometheus.CounterOpts{
50-
Name: "gotk_cache_events_total",
50+
Name: "gotk_sc_cache_events_total",
5151
Help: "Total number of cache retrieval events for a Gitops Toolkit resource reconciliation.",
5252
},
5353
[]string{"event_type", "name", "namespace"},

internal/controller/helmchart_controller.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ type HelmChartReconciler struct {
138138
Getters helmgetter.Providers
139139
ControllerName string
140140

141-
Cache *cache.Cache
142-
TTL time.Duration
141+
OIDCAuthenticator *soci.OIDCAuthenticator
142+
Cache *cache.Cache
143+
TTL time.Duration
143144
*cache.CacheRecorder
144145

145146
patchOptions []patch.Option
@@ -527,7 +528,8 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
527528
return chartRepoConfigErrorReturn(err, obj)
528529
}
529530

530-
clientOpts, certsTmpDir, err := getter.GetClientOpts(ctxTimeout, r.Client, repo, normalizedURL)
531+
clientOpts, certsTmpDir, err := getter.GetClientOptsWithOIDCAuth(ctxTimeout,
532+
r.Client, r.OIDCAuthenticator, repo, normalizedURL)
531533
if err != nil && !errors.Is(err, getter.ErrDeprecatedTLSConfig) {
532534
e := serror.NewGeneric(
533535
err,
@@ -1012,8 +1014,9 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
10121014
}
10131015
obj = &sourcev1.HelmRepository{
10141016
Spec: sourcev1.HelmRepositorySpec{
1015-
URL: url,
1016-
Timeout: &metav1.Duration{Duration: 60 * time.Second},
1017+
URL: url,
1018+
Timeout: &metav1.Duration{Duration: 60 * time.Second},
1019+
Provider: sourcev1beta2.GenericOCIProvider,
10171020
},
10181021
}
10191022
}
@@ -1022,7 +1025,8 @@ func (r *HelmChartReconciler) namespacedChartRepositoryCallback(ctx context.Cont
10221025
ctxTimeout, cancel := context.WithTimeout(ctx, obj.GetTimeout())
10231026
defer cancel()
10241027

1025-
clientOpts, certsTmpDir, err := getter.GetClientOpts(ctxTimeout, r.Client, obj, normalizedURL)
1028+
clientOpts, certsTmpDir, err := getter.GetClientOptsWithOIDCAuth(ctxTimeout, r.Client,
1029+
r.OIDCAuthenticator, obj, normalizedURL)
10261030
if err != nil && !errors.Is(err, getter.ErrDeprecatedTLSConfig) {
10271031
return nil, err
10281032
}

internal/controller/helmchart_controller_test.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -1129,8 +1129,9 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) {
11291129
GenerateName: "helmrepository-",
11301130
},
11311131
Spec: sourcev1.HelmRepositorySpec{
1132-
URL: server.URL(),
1133-
Timeout: &metav1.Duration{Duration: timeout},
1132+
URL: server.URL(),
1133+
Timeout: &metav1.Duration{Duration: timeout},
1134+
Provider: sourcev1beta2.GenericOCIProvider,
11341135
},
11351136
Status: sourcev1.HelmRepositoryStatus{
11361137
Artifact: &sourcev1.Artifact{
@@ -2647,11 +2648,14 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
26472648
},
26482649
}
26492650

2651+
authenticator, er := oci.NewOIDCAuthenticator(oci.WithCacheCapacity(1))
2652+
g.Expect(er).NotTo(HaveOccurred())
26502653
r := &HelmChartReconciler{
26512654
Client: clientBuilder.Build(),
26522655
EventRecorder: record.NewFakeRecorder(32),
26532656
Getters: testGetters,
26542657
RegistryClientGenerator: registry.ClientGenerator,
2658+
OIDCAuthenticator: authenticator,
26552659
patchOptions: getPatchOptions(helmChartReadyCondition.Owned, "sc"),
26562660
}
26572661

internal/controller/helmrepository_controller_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import (
5050
"github.com/fluxcd/pkg/runtime/patch"
5151

5252
sourcev1 "github.com/fluxcd/source-controller/api/v1"
53+
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
5354
"github.com/fluxcd/source-controller/internal/cache"
5455
intdigest "github.com/fluxcd/source-controller/internal/digest"
5556
"github.com/fluxcd/source-controller/internal/helm/getter"
@@ -819,6 +820,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) {
819820
Spec: sourcev1.HelmRepositorySpec{
820821
Interval: metav1.Duration{Duration: interval},
821822
Timeout: &metav1.Duration{Duration: timeout},
823+
Provider: sourcev1beta2.GenericOCIProvider,
822824
},
823825
}
824826

internal/controller/ocirepository_controller.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ type OCIRepositoryReconciler struct {
141141
Storage *Storage
142142
ControllerName string
143143
requeueDependency time.Duration
144+
OIDCAuthenticator *soci.OIDCAuthenticator
144145

145146
patchOptions []patch.Option
146147
}
@@ -355,7 +356,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
355356

356357
if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != ociv1.GenericOCIProvider && ok {
357358
var authErr error
358-
auth, authErr = soci.OIDCAuth(ctxTimeout, obj.Spec.URL, obj.Spec.Provider)
359+
auth, authErr = r.OIDCAuthenticator.Authorization(ctxTimeout, obj.Spec.URL, obj.Spec.Provider)
359360
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
360361
e := serror.NewGeneric(
361362
fmt.Errorf("failed to get credential from %s: %w", obj.Spec.Provider, authErr),

internal/controller/ocirepository_controller_test.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,10 @@ import (
6969

7070
sourcev1 "github.com/fluxcd/source-controller/api/v1"
7171
ociv1 "github.com/fluxcd/source-controller/api/v1beta2"
72+
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
7273
intdigest "github.com/fluxcd/source-controller/internal/digest"
7374
serror "github.com/fluxcd/source-controller/internal/error"
75+
soci "github.com/fluxcd/source-controller/internal/oci"
7476
snotation "github.com/fluxcd/source-controller/internal/oci/notation"
7577
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
7678
)
@@ -795,11 +797,15 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
795797
obj.Spec.Insecure = true
796798
}
797799

800+
authenticator, er := soci.NewOIDCAuthenticator(soci.WithCacheCapacity(1))
801+
g.Expect(er).NotTo(HaveOccurred())
802+
798803
r := &OCIRepositoryReconciler{
799-
Client: clientBuilder.Build(),
800-
EventRecorder: record.NewFakeRecorder(32),
801-
Storage: testStorage,
802-
patchOptions: getPatchOptions(ociRepositoryReadyCondition.Owned, "sc"),
804+
Client: clientBuilder.Build(),
805+
EventRecorder: record.NewFakeRecorder(32),
806+
Storage: testStorage,
807+
OIDCAuthenticator: authenticator,
808+
patchOptions: getPatchOptions(ociRepositoryReadyCondition.Owned, "sc"),
803809
}
804810

805811
opts := makeRemoteOptions(ctx, makeTransport(tt.insecure), authn.DefaultKeychain, nil)
@@ -1147,6 +1153,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) {
11471153
Interval: metav1.Duration{Duration: interval},
11481154
Timeout: &metav1.Duration{Duration: timeout},
11491155
Insecure: true,
1156+
Provider: sourcev1beta2.GenericOCIProvider,
11501157
},
11511158
}
11521159

@@ -1398,6 +1405,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi
13981405
},
13991406
Interval: metav1.Duration{Duration: interval},
14001407
Timeout: &metav1.Duration{Duration: timeout},
1408+
Provider: sourcev1beta2.GenericOCIProvider,
14011409
},
14021410
}
14031411

@@ -1718,6 +1726,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes
17181726
},
17191727
Interval: metav1.Duration{Duration: interval},
17201728
Timeout: &metav1.Duration{Duration: timeout},
1729+
Provider: sourcev1beta2.GenericOCIProvider,
17211730
},
17221731
}
17231732

@@ -2042,6 +2051,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing
20422051
},
20432052
Interval: metav1.Duration{Duration: interval},
20442053
Timeout: &metav1.Duration{Duration: timeout},
2054+
Provider: sourcev1beta2.GenericOCIProvider,
20452055
},
20462056
}
20472057

@@ -2265,6 +2275,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi
22652275
},
22662276
Interval: metav1.Duration{Duration: interval},
22672277
Timeout: &metav1.Duration{Duration: timeout},
2278+
Provider: sourcev1beta2.GenericOCIProvider,
22682279
Reference: tt.reference,
22692280
},
22702281
}
@@ -2448,6 +2459,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) {
24482459
Reference: &ociv1.OCIRepositoryRef{Tag: "6.1.5"},
24492460
Interval: metav1.Duration{Duration: interval},
24502461
Timeout: &metav1.Duration{Duration: timeout},
2462+
Provider: sourcev1beta2.GenericOCIProvider,
24512463
Insecure: true,
24522464
},
24532465
}

internal/helm/getter/client_opts.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,17 @@ func (o ClientOpts) MustLoginToRegistry() bool {
6464
return len(o.RegLoginOpts) > 0 && o.RegLoginOpts[0] != nil
6565
}
6666

67-
// GetClientOpts uses the provided HelmRepository object and a normalized
67+
// GetClientOptsWithOIDCAuth uses the provided HelmRepository object and a normalized
6868
// URL to construct a HelmClientOpts object. If obj is an OCI HelmRepository,
6969
// then the returned options object will also contain the required registry
7070
// auth mechanisms.
7171
// 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
7272
// caller's responsibility to clean up the directory.
73-
func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepository, url string) (*ClientOpts, string, error) {
73+
func GetClientOptsWithOIDCAuth(ctx context.Context, c client.Client, oidcAuthenticator *soci.OIDCAuthenticator,
74+
obj *sourcev1.HelmRepository, url string) (*ClientOpts, string, error) {
75+
if obj.Spec.Provider != sourcev1beta2.GenericOCIProvider && oidcAuthenticator == nil {
76+
return nil, "", fmt.Errorf("OIDC authenticator is not configured")
77+
}
7478
hrOpts := &ClientOpts{
7579
GetterOpts: []helmgetter.Option{
7680
helmgetter.WithURL(url),
@@ -137,7 +141,7 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepos
137141
}
138142
}
139143
} else if obj.Spec.Provider != sourcev1beta2.GenericOCIProvider && obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI && ociRepo {
140-
authenticator, authErr := soci.OIDCAuth(ctx, obj.Spec.URL, obj.Spec.Provider)
144+
authenticator, authErr := oidcAuthenticator.Authorization(ctx, obj.Spec.URL, obj.Spec.Provider)
141145
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
142146
return nil, "", fmt.Errorf("failed to get credential from '%s': %w", obj.Spec.Provider, authErr)
143147
}
@@ -179,6 +183,16 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepos
179183
return hrOpts, dir, err
180184
}
181185

186+
// GetClientOpts uses the provided HelmRepository object and a normalized
187+
// URL to construct a HelmClientOpts object. If obj is an OCI HelmRepository,
188+
// then the returned options object will also contain the required registry
189+
// auth mechanisms.
190+
// 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
191+
// caller's responsibility to clean up the directory.
192+
func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepository, url string) (*ClientOpts, string, error) {
193+
return GetClientOptsWithOIDCAuth(ctx, c, nil, obj, url)
194+
}
195+
182196
func fetchSecret(ctx context.Context, c client.Client, name, namespace string) (*corev1.Secret, error) {
183197
key := types.NamespacedName{
184198
Namespace: namespace,

internal/helm/getter/client_opts_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
3131

3232
helmv1 "github.com/fluxcd/source-controller/api/v1"
33+
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
3334
)
3435

3536
func TestGetClientOpts(t *testing.T) {
@@ -143,6 +144,7 @@ func TestGetClientOpts(t *testing.T) {
143144
Duration: time.Second,
144145
},
145146
Insecure: tt.insecure,
147+
Provider: sourcev1beta2.GenericOCIProvider,
146148
},
147149
}
148150
if tt.oci {
@@ -249,7 +251,8 @@ func TestGetClientOpts_registryTLSLoginOption(t *testing.T) {
249251
Timeout: &metav1.Duration{
250252
Duration: time.Second,
251253
},
252-
Type: helmv1.HelmRepositoryTypeOCI,
254+
Provider: sourcev1beta2.GenericOCIProvider,
255+
Type: helmv1.HelmRepositoryTypeOCI,
253256
},
254257
}
255258

0 commit comments

Comments
 (0)