Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a7cd178
STOR-1459: Add fine-grained RBAC roles instead of cluster-admin role …
aculnaig Sep 7, 2026
38db57b
STOR-1459: Refine fine-grained RBAC roles instead of cluster-admin fo…
aculnaig Sep 8, 2026
04bb9c8
STOR-1459: Add StorageClass management permissions to cluster-storage…
aculnaig Sep 8, 2026
e93078e
STOR-1459: Replace cluster-admin with fine-grained RBAC for cluster-s…
aculnaig Sep 8, 2026
1e15319
STOR-1459: Correct securityContext comments to accurately describe no…
aculnaig Sep 8, 2026
3fd8ddc
STOR-1459: Update AGENTS.md to reflect consolidated RBAC implementation
aculnaig Sep 8, 2026
a2ae953
STOR-1459: Fix ClusterRoleBinding roleRef immutability in upgrade path
aculnaig Sep 8, 2026
7c810cd
STOR-1459: Fix ClusterRoleBinding roleRef immutability in upgrade path
aculnaig Sep 8, 2026
227f76d
STOR-1459: Use separate deletion manifest for HyperShift RBAC migration
aculnaig Sep 9, 2026
7ae1ee8
STOR-1459: Update AGENTS.md to document immutable roleRef migration s…
aculnaig Sep 9, 2026
78fc333
STOR-1459: Refactor RBAC to fine-grained Role-based architecture
aculnaig Sep 9, 2026
77d0720
STOR-1459: Update AGENTS.md with newer RBAC fine-grained architecture…
aculnaig Sep 9, 2026
b4dc870
STOR-1459: Fix RBAC permission gaps discovered in operational testing
aculnaig Sep 9, 2026
e832613
STOR-1459: Fix additional RBAC permission gaps for secrets access
aculnaig Sep 9, 2026
da44017
STOR-1459: Fix all RBAC permission gaps discovered in operational tes…
aculnaig Sep 9, 2026
1e3281c
STOR-1459: Split StorageClasses and CSI driver management rules
aculnaig Sep 9, 2026
2a30531
STOR-1459: Remove clustercsidrivers/status permissions from CSO Clust…
aculnaig Sep 9, 2026
2d28547
STOR-1459: Delete servicemonitors/prometheusrules rules from CSO clus…
aculnaig Sep 10, 2026
24f068f
STOR-1459: Drop get rule on specific secrets in CSO's own namespace
aculnaig Sep 10, 2026
d15d186
STOR-1459: Remove deployments/scale and deployments/status from CSO n…
aculnaig Sep 10, 2026
849db2c
STOR-1459: Remove deployments/status from CSI drivers namespace Role
aculnaig Sep 10, 2026
1a9e2d7
STOR-1459: Document runlevel ordering for openshift-config namespace …
aculnaig Sep 10, 2026
d07f4c7
STOR-1459: Drop unused secret/RBAC reads from config namespace Roles
aculnaig Sep 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,38 @@ A PR review **must fail** if any of the following are true:
### RBAC Changes

- RBAC files under `assets/csidriveroperators/<driver>/base/` govern the CSI driver *operator*, not the driver itself. Verify the subject, namespace, and rules match the minimum needed.
- CSO itself currently runs with `cluster-admin` (`manifests/08_operator_rbac.yaml`) — this is a known open TODO, not a new concern introduced by a PR.
- **CSO Operator RBAC** — CSO runs with fine-grained Role-based RBAC instead of `cluster-admin`:
- **Cluster-scoped permissions** — `manifests/08_0001_cluster_storage_operator_storage_role.yaml` contains a ClusterRole with 7 rules for cluster-wide resources:
- Cluster configuration observation (Infrastructure, Proxies, ClusterVersions, FeatureGates, ClusterOperators, APIServers)
- StorageClass and CSI driver management (storageclasses, csidrivers, volumeattributesclasses)
- ClusterRoleBindings for CSI sidecar RBAC (provisioner, attacher, resizer, snapshotter)
- Operator custom resources (Storage, ClusterCSIDriver CRs and status subresources)
- CustomResourceDefinitions management (for VolumePopulator CRD)
- ClusterOperator status updates (for health condition reporting)
- Monitoring resources (cluster-scoped ServiceMonitors and PrometheusRules)
- **Namespace-scoped permissions** — 4 namespace-specific Roles for fine-grained isolation:
- `manifests/08_0002_cluster_storage_operator_operator_namespace_role.yaml` in `openshift-cluster-storage-operator`: leases (leader election), events, serviceaccounts, services, configmaps, deployments, replicasets, roles/rolebindings, vSphere secrets (resourceNames-restricted), monitoring
- `manifests/08_0003_cluster_storage_operator_csi_drivers_namespace_role.yaml` in `openshift-cluster-csi-drivers`: deployments, configmaps, RBAC (roles/rolebindings), serviceaccounts, services, replicasets, events, monitoring
- `manifests/08_0004_cluster_storage_operator_config_namespace_role.yaml` in `openshift-config`: configmaps (read-only)
- `manifests/08_0005_cluster_storage_operator_config_managed_namespace_role.yaml` in `openshift-config-managed`: configmaps, RBAC (read-only)
- **RoleBindings** — `manifests/08_0010_cluster_storage_operator_rolebindings.yaml` contains 4 RoleBindings binding the cluster-storage-operator ServiceAccount to the above Roles
- **Key improvements:**
- **Least privilege by scope:** Namespace operations use namespace-scoped Roles, not cluster-wide ClusterRole
- **Secrets restricted:** Only 2 specific vSphere secrets readable (vsphere-cloud-credentials, vsphere-problem-detector-serving-cert) via resourceNames restriction
- **Removed unnecessary permissions:** Pods removed (informers cache without RBAC), Events scoped to namespaces (not cluster-wide)
- **Clear justification:** Each permission rule includes a comment explaining why it's necessary
- **Standalone path** (`manifests/08_operator_rbac.yaml`):
- Contains a deletion manifest (with `release.openshift.io/delete: "true"` annotation) pointing to the old `cluster-admin` binding
- Followed by a replacement ClusterRoleBinding pointing to `cluster-storage-operator-storage-role`
- CVO processes deletion first, then applies the replacement, avoiding immutable `roleRef` conflicts during upgrades
- **HyperShift path** (`manifests/08_operator_rbac-hypershift.yaml` + `manifests/08_0002_operator_rbac-hypershift-delete.yaml`):
- `08_operator_rbac-hypershift.yaml` is autogenerated via `make update` and must not be hand-edited
- `08_0002_operator_rbac-hypershift-delete.yaml` is a hand-maintained deletion manifest with `release.openshift.io/delete: "true"` annotation
- CVO processes both: deletion first from the delete manifest, then applies the autogenerated binding
- `manifests/08_operator_scc.yaml` — ClusterRoleBinding granting the `nonroot-v2` SecurityContextConstraint (required for pod scheduling).
- Permissions were discovered incrementally by deploying with empty RBAC and capturing "forbidden" errors from operator logs, ensuring only necessary permissions are granted.
- **Immutable field migration strategy:** ClusterRoleBinding `roleRef` is immutable after creation. Changing it requires deletion and replacement in the same CVO update cycle using `release.openshift.io/delete: "true"` annotation on the old binding.
- When reviewing RBAC changes, verify verbs are minimal and necessary — do not use `["*"]` for new permissions. Use resourceNames for secrets access when possible.
- Sidecar RBAC for provisioner / attacher / resizer / snapshotter lives in `manifests/09_sidecar-*.yaml` and is shared across all drivers. Changes there affect every driver simultaneously.

### Adding a New CSI Driver
Expand Down
55 changes: 55 additions & 0 deletions manifests/08_0001_cluster_storage_operator_storage_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-storage-role
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
rules:
# Cluster infrastructure and configuration observation (cluster-scoped singletons)
# Required for determining platform capabilities, proxy settings, feature gates, and cluster health
- apiGroups: ["config.openshift.io"]
resources: ["infrastructures", "proxies", "clusterversions", "featuregates", "clusteroperators", "apiservers"]
verbs: ["get", "list", "watch"]

# Default StorageClass management — CSO creates/reconciles the cluster default SC
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
Comment thread
jsafrane marked this conversation as resolved.

# CSI driver / VAC observation only — CSO watches these to make decisions and
# emit metrics; the objects themselves are managed by the CSI driver operators.
- apiGroups: ["storage.k8s.io"]
resources: ["csidrivers", "volumeattributesclasses"]
verbs: ["get", "list", "watch"]

# ClusterRoleBindings for CSI driver sidecar RBAC (cluster-scoped)
# Required to grant sidecar containers (provisioner, attacher, resizer, snapshotter) cluster-level permissions
# Note: Roles and RoleBindings in namespaces are handled by namespace-scoped Roles
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterrolebindings"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# Storage operator custom resources (cluster-scoped)
# Required for managing the Storage CR and ClusterCSIDriver CRs for each platform
- apiGroups: ["operator.openshift.io"]
resources: ["storages", "clustercsidrivers"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["operator.openshift.io"]
resources: ["storages/status"]
verbs: ["get", "patch", "update"]

# Custom Resource Definitions management (cluster-scoped)
# Required for VolumeDataSourceValidator to deploy the VolumePopulator CRD
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# ClusterOperator status updates (cluster-scoped)
# Required by StatusSyncer controller to report operator health conditions
- apiGroups: ["config.openshift.io"]
resources: ["clusteroperators/status"]
verbs: ["patch", "update"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-role
namespace: openshift-cluster-storage-operator
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
rules:
# Leader election via leases in operator's own namespace
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# Event recording for operator status and lifecycle
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]

# ServiceAccount management for vSphere problem detector
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# Service management for metrics endpoint
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# CSO informs on all Secrets in its own namespace (informer requires list/watch,
# which already exposes full secret contents); vsphere-problem-detector reads
# vsphere-cloud-credentials and vsphere-problem-detector-serving-cert by name.
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]

# Monitoring resources for operator metrics
- apiGroups: ["monitoring.coreos.com"]
resources: ["servicemonitors", "prometheusrules"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# Deployment management for VolumeDataSourceValidator (library-go DeploymentController:
# Get/Create/Update/Delete on the Deployment; status is read via this rule, scale is unused)
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
Comment thread
jsafrane marked this conversation as resolved.

# ConfigMap management for operator configuration
# Required by ConfigObserver and other controllers that manage operator configuration data
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# RBAC management in operator namespace
# Required to create and manage Roles and RoleBindings for operator components and sidecars
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles", "rolebindings"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# ReplicaSet observation for deployment status tracking
# Required to watch ReplicaSets created by Deployments for accurate status reporting
- apiGroups: ["apps"]
resources: ["replicasets"]
verbs: ["get", "list", "watch"]
16 changes: 16 additions & 0 deletions manifests/08_0002_operator_rbac-hypershift-delete.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Deletion manifest for old cluster-admin binding in HyperShift — marked for deletion to avoid immutable roleRef conflict
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-storage-operator-role
annotations:
release.openshift.io/delete: "true"
include.release.openshift.io/hypershift: "true"
subjects:
- kind: ServiceAccount
name: cluster-storage-operator
namespace: openshift-cluster-storage-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-csi-drivers-role
namespace: openshift-cluster-csi-drivers
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
rules:
# ReplicaSet observation for owner reference resolution in deployment controller
- apiGroups: ["apps"]
resources: ["replicasets"]
verbs: ["get", "list", "watch"]

# Event recording for CSI driver operator lifecycle events
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]

# Deployment management for CSI driver operators (DeploymentController)
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# ConfigMap management for driver operator configuration
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# RBAC management for CSI driver operators (roles and rolebindings)
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles", "rolebindings"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# ServiceAccount management for CSI driver operators
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# Service management for CSI driver metrics and communication
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# Monitoring resources for CSI driver metrics
- apiGroups: ["monitoring.coreos.com"]
resources: ["servicemonitors", "prometheusrules"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

# Secrets for CSI driver operators (e.g., cloud provider credentials)
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-config-role
namespace: openshift-config
Comment thread
jsafrane marked this conversation as resolved.
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
rules:
# ConfigMap observation for cluster configuration (e.g., cloud provider config)
# Read-only access to configuration data
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-config-managed-role
namespace: openshift-config-managed
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
rules:
# ConfigMap observation for managed cluster configuration (CA bundle sync
# via resourcesynccontroller). Read-only.
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
84 changes: 84 additions & 0 deletions manifests/08_0010_cluster_storage_operator_rolebindings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
# RoleBinding for openshift-cluster-storage-operator namespace
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-role
namespace: openshift-cluster-storage-operator
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
subjects:
- kind: ServiceAccount
name: cluster-storage-operator
namespace: openshift-cluster-storage-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cluster-storage-operator-role
---
# RoleBinding for openshift-cluster-csi-drivers namespace
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-csi-drivers-role
namespace: openshift-cluster-csi-drivers
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
subjects:
- kind: ServiceAccount
name: cluster-storage-operator
namespace: openshift-cluster-storage-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cluster-storage-operator-csi-drivers-role
---
# RoleBinding for openshift-config namespace
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-config-role
namespace: openshift-config
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
subjects:
- kind: ServiceAccount
name: cluster-storage-operator
namespace: openshift-cluster-storage-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cluster-storage-operator-config-role
---
# RoleBinding for openshift-config-managed namespace
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-storage-operator-config-managed-role
namespace: openshift-config-managed
annotations:
include.release.openshift.io/hypershift: "true"
include.release.openshift.io/ibm-cloud-managed: "true"
include.release.openshift.io/self-managed-high-availability: "true"
include.release.openshift.io/single-node-developer: "true"
capability.openshift.io/name: Storage
subjects:
- kind: ServiceAccount
name: cluster-storage-operator
namespace: openshift-cluster-storage-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cluster-storage-operator-config-managed-role
4 changes: 1 addition & 3 deletions manifests/08_operator_rbac-hypershift.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/cluster-service: "true"
name: cluster-storage-operator-role
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
Comment thread
coderabbitai[bot] marked this conversation as resolved.
subjects:
Expand Down
Loading