diff --git a/Makefile b/Makefile index c0659d7ba8..31b08ff782 100644 --- a/Makefile +++ b/Makefile @@ -209,6 +209,10 @@ manifests-generate: $(CONTROLLER_GEN) manifests-kustomize: $(KUSTOMIZE) $< build config/default > config/render/capm3.yaml +.PHONY: manifests-generate-namespaced +manifests-generate-namespaced: manifests-generate $(KUSTOMIZE) + $(KUSTOMIZE) build config/overlays/namespaced > config/render/capm3.yaml + .PHONY: set-manifest-image-bmo set-manifest-image-bmo: $(KUSTOMIZE) manifests $(info Updating container image for BMO to use ${MANIFEST_IMG}:${MANIFEST_TAG}) diff --git a/config/overlays/namespaced/kustomization.yaml b/config/overlays/namespaced/kustomization.yaml new file mode 100644 index 0000000000..955f3ad80c --- /dev/null +++ b/config/overlays/namespaced/kustomization.yaml @@ -0,0 +1,49 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +bases: + - ../../default + +# The subjects and roleRef needs to be update here otherwise we lose name-prefix +# This is of course not ideal if the name-prefix changes +patchesStrategicMerge: + - namespaced-manager-patch.yaml + - | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: baremetal-operator-manager-rolebinding + roleRef: + kind: Role + name: baremetal-operator-manager-role + subjects: + - kind: ServiceAccount + name: baremetal-operator-controller-manager + namespace: baremetal-operator-system + +patches: +- patch: | + # Add a namespace to watch + - op: replace + path: /kind + value: RoleBinding + - op: add + path: /metadata/namespace + value: single-ns-bmh + target: + group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: baremetal-operator-manager-rolebinding + +- patch: | + # Add a namespace to watch + - op: replace + path: /kind + value: Role + - op: add + path: /metadata/namespace + value: single-ns-bmh + target: + group: rbac.authorization.k8s.io + kind: ClusterRole + name: baremetal-operator-manager-role diff --git a/config/overlays/namespaced/namespaced-manager-patch.yaml b/config/overlays/namespaced/namespaced-manager-patch.yaml new file mode 100644 index 0000000000..2adb5b47e3 --- /dev/null +++ b/config/overlays/namespaced/namespaced-manager-patch.yaml @@ -0,0 +1,13 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + env: + - name: WATCH_NAMESPACE + value: "single-ns-bmh" \ No newline at end of file diff --git a/config/render/capm3.yaml b/config/render/capm3.yaml index fa76809136..f79badec58 100644 --- a/config/render/capm3.yaml +++ b/config/render/capm3.yaml @@ -2167,9 +2167,10 @@ rules: - delete --- apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole +kind: Role metadata: name: baremetal-operator-manager-role + namespace: single-ns-bmh rules: - apiGroups: - "" @@ -2412,12 +2413,13 @@ subjects: namespace: baremetal-operator-system --- apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding +kind: RoleBinding metadata: name: baremetal-operator-manager-rolebinding + namespace: single-ns-bmh roleRef: apiGroup: rbac.authorization.k8s.io - kind: ClusterRole + kind: Role name: baremetal-operator-manager-role subjects: - kind: ServiceAccount @@ -2525,6 +2527,8 @@ spec: command: - /baremetal-operator env: + - name: WATCH_NAMESPACE + value: single-ns-bmh - name: POD_NAME valueFrom: fieldRef: diff --git a/controllers/metal3.io/baremetalhost_controller.go b/controllers/metal3.io/baremetalhost_controller.go index 40ece1ec62..3199b31c74 100644 --- a/controllers/metal3.io/baremetalhost_controller.go +++ b/controllers/metal3.io/baremetalhost_controller.go @@ -82,24 +82,24 @@ func (info *reconcileInfo) publishEvent(reason, message string) { info.events = append(info.events, info.host.NewEvent(reason, message)) } -// +kubebuilder:rbac:groups=metal3.io,resources=baremetalhosts,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=metal3.io,resources=baremetalhosts/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=metal3.io,resources=baremetalhosts/finalizers,verbs=update -// +kubebuilder:rbac:groups=metal3.io,resources=preprovisioningimages,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=metal3.io,resources=hardwaredata,verbs=get;list;watch;create;delete;patch;update -// +kubebuilder:rbac:groups=metal3.io,resources=hardware/finalizers,verbs=update -// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;update;delete -// +kubebuilder:rbac:groups="",resources=events,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=baremetalhosts,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=baremetalhosts/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=baremetalhosts/finalizers,verbs=update +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=preprovisioningimages,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=hardwaredata,verbs=get;list;watch;create;delete;patch;update +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=hardware/finalizers,verbs=update +// +kubebuilder:rbac:groups="",namespace="",resources=secrets,verbs=get;list;watch;update;delete +// +kubebuilder:rbac:groups="",namespace="",resources=events,verbs=get;list;watch;create;update;patch // Allow for managing hostfirmwaresettings, firmwareschema, bmceventsubscriptions and hostfirmwarecomponents -//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwaresettings,verbs=get;list;watch;create;update;patch -//+kubebuilder:rbac:groups=metal3.io,resources=firmwareschemas,verbs=get;list;watch;create;update;patch -//+kubebuilder:rbac:groups=metal3.io,resources=bmceventsubscriptions,verbs=get;list;watch;create;update;patch -//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents,verbs=get;list;watch;create;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=hostfirmwaresettings,verbs=get;list;watch;create;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=firmwareschemas,verbs=get;list;watch;create;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=bmceventsubscriptions,verbs=get;list;watch;create;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=hostfirmwarecomponents,verbs=get;list;watch;create;update;patch // Allow for updating dataimage -// +kubebuilder:rbac:groups=metal3.io,resources=dataimages,verbs=get;list;watch;create;update;patch -// +kubebuilder:rbac:groups=metal3.io,resources=dataimages/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=dataimages,verbs=get;list;watch;create;update;patch +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=dataimages/status,verbs=get;update;patch // Reconcile handles changes to BareMetalHost resources. func (r *BareMetalHostReconciler) Reconcile(ctx context.Context, request ctrl.Request) (result ctrl.Result, err error) { diff --git a/controllers/metal3.io/bmceventsubscription_controller.go b/controllers/metal3.io/bmceventsubscription_controller.go index 994cc56ddd..6041825bff 100644 --- a/controllers/metal3.io/bmceventsubscription_controller.go +++ b/controllers/metal3.io/bmceventsubscription_controller.go @@ -49,8 +49,8 @@ type BMCEventSubscriptionReconciler struct { APIReader client.Reader } -//+kubebuilder:rbac:groups=metal3.io,resources=bmceventsubscriptions,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=metal3.io,resources=bmceventsubscriptions/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=bmceventsubscriptions,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=bmceventsubscriptions/status,verbs=get;update;patch func (r *BMCEventSubscriptionReconciler) Reconcile(ctx context.Context, request ctrl.Request) (result ctrl.Result, err error) { reqLogger := r.Log.WithValues("bmceventsubscription", request.NamespacedName) diff --git a/controllers/metal3.io/dataimage_controller.go b/controllers/metal3.io/dataimage_controller.go index b24a8e9178..66203b2634 100644 --- a/controllers/metal3.io/dataimage_controller.go +++ b/controllers/metal3.io/dataimage_controller.go @@ -86,9 +86,9 @@ func (info *rdiInfo) publishEvent(reason, message string) { info.events = append(info.events, dataImageEvent) } -//+kubebuilder:rbac:groups=metal3.io,resources=dataimages,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=metal3.io,resources=dataimages/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=metal3.io,resources=dataimages/finalizers,verbs=update +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=dataimages,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=dataimages/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=dataimages/finalizers,verbs=update // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. diff --git a/controllers/metal3.io/hostfirmwarecomponents_controller.go b/controllers/metal3.io/hostfirmwarecomponents_controller.go index f045e705bd..df072b9335 100644 --- a/controllers/metal3.io/hostfirmwarecomponents_controller.go +++ b/controllers/metal3.io/hostfirmwarecomponents_controller.go @@ -88,9 +88,9 @@ func (info *rhfcInfo) publishEvent(reason, message string) { info.events = append(info.events, hfcEvent) } -//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents/finalizers,verbs=update +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=hostfirmwarecomponents,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=hostfirmwarecomponents/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=hostfirmwarecomponents/finalizers,verbs=update // Reconcile handles changes to HostFirmwareComponents resources. func (r *HostFirmwareComponentsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { diff --git a/controllers/metal3.io/hostfirmwaresettings_controller.go b/controllers/metal3.io/hostfirmwaresettings_controller.go index 41ef319f8d..ab31858168 100644 --- a/controllers/metal3.io/hostfirmwaresettings_controller.go +++ b/controllers/metal3.io/hostfirmwaresettings_controller.go @@ -100,10 +100,10 @@ func (info *rInfo) publishEvent(reason, message string) { info.events = append(info.events, hfsEvent) } -//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwaresettings,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwaresettings/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=metal3.io,resources=firmwareschemas,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=metal3.io,resources=firmwareschemas/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=hostfirmwaresettings,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=hostfirmwaresettings/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=firmwareschemas,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=metal3.io,namespace="",resources=firmwareschemas/status,verbs=get;update;patch // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. diff --git a/controllers/metal3.io/preprovisioningimage_controller.go b/controllers/metal3.io/preprovisioningimage_controller.go index 1dc3cfd055..db00fe2be3 100644 --- a/controllers/metal3.io/preprovisioningimage_controller.go +++ b/controllers/metal3.io/preprovisioningimage_controller.go @@ -61,9 +61,9 @@ const ( reasonImageBuildInvalid imageConditionReason = "ImageBuildInvalid" ) -// +kubebuilder:rbac:groups=metal3.io,resources=preprovisioningimages,verbs=get;list;watch;update;patch -// +kubebuilder:rbac:groups=metal3.io,resources=preprovisioningimages/status,verbs=get;update;patch -// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;update +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=preprovisioningimages,verbs=get;list;watch;update;patch +// +kubebuilder:rbac:groups=metal3.io,namespace="",resources=preprovisioningimages/status,verbs=get;update;patch +// +kubebuilder:rbac:groups="",namespace="",resources=secrets,verbs=get;list;watch;update func (r *PreprovisioningImageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := r.Log.WithValues("preprovisioningimage", req.NamespacedName) diff --git a/docs/single-ns-deploy.md b/docs/single-ns-deploy.md new file mode 100644 index 0000000000..c4656f0f08 --- /dev/null +++ b/docs/single-ns-deploy.md @@ -0,0 +1,81 @@ +# How to restrict the Baremetal Operator scope + +The guide is based on the instructions in the +[operator framework documentation][operator-scope]. + +[operator-scope]: https://sdk.operatorframework.io/docs/building-operators/golang/operator-scope/ + + +## To generate manifests for namespace scoped BMO + +To generate namespace-scoped manifests, run the `manifests-generate-namespaced` +make target. This command will create manifests specifically configured for the +`single-ns-bmh` namespace. It uses the `config/overlays/namespaced` kustomize +overlay to replace cluster-scoped resources with their namespace-scoped counterparts. + + +## Watching resources in specific Namespaces + +When setting up the manager, you can use the environment variable +`WATCH_NAMESPACE` to restrict the operator to a specific namespace. If +`WATCH_NAMESPACE` is unset or set to an empty string, the operator will +monitor all namespaces. To limit it to a specific namespace, set +`WATCH_NAMESPACE` to that namespace. + +For example, to configure the operator to watch the same namespace where +it is deployed, update the `config/base/manager.yaml` file. Add the +following configuration under `spec.template.spec.containers.env`: + +```yaml +- name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace +``` + +## Restricting Roles and permissions + +When BMO is restricted to a single namespace, the RBAC permissions need +to be updated accordingly. Instead of using `ClusterRole`, you will use +`Role`. + +The `Role` is defined in the file `config/base/rbac/role_ns.yaml`. This +file is auto-generated based on Kubebuilder RBAC markers, specifically those +in `_controller.go`. The default namespace marking is set to `""`, +which results in a `ClusterRole`. To restrict it to a specific namespace, +update this value accordingly. + +After updating the markers, generate the new manifests by running: + +```bash + make manifests +``` + +Ensure that `config/base/rbac/role_ns.yaml` has been updated to a `Role`. + +Due to limitations in Kubebuilder generation, the `RoleBinding` will not +be updated automatically.You can manually update `config/base/rbac/role_binding.yaml` +to achieve the desired outcome. Below is an example of how to modify the +`role_binding.yaml` file: + +```yaml: +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: manager-rolebinding + namespace: your-namespace +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: manager-role + namespace: your-namespace +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system +``` + +Replace `your-namespace` and other fields as necessary to match your +specific configuration. + +After this you can run `make manifests-kustomize` to get correct RoleBinding generated