diff --git a/go.mod b/go.mod index 6ff4211e..e92fbf79 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/fluxcd/cli-utils v0.36.0-flux.14 github.com/fluxcd/pkg/apis/event v0.18.0 github.com/fluxcd/pkg/apis/meta v1.18.0 - github.com/fluxcd/pkg/auth v0.21.0 + github.com/fluxcd/pkg/auth v0.27.0 github.com/fluxcd/pkg/cache v0.10.0 github.com/fluxcd/pkg/git v0.35.0 github.com/fluxcd/pkg/git/gogit v0.38.0 diff --git a/go.sum b/go.sum index e6b8be5b..45e7921b 100644 --- a/go.sum +++ b/go.sum @@ -378,8 +378,8 @@ github.com/fluxcd/pkg/apis/event v0.18.0 h1:PNbWk9gvX8gMIi6VsJapnuDO+giLEeY+6olL github.com/fluxcd/pkg/apis/event v0.18.0/go.mod h1:7S/DGboLolfbZ6stO6dcDhG1SfkPWQ9foCULvbiYpiA= github.com/fluxcd/pkg/apis/meta v1.18.0 h1:ACHrMIjlcioE9GKS7NGk62KX4NshqNewr8sBwMcXABs= github.com/fluxcd/pkg/apis/meta v1.18.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8= -github.com/fluxcd/pkg/auth v0.21.0 h1:ckAQqP12wuptXEkMY18SQKWEY09m9e6yI0mEMsDV15M= -github.com/fluxcd/pkg/auth v0.21.0/go.mod h1:MXmpsXT97c874HCw5hnfqFUP7TsG8/Ss1vFrk8JccfM= +github.com/fluxcd/pkg/auth v0.27.0 h1:DFsizUxt9ZDAc+z7+o7jcbtfaxRH55MRD/wdU4CXNCQ= +github.com/fluxcd/pkg/auth v0.27.0/go.mod h1:YEAHpBFuW5oLlH9ekuJaQdnJ2Q3A7Ny8kha3WY7QMnY= github.com/fluxcd/pkg/cache v0.10.0 h1:M+OGDM4da1cnz7q+sZSBtkBJHpiJsLnKVmR9OdMWxEY= github.com/fluxcd/pkg/cache v0.10.0/go.mod h1:pPXRzQUDQagsCniuOolqVhnAkbNgYOg8d2cTliPs7ME= github.com/fluxcd/pkg/git v0.35.0 h1:mAauhsdfxNW4yQdXviVlvcN/uCGGG0+6p5D1+HFZI9w= diff --git a/internal/controller/bucket_controller.go b/internal/controller/bucket_controller.go index 66c65eb9..8657d0e9 100644 --- a/internal/controller/bucket_controller.go +++ b/internal/controller/bucket_controller.go @@ -860,14 +860,13 @@ func (r *BucketReconciler) setupCredentials(ctx context.Context, obj *sourcev1.B // createBucketProvider creates a provider-specific bucket client using the given credentials and configuration. // It handles different bucket providers (AWS, GCP, Azure, generic) and returns the appropriate client. func (r *BucketReconciler) createBucketProvider(ctx context.Context, obj *sourcev1.Bucket, creds *bucketCredentials) (BucketProvider, error) { - var authOpts []auth.Option + authOpts := []auth.Option{ + auth.WithClient(r.Client), + auth.WithServiceAccountNamespace(obj.GetNamespace()), + } if obj.Spec.ServiceAccountName != "" { - serviceAccount := client.ObjectKey{ - Name: obj.Spec.ServiceAccountName, - Namespace: obj.GetNamespace(), - } - authOpts = append(authOpts, auth.WithServiceAccount(serviceAccount, r.Client)) + authOpts = append(authOpts, auth.WithServiceAccountName(obj.Spec.ServiceAccountName)) } if r.TokenCache != nil { diff --git a/internal/controller/bucket_controller_test.go b/internal/controller/bucket_controller_test.go index f3406f28..e00541bb 100644 --- a/internal/controller/bucket_controller_test.go +++ b/internal/controller/bucket_controller_test.go @@ -38,6 +38,7 @@ import ( kstatus "github.com/fluxcd/cli-utils/pkg/kstatus/status" "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/auth" "github.com/fluxcd/pkg/runtime/conditions" conditionscheck "github.com/fluxcd/pkg/runtime/conditions/check" "github.com/fluxcd/pkg/runtime/jitter" @@ -1390,11 +1391,10 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) { patchOptions: getPatchOptions(bucketReadyCondition.Owned, "sc"), } - // Handle ObjectLevelWorkloadIdentity feature gate environment variable - if tt.disableObjectLevelWorkloadIdentity { - t.Setenv("ENABLE_OBJECT_LEVEL_WORKLOAD_IDENTITY", "false") - } else if tt.serviceAccount != nil { - t.Setenv("ENABLE_OBJECT_LEVEL_WORKLOAD_IDENTITY", "true") + // Handle ObjectLevelWorkloadIdentity feature gate + if !tt.disableObjectLevelWorkloadIdentity { + auth.EnableObjectLevelWorkloadIdentity() + t.Cleanup(auth.DisableObjectLevelWorkloadIdentity) } tmpDir := t.TempDir() diff --git a/internal/controller/gitrepository_controller.go b/internal/controller/gitrepository_controller.go index 35ce52e4..e704790d 100644 --- a/internal/controller/gitrepository_controller.go +++ b/internal/controller/gitrepository_controller.go @@ -661,7 +661,10 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1 switch provider := obj.GetProvider(); provider { case sourcev1.GitProviderAzure: // If AWS or GCP are added in the future they can be added here separated by a comma. getCreds = func() (*authutils.GitCredentials, error) { - var opts []auth.Option + opts := []auth.Option{ + auth.WithClient(r.Client), + auth.WithServiceAccountNamespace(obj.GetNamespace()), + } if obj.Spec.ServiceAccountName != "" { // Check object-level workload identity feature gate. @@ -672,11 +675,8 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1 conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, meta.FeatureGateDisabledReason, "%s", err) return nil, err } - serviceAccount := client.ObjectKey{ - Name: obj.Spec.ServiceAccountName, - Namespace: obj.GetNamespace(), - } - opts = append(opts, auth.WithServiceAccount(serviceAccount, r.Client)) + // Set ServiceAccountName only if explicitly specified + opts = append(opts, auth.WithServiceAccountName(obj.Spec.ServiceAccountName)) } if r.TokenCache != nil { diff --git a/internal/controller/ocirepository_controller.go b/internal/controller/ocirepository_controller.go index 6d5341b4..3a86e61e 100644 --- a/internal/controller/ocirepository_controller.go +++ b/internal/controller/ocirepository_controller.go @@ -373,7 +373,11 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch } if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != "" && obj.Spec.Provider != sourcev1.GenericOCIProvider && ok { - var opts []auth.Option + opts := []auth.Option{ + auth.WithClient(r.Client), + auth.WithServiceAccountNamespace(obj.GetNamespace()), + } + if obj.Spec.ServiceAccountName != "" { // Check object-level workload identity feature gate. if !auth.IsObjectLevelWorkloadIdentityEnabled() { @@ -382,11 +386,8 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch err := fmt.Errorf(msgFmt, gate) return sreconcile.ResultEmpty, serror.NewStalling(err, meta.FeatureGateDisabledReason) } - serviceAccount := client.ObjectKey{ - Name: obj.Spec.ServiceAccountName, - Namespace: obj.GetNamespace(), - } - opts = append(opts, auth.WithServiceAccount(serviceAccount, r.Client)) + // Set ServiceAccountName only if explicitly specified + opts = append(opts, auth.WithServiceAccountName(obj.Spec.ServiceAccountName)) } if r.TokenCache != nil { involvedObject := cache.InvolvedObject{ diff --git a/internal/controller/ocirepository_controller_test.go b/internal/controller/ocirepository_controller_test.go index 7f7d9cc9..f1370b78 100644 --- a/internal/controller/ocirepository_controller_test.go +++ b/internal/controller/ocirepository_controller_test.go @@ -3059,7 +3059,8 @@ func TestOCIRepository_objectLevelWorkloadIdentityFeatureGate(t *testing.T) { g.Expect(stalledCondition.Reason).Should(Equal(meta.FeatureGateDisabledReason)) g.Expect(stalledCondition.Message).Should(Equal("to use spec.serviceAccountName for provider authentication please enable the ObjectLevelWorkloadIdentity feature gate in the controller")) - t.Setenv(auth.EnvVarEnableObjectLevelWorkloadIdentity, "true") + auth.EnableObjectLevelWorkloadIdentity() + t.Cleanup(auth.DisableObjectLevelWorkloadIdentity) g.Eventually(func() bool { if err := testEnv.Get(ctx, key, resultobj); err != nil { diff --git a/main.go b/main.go index 114e7c7d..9bfb4e35 100644 --- a/main.go +++ b/main.go @@ -121,6 +121,7 @@ func main() { artifactRetentionRecords int artifactDigestAlgo string tokenCacheOptions pkgcache.TokenFlags + defaultServiceAccount string ) flag.StringVar(&metricsAddr, "metrics-addr", envOrDefault("METRICS_ADDR", ":8080"), @@ -159,6 +160,8 @@ func main() { "The maximum number of artifacts to be kept in storage after a garbage collection.") flag.StringVar(&artifactDigestAlgo, "artifact-digest-algo", intdigest.Canonical.String(), "The algorithm to use to calculate the digest of artifacts.") + flag.StringVar(&defaultServiceAccount, auth.ControllerFlagDefaultServiceAccount, + "", "Default service account to use for workload identity when not specified in resources.") clientOptions.BindFlags(flag.CommandLine) logOptions.BindFlags(flag.CommandLine) @@ -173,6 +176,10 @@ func main() { logger.SetLogger(logger.NewLogger(logOptions)) + if defaultServiceAccount != "" { + auth.SetDefaultServiceAccount(defaultServiceAccount) + } + if err := featureGates.WithLogger(setupLog).SupportedFeatures(features.FeatureGates()); err != nil { setupLog.Error(err, "unable to load feature gates") os.Exit(1) @@ -186,6 +193,11 @@ func main() { auth.EnableObjectLevelWorkloadIdentity() } + if auth.InconsistentObjectLevelConfiguration() { + setupLog.Error(auth.ErrInconsistentObjectLevelConfiguration, "invalid configuration") + os.Exit(1) + } + if err := intervalJitterOptions.SetGlobalJitter(nil); err != nil { setupLog.Error(err, "unable to set global jitter") os.Exit(1)