diff --git a/controllers/imagepolicy_controller.go b/controllers/imagepolicy_controller.go index 85076e39..47e52a18 100644 --- a/controllers/imagepolicy_controller.go +++ b/controllers/imagepolicy_controller.go @@ -57,6 +57,7 @@ type ImagePolicyReconciler struct { ExternalEventRecorder *events.Recorder MetricsRecorder *metrics.Recorder Database DatabaseReader + ACLOptions acl.Options } type ImagePolicyReconcilerOptions struct { @@ -97,6 +98,23 @@ func (r *ImagePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) if pol.Spec.ImageRepositoryRef.Namespace != "" { repoNamespacedName.Namespace = pol.Spec.ImageRepositoryRef.Namespace } + + // check if we're allowed to reference across namespaces, before trying to fetch it + if r.ACLOptions.NoCrossNamespaceRefs && repoNamespacedName.Namespace != pol.GetNamespace() { + err := fmt.Errorf("cannot access '%s/%s', cross-namespace references have been blocked", imagev1.ImageRepositoryKind, repoNamespacedName) + imagev1.SetImagePolicyReadiness( + &pol, + metav1.ConditionFalse, + aclapi.AccessDeniedReason, + err.Error(), + ) + if err := r.patchStatus(ctx, req, pol.Status); err != nil { + return ctrl.Result{Requeue: true}, err + } + log.Error(err, "access denied to cross-namespace ImageRepository") + return ctrl.Result{}, nil // this cannot proceed until the spec changes, so no need to requeue explicitly + } + if err := r.Get(ctx, repoNamespacedName, &repo); err != nil { if client.IgnoreNotFound(err) == nil { imagev1.SetImagePolicyReadiness( diff --git a/main.go b/main.go index b24a434c..915756ca 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" crtlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" + "github.com/fluxcd/pkg/runtime/acl" "github.com/fluxcd/pkg/runtime/client" "github.com/fluxcd/pkg/runtime/events" "github.com/fluxcd/pkg/runtime/leaderelection" @@ -72,6 +73,7 @@ func main() { awsAutoLogin bool gcpAutoLogin bool azureAutoLogin bool + aclOptions acl.Options ) flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") @@ -89,6 +91,7 @@ func main() { clientOptions.BindFlags(flag.CommandLine) logOptions.BindFlags(flag.CommandLine) leaderElectionOptions.BindFlags(flag.CommandLine) + aclOptions.BindFlags(flag.CommandLine) flag.Parse() log := logger.NewLogger(logOptions) @@ -167,6 +170,7 @@ func main() { ExternalEventRecorder: eventRecorder, MetricsRecorder: metricsRecorder, Database: db, + ACLOptions: aclOptions, }).SetupWithManager(mgr, controllers.ImagePolicyReconcilerOptions{ MaxConcurrentReconciles: concurrent, }); err != nil {