Skip to content

Commit

Permalink
draft: add namespace scoped operator mode
Browse files Browse the repository at this point in the history
This adds automation and docs for restricting the
operator scope from cluster wide to namespace restricted.

Signed-off-by: NymanRobin <[email protected]>
  • Loading branch information
NymanRobin committed Aug 22, 2024
1 parent efae71e commit 11dbdad
Show file tree
Hide file tree
Showing 35 changed files with 748 additions and 84 deletions.
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,14 @@ manifests-generate: $(CONTROLLER_GEN)
manifests-kustomize: $(KUSTOMIZE)
$< build config/default > config/render/capm3.yaml

.PHONY: manifests-namespaced
manifests-namespaced: manifests-generate $(KUSTOMIZE)
$(KUSTOMIZE) build config/overlays/namespaced --enable-alpha-plugins > config/render/capm3.yaml

.PHONY: manifests-namespaced-e2e
manifests-namespaced: manifests-generate $(KUSTOMIZE)
$(KUSTOMIZE) build config/overlays/namespaced-e2e --enable-alpha-plugins > 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})
Expand Down
2 changes: 1 addition & 1 deletion config/namespace/namespace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ kind: Namespace
metadata:
labels:
control-plane: controller-manager
name: baremetal-operator-system
name: baremetal-operator-system
47 changes: 47 additions & 0 deletions config/overlays/namespaced-e2e/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../e2e

# 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
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
target:
group: rbac.authorization.k8s.io
kind: ClusterRole
name: baremetal-operator-manager-role

transformers:
- roles-ns-annotator.yaml
13 changes: 13 additions & 0 deletions config/overlays/namespaced-e2e/namespaced-manager-patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- env:
- name: WATCH_NAMESPACE
value: basic-ops-test,external-inspection-test,inspection-test,live-iso-ops-test,provisioning-ops-test,re-inspection-test
name: manager
14 changes: 14 additions & 0 deletions config/overlays/namespaced-e2e/roles-ns-annotator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: transformers.example.co/v1
kind: ValueAnnotator
metadata:
annotations:
config.kubernetes.io/function: "container:\n image: bmo/roleannotator:1.0.0\
\ \n"
name: notImportantHere
values:
- basic-ops-test
- external-inspection-test
- inspection-test
- live-iso-ops-test
- provisioning-ops-test
- re-inspection-test
46 changes: 46 additions & 0 deletions config/overlays/namespaced/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base
# 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
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
target:
group: rbac.authorization.k8s.io
kind: ClusterRole
name: baremetal-operator-manager-role

transformers:
- roles-ns-annotator.yaml
13 changes: 13 additions & 0 deletions config/overlays/namespaced/namespaced-manager-patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- env:
- name: WATCH_NAMESPACE
value: metal3
name: manager
9 changes: 9 additions & 0 deletions config/overlays/namespaced/roles-ns-annotator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: transformers.example.co/v1
kind: ValueAnnotator
metadata:
annotations:
config.kubernetes.io/function: "container:\n image: bmo/roleannotator:1.0.0 \
\ \n"
name: notImportantHere
values:
- metal3
15 changes: 12 additions & 3 deletions config/render/capm3.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
apiVersion: v1
kind: Namespace
metadata:
name: metal3
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
Expand Down Expand Up @@ -2167,9 +2172,10 @@ rules:
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
kind: Role
metadata:
name: baremetal-operator-manager-role
namespace: metal3
rules:
- apiGroups:
- ""
Expand Down Expand Up @@ -2412,12 +2418,13 @@ subjects:
namespace: baremetal-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
kind: RoleBinding
metadata:
name: baremetal-operator-manager-rolebinding
namespace: metal3
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
kind: Role
name: baremetal-operator-manager-role
subjects:
- kind: ServiceAccount
Expand Down Expand Up @@ -2525,6 +2532,8 @@ spec:
command:
- /baremetal-operator
env:
- name: WATCH_NAMESPACE
value: metal3
- name: POD_NAME
valueFrom:
fieldRef:
Expand Down
28 changes: 14 additions & 14 deletions controllers/metal3.io/baremetalhost_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions controllers/metal3.io/bmceventsubscription_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions controllers/metal3.io/dataimage_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions controllers/metal3.io/hostfirmwarecomponents_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions controllers/metal3.io/hostfirmwaresettings_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions controllers/metal3.io/preprovisioningimage_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
79 changes: 79 additions & 0 deletions docs/namespace-scoped-operator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# 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-namespaced`
make target. This command will create manifests specifically configured for the
namespaces defined in. 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 `<some>_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
Loading

0 comments on commit 11dbdad

Please sign in to comment.