Skip to content

Commit 816e227

Browse files
committed
[RFC-0010] Introduce object-level workload identity
Signed-off-by: Matheus Pimenta <[email protected]>
1 parent 09169ce commit 816e227

File tree

5 files changed

+102
-45
lines changed

5 files changed

+102
-45
lines changed

docs/spec/v1beta2/imagerepositories.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ metadata:
208208
namespace: default
209209
spec:
210210
interval: 5m0s
211-
url: example.com
211+
image: example.com
212212
certSecretRef:
213213
name: example-tls
214214
---
@@ -252,7 +252,7 @@ metadata:
252252
namespace: default
253253
spec:
254254
interval: 5m0s
255-
url: example.com
255+
image: example.com
256256
proxySecretRef:
257257
name: http-proxy
258258
---

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ require (
1313
github.com/fluxcd/pkg/apis/acl v0.7.0
1414
github.com/fluxcd/pkg/apis/event v0.17.0
1515
github.com/fluxcd/pkg/apis/meta v1.11.0
16-
github.com/fluxcd/pkg/oci v0.47.0
16+
github.com/fluxcd/pkg/auth v0.11.1-0.20250504212336-3c3c3cab892e
17+
github.com/fluxcd/pkg/cache v0.9.0
1718
github.com/fluxcd/pkg/runtime v0.59.0
1819
github.com/fluxcd/pkg/version v0.7.0
1920
github.com/google/go-containerregistry v0.20.3

go.sum

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRcc
107107
github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU=
108108
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
109109
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
110+
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
111+
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
110112
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
111113
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
112114
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
@@ -161,8 +163,10 @@ github.com/fluxcd/pkg/apis/event v0.17.0 h1:foEINE++pCJlWVhWjYDXfkVmGKu8mQ4BDBlb
161163
github.com/fluxcd/pkg/apis/event v0.17.0/go.mod h1:0fLhLFiHlRTDKPDXdRnv+tS7mCMIQ0fJxnEfmvGM/5A=
162164
github.com/fluxcd/pkg/apis/meta v1.11.0 h1:h8q95k6ZEK1HCfsLkt8Np3i6ktb6ZzcWJ6hg++oc9w0=
163165
github.com/fluxcd/pkg/apis/meta v1.11.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI=
164-
github.com/fluxcd/pkg/oci v0.47.0 h1:eQ7syqy91Xcfd7Sgf64v5n+dfRAju/OBiXuOhZsgQAg=
165-
github.com/fluxcd/pkg/oci v0.47.0/go.mod h1:XBnI8+T6YFnIW4uEFojg7iIgHjKH7LXMpZARXJ9qmZk=
166+
github.com/fluxcd/pkg/auth v0.11.1-0.20250504212336-3c3c3cab892e h1:bYYHjibVjIJLKtTfYAijvfq1TZM50ZA16XuSfEurbrc=
167+
github.com/fluxcd/pkg/auth v0.11.1-0.20250504212336-3c3c3cab892e/go.mod h1:gQD2VT5OhIR1E8ZTEsTaho3bDQZidr9P10smH/awcew=
168+
github.com/fluxcd/pkg/cache v0.9.0 h1:EGKfOLMG3fOwWnH/4Axl5xd425mxoQbZzlZoLfd8PDk=
169+
github.com/fluxcd/pkg/cache v0.9.0/go.mod h1:jMwabjWfsC5lW8hE7NM3wtGNwSJ38Javx6EKbEi7INU=
166170
github.com/fluxcd/pkg/runtime v0.59.0 h1:3OrFkMJB39NcQ2vhhoxqls59sQVSn8U+thhyLbsQoA4=
167171
github.com/fluxcd/pkg/runtime v0.59.0/go.mod h1:MFbfyNyyoYRgPxpdwC9/dCOkzo7Yxhu/cQ9NKyhvqc0=
168172
github.com/fluxcd/pkg/version v0.7.0 h1:jZT5I6WFy1KlM40nHCSqlHmjC1VT1/DfmbAdOkIVVJc=
@@ -176,6 +180,8 @@ github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vt
176180
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
177181
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
178182
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
183+
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
184+
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
179185
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
180186
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
181187
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=

internal/controller/imagerepository_controller.go

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ import (
4848

4949
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
5050
"github.com/fluxcd/pkg/apis/meta"
51-
"github.com/fluxcd/pkg/oci"
52-
"github.com/fluxcd/pkg/oci/auth/login"
51+
"github.com/fluxcd/pkg/auth"
52+
authutils "github.com/fluxcd/pkg/auth/utils"
53+
"github.com/fluxcd/pkg/cache"
5354
"github.com/fluxcd/pkg/runtime/conditions"
5455
helper "github.com/fluxcd/pkg/runtime/controller"
5556
"github.com/fluxcd/pkg/runtime/patch"
@@ -111,11 +112,12 @@ type ImageRepositoryReconciler struct {
111112
helper.Metrics
112113

113114
ControllerName string
115+
TokenCache *cache.TokenCache
114116
Database interface {
115117
DatabaseWriter
116118
DatabaseReader
117119
}
118-
DeprecatedLoginOpts login.ProviderOptions
120+
DeprecatedLoginOpts []auth.Provider
119121

120122
patchOptions []patch.Option
121123
}
@@ -350,7 +352,7 @@ func (r *ImageRepositoryReconciler) setAuthOptions(ctx context.Context, obj *ima
350352
// Configure authentication strategy to access the registry.
351353
var options []remote.Option
352354
var authSecret corev1.Secret
353-
var auth authn.Authenticator
355+
var authenticator authn.Authenticator
354356
var authErr error
355357

356358
if obj.Spec.SecretRef != nil {
@@ -360,37 +362,49 @@ func (r *ImageRepositoryReconciler) setAuthOptions(ctx context.Context, obj *ima
360362
}, &authSecret); err != nil {
361363
return nil, err
362364
}
363-
auth, authErr = secret.AuthFromSecret(authSecret, ref)
365+
authenticator, authErr = secret.AuthFromSecret(authSecret, ref)
364366
} else {
365367
// Build login provider options and use it to attempt registry login.
366-
opts := login.ProviderOptions{}
367-
switch obj.GetProvider() {
368-
case "aws":
369-
opts.AwsAutoLogin = true
370-
case "azure":
371-
opts.AzureAutoLogin = true
372-
case "gcp":
373-
opts.GcpAutoLogin = true
374-
default:
375-
opts = r.DeprecatedLoginOpts
376-
}
377-
var managerOpts []login.Option
368+
var opts []auth.Option
378369
if proxyURL != nil {
379-
managerOpts = append(managerOpts, login.WithProxyURL(proxyURL))
370+
opts = append(opts, auth.WithProxyURL(*proxyURL))
371+
}
372+
switch provider := obj.GetProvider(); provider {
373+
case "aws", "azure", "gcp":
374+
// Support new features (service account and cache) only for non-deprecated code paths.
375+
if obj.Spec.ServiceAccountName != "" {
376+
serviceAccount := client.ObjectKey{
377+
Name: obj.Spec.ServiceAccountName,
378+
Namespace: obj.GetNamespace(),
379+
}
380+
opts = append(opts, auth.WithServiceAccount(serviceAccount, r.Client))
381+
}
382+
if r.TokenCache != nil {
383+
involvedObject := cache.InvolvedObject{
384+
Kind: imagev1.ImageRepositoryKind,
385+
Name: obj.GetName(),
386+
Namespace: obj.GetNamespace(),
387+
Operation: cache.OperationReconcile,
388+
}
389+
opts = append(opts, auth.WithCache(*r.TokenCache, involvedObject))
390+
}
391+
authenticator, authErr = authutils.GetArtifactRegistryCredentials(ctx, provider, obj.Spec.Image, opts...)
392+
default:
393+
// Handle deprecated auto-login controller flags.
394+
for _, provider := range r.DeprecatedLoginOpts {
395+
if _, err := provider.ParseArtifactRepository(obj.Spec.Image); err == nil {
396+
authenticator, authErr = authutils.GetArtifactRegistryCredentials(ctx,
397+
provider.GetName(), obj.Spec.Image, opts...)
398+
break
399+
}
400+
}
380401
}
381-
manager := login.NewManager(managerOpts...)
382-
auth, authErr = manager.Login(ctx, obj.Spec.Image, ref, opts)
383402
}
384403
if authErr != nil {
385-
// If it's not unconfigured provider error, abort reconciliation.
386-
// Continue reconciliation if it's unconfigured providers for scanning
387-
// public repositories.
388-
if !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
389-
return nil, authErr
390-
}
404+
return nil, authErr
391405
}
392-
if auth != nil {
393-
options = append(options, remote.WithAuth(auth))
406+
if authenticator != nil {
407+
options = append(options, remote.WithAuth(authenticator))
394408
}
395409

396410
// Load any provided certificate.
@@ -437,7 +451,7 @@ func (r *ImageRepositoryReconciler) setAuthOptions(ctx context.Context, obj *ima
437451
options = append(options, remote.WithTransport(tr))
438452
}
439453

440-
if obj.Spec.ServiceAccountName != "" {
454+
if authenticator == nil && obj.Spec.ServiceAccountName != "" {
441455
serviceAccount := corev1.ServiceAccount{}
442456
// Lookup service account
443457
if err := r.Get(ctx, types.NamespacedName{
@@ -619,6 +633,10 @@ func (r *ImageRepositoryReconciler) reconcileDelete(ctx context.Context, obj *im
619633
// Remove our finalizer from the list.
620634
controllerutil.RemoveFinalizer(obj, imagev1.ImageFinalizer)
621635

636+
// Cleanup caches.
637+
r.TokenCache.DeleteEventsForObject(imagev1.ImageRepositoryKind,
638+
obj.GetName(), obj.GetNamespace(), cache.OperationReconcile)
639+
622640
// Stop reconciliation as the object is being deleted.
623641
return ctrl.Result{}, nil
624642
}

main.go

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@ import (
3333
ctrlcache "sigs.k8s.io/controller-runtime/pkg/cache"
3434
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
3535
"sigs.k8s.io/controller-runtime/pkg/config"
36+
ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
3637
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
3738

38-
"github.com/fluxcd/pkg/oci/auth/login"
39+
"github.com/fluxcd/pkg/auth"
40+
"github.com/fluxcd/pkg/auth/aws"
41+
"github.com/fluxcd/pkg/auth/azure"
42+
"github.com/fluxcd/pkg/auth/gcp"
43+
pkgcache "github.com/fluxcd/pkg/cache"
3944
"github.com/fluxcd/pkg/runtime/acl"
4045
"github.com/fluxcd/pkg/runtime/client"
4146
helper "github.com/fluxcd/pkg/runtime/controller"
@@ -70,6 +75,10 @@ func init() {
7075
}
7176

7277
func main() {
78+
const (
79+
tokenCacheDefaultMaxSize = 100
80+
)
81+
7382
var (
7483
metricsAddr string
7584
eventsAddr string
@@ -87,6 +96,7 @@ func main() {
8796
aclOptions acl.Options
8897
rateLimiterOptions helper.RateLimiterOptions
8998
featureGates feathelper.FeatureGates
99+
tokenCacheOptions pkgcache.TokenFlags
90100
)
91101

92102
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
@@ -108,6 +118,7 @@ func main() {
108118
rateLimiterOptions.BindFlags(flag.CommandLine)
109119
featureGates.BindFlags(flag.CommandLine)
110120
watchOptions.BindFlags(flag.CommandLine)
121+
tokenCacheOptions.BindFlags(flag.CommandLine, tokenCacheDefaultMaxSize)
111122

112123
flag.Parse()
113124

@@ -215,17 +226,38 @@ func main() {
215226

216227
metricsH := helper.NewMetrics(mgr, metrics.MustMakeRecorder(), imagev1.ImageFinalizer)
217228

229+
var tokenCache *pkgcache.TokenCache
230+
if tokenCacheOptions.MaxSize > 0 {
231+
var err error
232+
tokenCache, err = pkgcache.NewTokenCache(tokenCacheOptions.MaxSize,
233+
pkgcache.WithMaxDuration(tokenCacheOptions.MaxDuration),
234+
pkgcache.WithMetricsRegisterer(ctrlmetrics.Registry),
235+
pkgcache.WithMetricsPrefix("gotk_token_"))
236+
if err != nil {
237+
setupLog.Error(err, "unable to create token cache")
238+
os.Exit(1)
239+
}
240+
}
241+
242+
var deprecatedLoginOpts []auth.Provider
243+
if awsAutoLogin {
244+
deprecatedLoginOpts = append(deprecatedLoginOpts, aws.Provider{})
245+
}
246+
if azureAutoLogin {
247+
deprecatedLoginOpts = append(deprecatedLoginOpts, azure.Provider{})
248+
}
249+
if gcpAutoLogin {
250+
deprecatedLoginOpts = append(deprecatedLoginOpts, gcp.Provider{})
251+
}
252+
218253
if err := (&controller.ImageRepositoryReconciler{
219-
Client: mgr.GetClient(),
220-
EventRecorder: eventRecorder,
221-
Metrics: metricsH,
222-
Database: db,
223-
ControllerName: controllerName,
224-
DeprecatedLoginOpts: login.ProviderOptions{
225-
AwsAutoLogin: awsAutoLogin,
226-
AzureAutoLogin: azureAutoLogin,
227-
GcpAutoLogin: gcpAutoLogin,
228-
},
254+
Client: mgr.GetClient(),
255+
EventRecorder: eventRecorder,
256+
Metrics: metricsH,
257+
Database: db,
258+
ControllerName: controllerName,
259+
TokenCache: tokenCache,
260+
DeprecatedLoginOpts: deprecatedLoginOpts,
229261
}).SetupWithManager(mgr, controller.ImageRepositoryReconcilerOptions{
230262
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
231263
}); err != nil {

0 commit comments

Comments
 (0)