diff --git a/docs/rbac.md b/docs/rbac.md new file mode 100644 index 000000000..71b937cfe --- /dev/null +++ b/docs/rbac.md @@ -0,0 +1,41 @@ +# RBAC Management + +## Structure + +### capi-operator and capi-installer + +The `capi-operator` and `capi-installer` ServiceAccounts (in `openshift-cluster-api-operator`) have separate, scoped permissions: + +| Manifest | Kind | Scope | SA | Purpose | +|----------|------|-------|----|---------| +| `0000_30_cluster-api-operator_03_clusterrole.yaml` | ClusterRole `openshift-capi-operator` | cluster-wide | `capi-operator` | config.openshift.io resources, ClusterOperator management, ClusterAPI/ConfigMap/Deployment read | +| `0000_30_cluster-api-operator_03_clusterrole.yaml` | Role `capi-operator` | `openshift-cluster-api-operator` | `capi-operator` | Leader election leases, Deployment write (capi-installer), pod self-read, events | +| `0000_30_cluster-api-operator_03_capi-installer-clusterrole.yaml` | ClusterRole `openshift-capi-installer` | cluster-wide | `capi-installer` | CRDs, admission resources, cluster RBAC, config.openshift.io, ClusterAPI/ClusterOperator status, tracking cache informers | +| `0000_30_cluster-api-operator_03_capi-installer-clusterrole.yaml` | Role `capi-installer` | `openshift-cluster-api-operator` | `capi-installer` | Leader election leases, pod self-read, ConfigMap read, events | +| `0000_30_cluster-api-operator_03_capi-installer-clusterrole.yaml` | Role `capi-installer` | `openshift-cluster-api` | `capi-installer` | boxcutter-managed resources (ServiceAccounts, Services, Deployments, Roles, RoleBindings), VAP paramRef list | +| `0000_30_cluster-api-operator_03_capi-installer-clusterrole.yaml` | Role `capi-installer` | `openshift-machine-api` | `capi-installer` | VAP paramRef list (machines, machinesets) | + +Both SAs also bind to ClusterRole `system:openshift:openshift-cluster-api:read-tls-configuration` for APIServer TLS profile reading. + +### capi-controllers + +The `capi-controllers` ServiceAccount (used by both the `capi-controllers` and `machine-api-migration` containers) has permissions split across scopes: + +| Manifest | Kind | Scope | Purpose | +|----------|------|-------|---------| +| `03_rbac_roles.yaml` | ClusterRole `openshift-capi-controllers` | cluster-wide | Cluster-scoped resources only: infrastructures, clusteroperators, featuregates, clusterversions, nodes, CRDs | +| `03_rbac_roles.yaml` | Role `capi-controllers` | `openshift-cluster-api` | CAPI core + infra provider resources, secrets, events, leases | +| `03_rbac_roles.yaml` | Role `capi-controllers` | `openshift-machine-api` | MAPI machines, machinesets, controlplanemachinesets, secrets, events | +| `03_rbac_roles.yaml` | Role `capi-controllers-kube-system` | `kube-system` | Secrets (vSphere credentials) | +| `03_rbac_roles.yaml` | Role `cluster-capi-operator-pull-secret` | `openshift-config` | Pull-secret read | + +## Principles + +- Each permission lives in the narrowest scope where it's used +- Cluster-scoped Kubernetes objects (CRDs, ClusterRoles, ClusterOperators) go in ClusterRoles +- Namespaced resources go into Roles in the specific namespace where they're accessed +- Read-only informer permissions may use ClusterRoles when the cache watches multiple namespaces + +## Updating RBAC + +Use the `/rbac-review` skill to audit and regenerate RBAC permissions. It requires a live cluster and uses audit2rbac + static code analysis to derive least-privilege rules. diff --git a/manifests/0000_30_cluster-api-operator_03_capi-installer-clusterrole.yaml b/manifests/0000_30_cluster-api-operator_03_capi-installer-clusterrole.yaml new file mode 100644 index 000000000..005b6942d --- /dev/null +++ b/manifests/0000_30_cluster-api-operator_03_capi-installer-clusterrole.yaml @@ -0,0 +1,271 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" + name: openshift-capi-installer +rules: +# VAP binding creation requires get+list on all resources when the referenced +# policy doesn't exist yet. Also covers boxcutter tracking cache reads. +- apiGroups: + - '*' + resources: + - '*' + verbs: + - get + - list +- apiGroups: + - config.openshift.io + resources: + - infrastructures + verbs: + - get + - list + - watch +- apiGroups: + - config.openshift.io + resources: + - clusteroperators + verbs: + - get + - list + - watch +- apiGroups: + - config.openshift.io + resources: + - clusteroperators/status + verbs: + - get + - update + - patch +- apiGroups: + - operator.openshift.io + resources: + - clusterapis + verbs: + - get + - list + - watch +- apiGroups: + - operator.openshift.io + resources: + - clusterapis/status + verbs: + - get + - update + - patch +# boxcutter: manages CRDs from provider manifests +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +# boxcutter: manages admission resources from provider manifests +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + - validatingadmissionpolicies + - validatingadmissionpolicybindings + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +# boxcutter: manages cluster-scoped RBAC from provider manifests. +# escalate + bind: installer creates Roles granting permissions it doesn't hold. +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - escalate + - bind +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +# boxcutter: tracking cache watches namespace-scoped types cluster-wide +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + - rolebindings + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + - services + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" + name: capi-installer + namespace: openshift-cluster-api-operator +rules: +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" + name: capi-installer + namespace: openshift-cluster-api +rules: +# boxcutter: applies namespace-scoped provider resources +- apiGroups: + - "" + resources: + - serviceaccounts + - services + verbs: + - create + - get + - update + - patch + - delete +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - get + - update + - patch + - delete +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + verbs: + - create + - get + - update + - patch + - delete + - escalate + - bind +- apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + verbs: + - create + - get + - update + - patch + - delete +# VAP paramRef authorization: API server requires list on paramKind types +- apiGroups: + - cluster.x-k8s.io + resources: + - machines + - machinesets + verbs: + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" + name: capi-installer + namespace: openshift-machine-api +rules: +# VAP paramRef authorization: API server requires list on paramKind types +- apiGroups: + - machine.openshift.io + resources: + - machines + - machinesets + verbs: + - list diff --git a/manifests/0000_30_cluster-api-operator_03_clusterrole.yaml b/manifests/0000_30_cluster-api-operator_03_clusterrole.yaml index 2f489e303..f2fcc89f2 100644 --- a/manifests/0000_30_cluster-api-operator_03_clusterrole.yaml +++ b/manifests/0000_30_cluster-api-operator_03_clusterrole.yaml @@ -9,10 +9,138 @@ metadata: release.openshift.io/feature-gate: "ClusterAPIMachineManagement" name: openshift-capi-operator rules: -# Being an installer, the required RBAC is necessarily a lot - apiGroups: - - '*' + - config.openshift.io resources: - - '*' + - infrastructures verbs: - - '*' + - get +- apiGroups: + - config.openshift.io + resources: + - clusteroperators + verbs: + - get + - list + - watch + - create +- apiGroups: + - config.openshift.io + resources: + - clusteroperators + resourceNames: + - cluster-api + verbs: + - update + - patch +- apiGroups: + - config.openshift.io + resources: + - clusteroperators/status + resourceNames: + - cluster-api + verbs: + - update + - patch +- apiGroups: + - config.openshift.io + resources: + - clusterversions + - featuregates + verbs: + - get + - list + - watch +- apiGroups: + - operator.openshift.io + resources: + - clusterapis + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" + name: capi-operator + namespace: openshift-cluster-api-operator +rules: +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch + - create + - patch + - update + - delete +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" + name: capi-operator + namespace: openshift-cluster-api +rules: +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch diff --git a/manifests/0000_30_cluster-api-operator_04_capi-installer-clusterrolebinding.yaml b/manifests/0000_30_cluster-api-operator_04_capi-installer-clusterrolebinding.yaml index 64eb10129..8ba452527 100644 --- a/manifests/0000_30_cluster-api-operator_04_capi-installer-clusterrolebinding.yaml +++ b/manifests/0000_30_cluster-api-operator_04_capi-installer-clusterrolebinding.yaml @@ -11,8 +11,83 @@ metadata: roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: openshift-capi-operator + name: openshift-capi-installer +subjects: +- kind: ServiceAccount + name: capi-installer + namespace: openshift-cluster-api-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: capi-installer + namespace: openshift-cluster-api-operator + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: capi-installer +subjects: +- kind: ServiceAccount + name: capi-installer + namespace: openshift-cluster-api-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: capi-installer + namespace: openshift-cluster-api + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: capi-installer +subjects: +- kind: ServiceAccount + name: capi-installer + namespace: openshift-cluster-api-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: capi-installer + namespace: openshift-machine-api + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: capi-installer subjects: - kind: ServiceAccount name: capi-installer namespace: openshift-cluster-api-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: system:openshift:capi-installer-read-tls-configuration + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" +roleRef: + kind: ClusterRole + name: system:openshift:openshift-cluster-api:read-tls-configuration + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + namespace: openshift-cluster-api-operator + name: capi-installer diff --git a/manifests/0000_30_cluster-api-operator_04_clusterrolebinding.yaml b/manifests/0000_30_cluster-api-operator_04_clusterrolebinding.yaml index d372cdaae..ab409dafd 100644 --- a/manifests/0000_30_cluster-api-operator_04_clusterrolebinding.yaml +++ b/manifests/0000_30_cluster-api-operator_04_clusterrolebinding.yaml @@ -18,6 +18,44 @@ subjects: name: capi-operator --- apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: capi-operator + namespace: openshift-cluster-api-operator + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" +roleRef: + kind: Role + name: capi-operator + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + namespace: openshift-cluster-api-operator + name: capi-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: capi-operator + namespace: openshift-cluster-api + annotations: + exclude.release.openshift.io/internal-openshift-hosted: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/feature-gate: "ClusterAPIMachineManagement" +roleRef: + kind: Role + name: capi-operator + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + namespace: openshift-cluster-api-operator + name: capi-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: system:openshift:capi-operator-read-tls-configuration