-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🌱 Use SA from spec when installing bundles #907
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,10 +28,16 @@ import ( | |
"go.uber.org/zap/zapcore" | ||
k8slabels "k8s.io/apimachinery/pkg/labels" | ||
"k8s.io/apimachinery/pkg/selection" | ||
"k8s.io/apimachinery/pkg/types" | ||
"k8s.io/client-go/informers" | ||
"k8s.io/client-go/kubernetes" | ||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1" | ||
_ "k8s.io/client-go/plugin/pkg/client/auth" | ||
"k8s.io/client-go/rest" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
crcache "sigs.k8s.io/controller-runtime/pkg/cache" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/event" | ||
crfinalizer "sigs.k8s.io/controller-runtime/pkg/finalizer" | ||
"sigs.k8s.io/controller-runtime/pkg/healthz" | ||
"sigs.k8s.io/controller-runtime/pkg/log/zap" | ||
|
@@ -44,6 +50,7 @@ import ( | |
"github.com/operator-framework/rukpak/pkg/storage" | ||
|
||
ocv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1" | ||
"github.com/operator-framework/operator-controller/internal/authentication" | ||
"github.com/operator-framework/operator-controller/internal/catalogmetadata/cache" | ||
catalogclient "github.com/operator-framework/operator-controller/internal/catalogmetadata/client" | ||
"github.com/operator-framework/operator-controller/internal/controllers" | ||
|
@@ -159,19 +166,44 @@ func main() { | |
cl := mgr.GetClient() | ||
catalogClient := catalogclient.New(cl, cache.NewFilesystemCache(cachePath, httpClient)) | ||
|
||
installNamespaceMapper := helmclient.ObjectToStringMapper(func(obj client.Object) (string, error) { | ||
ext := obj.(*ocv1alpha1.ClusterExtension) | ||
saGetter, err := corev1client.NewForConfig(ctrl.GetConfigOrDie()) | ||
if err != nil { | ||
setupLog.Error(err, "unable to create service account client") | ||
os.Exit(1) | ||
} | ||
|
||
tg := authentication.NewTokenGetter(saGetter, 3600) | ||
nsMapper := func(obj client.Object) (string, error) { | ||
ext, ok := obj.(*ocv1alpha1.ClusterExtension) | ||
if !ok { | ||
return "", fmt.Errorf("cannot derive namespace from object of type %T", obj) | ||
} | ||
return ext.Spec.InstallNamespace, nil | ||
}) | ||
} | ||
|
||
rcm := func(ctx context.Context, obj client.Object, baseRestConfig *rest.Config) (*rest.Config, error) { | ||
cfg := rest.AnonymousClientConfig(rest.CopyConfig(baseRestConfig)) | ||
ext, ok := obj.(*ocv1alpha1.ClusterExtension) | ||
if !ok { | ||
return cfg, nil | ||
} | ||
token, err := tg.Get(ctx, types.NamespacedName{Namespace: ext.Spec.InstallNamespace, Name: ext.Spec.ServiceAccountName}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
cfg.BearerToken = token | ||
return cfg, nil | ||
} | ||
|
||
cfgGetter, err := helmclient.NewActionConfigGetter(mgr.GetConfig(), mgr.GetRESTMapper(), | ||
helmclient.StorageNamespaceMapper(installNamespaceMapper), | ||
helmclient.ClientNamespaceMapper(installNamespaceMapper), | ||
helmclient.ClientNamespaceMapper(nsMapper), | ||
helmclient.StorageNamespaceMapper(nsMapper), | ||
helmclient.RestConfigMapper(rcm), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this setup, we should also remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we would still need list and watch on all objects right ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The initial reason for using such a broad RBAC was the uncertainty regarding the objects the bundle would contain. Consequently, the controller was granted admin permissions to monitor and perform CRUD operations on all GVKs. However, in this scenario, the user (specifically the cluster admin) provides a SA that the controller uses to install contents. It's not necessary for the SA to have admin permissions. Instead, the SA can be granted restricted permissions, limited to only the GVKs present in the bundle. It's expected that the entity providing this SA is aware of the specific permissions needed to install and manage the bundle. This way we minimise the scope of the SA's access, ensuring it only has the necessary permissions to interact with the relevant GRs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True for installing the bundles the SA provided in the spec will be used but the controller also establishes watches on the bundle content and this is done with the controller service account so it needs to be able to watch arbitrary objects. |
||
) | ||
if err != nil { | ||
setupLog.Error(err, "unable to config for creating helm client") | ||
os.Exit(1) | ||
} | ||
|
||
acg, err := helmclient.NewActionClientGetter(cfgGetter) | ||
if err != nil { | ||
setupLog.Error(err, "unable to create helm client") | ||
|
@@ -217,6 +249,10 @@ func main() { | |
InstalledBundleGetter: &controllers.DefaultInstalledBundleGetter{ActionClientGetter: acg}, | ||
Handler: registryv1handler.HandlerFunc(registry.HandleBundleDeployment), | ||
Finalizers: clusterExtensionFinalizers, | ||
InformerClientMap: make(map[types.UID]kubernetes.Interface), | ||
InformerFactoryMap: make(map[types.UID]informers.SharedInformerFactory), | ||
InformerMap: make(map[string]informers.GenericInformer), | ||
EventChannel: make(chan event.GenericEvent), | ||
}).SetupWithManager(mgr); err != nil { | ||
setupLog.Error(err, "unable to create controller", "controller", "ClusterExtension") | ||
os.Exit(1) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional Nit: Using https://pkg.go.dev/k8s.io/api/core/v1#LocalObjectReference could be nice here as it is meant for local object references like we are doing here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure what is meant here, is there an example you can point me to ?