From 863699c800640d5600eaca810f3fe0632a8bf553 Mon Sep 17 00:00:00 2001 From: Pratik Bandarkar Date: Wed, 29 Oct 2025 11:14:11 +0000 Subject: [PATCH 1/2] feat: Add default rbac for OIDC integration --- .../keycloak/20-keycloak/kustomization.yaml | 1 - .../rbac/k8s-ops-cluster-role.yaml | 64 ----- .../services/keycloak/30-oidc-rbac/README.md | 74 ++++++ .../keycloak/30-oidc-rbac/default-rbac.yaml | 220 ++++++++++++++++++ .../rbac => 30-oidc-rbac}/kustomization.yaml | 2 +- 5 files changed, 295 insertions(+), 66 deletions(-) delete mode 100644 applications/base/services/keycloak/20-keycloak/rbac/k8s-ops-cluster-role.yaml create mode 100644 applications/base/services/keycloak/30-oidc-rbac/README.md create mode 100644 applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml rename applications/base/services/keycloak/{20-keycloak/rbac => 30-oidc-rbac}/kustomization.yaml (71%) diff --git a/applications/base/services/keycloak/20-keycloak/kustomization.yaml b/applications/base/services/keycloak/20-keycloak/kustomization.yaml index 67b316c..1ab378b 100644 --- a/applications/base/services/keycloak/20-keycloak/kustomization.yaml +++ b/applications/base/services/keycloak/20-keycloak/kustomization.yaml @@ -4,4 +4,3 @@ kind: Kustomization namespace: keycloak resources: - "keycloak-cr.yaml" - - "rbac/" diff --git a/applications/base/services/keycloak/20-keycloak/rbac/k8s-ops-cluster-role.yaml b/applications/base/services/keycloak/20-keycloak/rbac/k8s-ops-cluster-role.yaml deleted file mode 100644 index 332e4d4..0000000 --- a/applications/base/services/keycloak/20-keycloak/rbac/k8s-ops-cluster-role.yaml +++ /dev/null @@ -1,64 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: k8s-ops -rules: - - apiGroups: [""] - resources: - - pods - - pods/log - - services - - endpoints - - configmaps - - serviceaccounts - - resourcequotas - - limitranges - - persistentvolumeclaims - - replicationcontrollers - - events - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: - - nodes - - namespaces - - persistentvolumes - verbs: ["get", "list", "watch"] - - apiGroups: ["apps"] - resources: - - deployments - - daemonsets - - statefulsets - - replicasets - verbs: ["get", "list", "watch"] - - apiGroups: ["batch"] - resources: - - jobs - - cronjobs - verbs: ["get", "list", "watch"] - - apiGroups: ["networking.k8s.io"] - resources: - - ingresses - - networkpolicies - - ingressclasses - verbs: ["get", "list", "watch"] - - apiGroups: ["discovery.k8s.io"] - resources: - - endpointslices - verbs: ["get", "list", "watch"] - - apiGroups: ["storage.k8s.io"] - resources: - - storageclasses - - csidrivers - - csinodes - - csistoragecapacities - verbs: ["get", "list", "watch"] - - apiGroups: ["coordination.k8s.io"] - resources: - - leases - verbs: ["get", "list", "watch"] - - apiGroups: ["events.k8s.io"] - resources: - - events - verbs: ["get", "list", "watch"] - - nonResourceURLs: ["/healthz", "/readyz", "/livez", "/version"] - verbs: ["get"] diff --git a/applications/base/services/keycloak/30-oidc-rbac/README.md b/applications/base/services/keycloak/30-oidc-rbac/README.md new file mode 100644 index 0000000..dfe462e --- /dev/null +++ b/applications/base/services/keycloak/30-oidc-rbac/README.md @@ -0,0 +1,74 @@ +# Default RBAC Configuration (OIDC + rbac-manager) + +This configuration provides a **structured and scalable role-based access control (RBAC)** setup for Kubernetes clusters integrated with **OIDC providers such as Keycloak**. +It defines clear access boundaries for different teams (admins, observability, platform, security, namespace admins, etc.) and leverages **rbac-manager** for automated creation and reconciliation of RBAC bindings. + +By using **namespace labels** and centralized **OIDC groups**, the configuration enables **multi-team, least-privilege access management** that is both **GitOps-friendly and self-maintaining**. + +--- + +## Prerequisites + +1. **[rbac-manager](https://github.com/FairwindsOps/rbac-manager)** must be installed in the cluster. + - This controller manages `RBACDefinition` CRDs and automatically creates RoleBindings and ClusterRoleBindings defined in this configuration. + +2. **OIDC integration** must be enabled on the Kubernetes API server. + - The OIDC provider (e.g., Keycloak) should expose user groups (such as `oidc:cluster-admins`, `oidc:observability`, etc.) in the `groups` claim of the OIDC token. + +--- + +## What this configuration enables + +| Group | Description | +|--------|--------------| +| **oidc:cluster-admins** | Full cluster-admin access to manage all resources. | +| **oidc:read-only** | Cluster-wide read-only access using the built-in `view` role. | +| **oidc:namespace-admins** | Admin rights only in namespaces labeled `rbac.opencenter.io/admin="true"`. | +| **oidc:security-team** | Cluster-wide read access + admin rights in security-labeled namespaces. | +| **oidc:observability** | Read access to workloads, nodes, logs, metrics, and monitoring CRDs (no Secrets). | +| **oidc:platform-team** | Permission to manage only `RBACDefinition` CRDs used by rbac-manager. | +| **oidc:k8s-ops** | Broad, read-only cluster visibility for operations teams. | + +--- + +## Namespace Label Usage + +Namespace labels provide **dynamic, label-driven authorization** so that access adjusts automatically without editing RBAC definitions whenever a new namespace is created. + +| Label | Purpose | +|--------|----------| +| `rbac.opencenter.io/admin="true"` | Grants admin privileges to members of `oidc:namespace-admins`. | +| `security.opencenter.io/managed="true"` | Grants admin privileges to `oidc:security-team` in those namespaces. | + +**NOTE:** When these labels are added or removed, **rbac-manager automatically updates** the corresponding RoleBindings - ensuring RBAC stays consistent with namespace state. + +--- + +## Deployment + +For both **in-cluster IDP (Keycloak)** and **external OIDC providers**, the default RBAC configuration can be deployed via your **GitOps tool (FluxCD)** from your overlay cluster repository. +Just make sure the required **OIDC groups** (`oidc:cluster-admins`, `oidc:observability`, `oidc:namespace-admins`, etc.) are created in the identity provider before users attempt to log in. + +--- + +## Structure Overview + +- **ClusterRole: `observability-extras`** - Extends `view` with nodes, logs, metrics, and monitoring CRDs. +- **ClusterRole: `rbacmanager-crd-admin`** - Manages rbac-manager `RBACDefinition` CRDs. +- **ClusterRole: `k8s-ops`** - Provides consolidated, read-only access for operations teams. +- **RBACDefinitions:** + - `oidc-cluster-admins` - Full cluster control + - `oidc-read-only` - Safe cluster-wide read access + - `oidc-observability` - Read + observability extras + - `oidc-namespace-admins` - Admin in namespaces labeled for delegation + - `oidc-security-team` - Cluster read + admin in security namespaces + - `oidc-platform-team` - Manage rbac-manager CRDs + - `oidc-k8s-ops` - Bind OIDC ops group to `k8s-ops` role + +--- + +## Summary + +This RBAC configuration provides a **secure, modular, and OIDC-driven access model** for Kubernetes clusters. +It separates team privileges, leverages **namespace labels for delegated control**, and uses **rbac-manager** to keep bindings synchronized automatically. +Whether you're running an **in-cluster Keycloak** or connecting to an **external IdP**, this setup ensures consistent, auditable, and GitOps-friendly RBAC management across all environments. diff --git a/applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml b/applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml new file mode 100644 index 0000000..50a9592 --- /dev/null +++ b/applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml @@ -0,0 +1,220 @@ +# oidc-cluster-admins - Full cluster-admin access for OIDC cluster admins +# oidc-read-only - Cluster-wide read-only access +# oidc-namespace-admins - Admin rights in namespaces labeled `rbac.opencenter.io/admin="true"` +# oidc-security-team - Security team: view cluster + admin in namespaces labeled `security.opencenter.io/managed="true"` +# oidc-observability - Observability group: view + extras for metrics/logs/monitoring +# oidc-platform-team - Platform team: manage only rbac-manager CRDs +# oidc-k8s-ops – bind ops group to k8s-ops +# k8s-ops - broad read-only (no Secrets, no write) for ops team +# observability-extras - Adds metrics/logs/nodes access to 'view' for observability +# rbacmanager-crd-admin - Manages rbac-manager RBACDefinition CRDs + +# ClusterRole: k8s-ops – broad read-only (no Secrets, no write) +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: k8s-ops +rules: + - apiGroups: [""] + resources: + - pods + - pods/log + - services + - endpoints + - configmaps + - serviceaccounts + - resourcequotas + - limitranges + - persistentvolumeclaims + - replicationcontrollers + - events + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["nodes", "namespaces", "persistentvolumes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["deployments", "daemonsets", "statefulsets", "replicasets"] + verbs: ["get", "list", "watch"] + - apiGroups: ["batch"] + resources: ["jobs", "cronjobs"] + verbs: ["get", "list", "watch"] + - apiGroups: ["networking.k8s.io"] + resources: ["ingresses", "networkpolicies", "ingressclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] + - apiGroups: ["storage.k8s.io"] + resources: + ["storageclasses", "csidrivers", "csinodes", "csistoragecapacities"] + verbs: ["get", "list", "watch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch"] + - apiGroups: ["events.k8s.io"] + resources: ["events"] + verbs: ["get", "list", "watch"] + - apiGroups: ["metrics.k8s.io"] + resources: ["nodes", "pods"] + verbs: ["get", "list", "watch"] + - nonResourceURLs: ["/healthz", "/readyz", "/livez", "/version"] + verbs: ["get"] +--- +# 'observability-extras' ClusterRole – adds metrics/logs/nodes access to 'view' +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: observability-extras +rules: + - apiGroups: [""] + resources: + [nodes, nodes/proxy, nodes/metrics, nodes/stats, services/proxy, pods/log] + verbs: [get, list, watch] + - nonResourceURLs: ["/metrics", "/healthz", "/readyz", "/livez", "/version"] + verbs: [get] + - apiGroups: ["monitoring.coreos.com"] + resources: + [ + prometheuses, + servicemonitors, + podmonitors, + alertmanagers, + thanosrulers, + prometheusrules, + alertmanagerconfigs, + ] + verbs: [get, list, watch] + +--- +# Let "platform team" manage only rbac-manager CRDs +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: rbacmanager-crd-admin +rules: + - apiGroups: ["rbacmanager.reactiveops.io"] + resources: ["rbacdefinitions"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + +--- +# Cluster admins +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: oidc-cluster-admins + namespace: rbac-system +rbacBindings: + - name: cluster-admins + subjects: + - kind: Group + name: "oidc:cluster-admins" + clusterRoleBindings: + - clusterRole: cluster-admin + +--- +# Cluster viewers +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: oidc-read-only + namespace: rbac-system +rbacBindings: + - name: cluster-view + subjects: + - kind: Group + name: "oidc:read-only" + clusterRoleBindings: + - clusterRole: view + +--- +# Observability — 'view' plus extras, cluster-scoped +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: oidc-observability + namespace: rbac-system +rbacBindings: + - name: observability-view + subjects: + - kind: Group + name: "oidc:observability" + clusterRoleBindings: + - clusterRole: view + - name: observability-extras + subjects: + - kind: Group + name: "oidc:observability" + clusterRoleBindings: + - clusterRole: observability-extras + +--- +# Namespace admins +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: oidc-namespace-admins + namespace: rbac-system +rbacBindings: + - name: ns-admins + subjects: + - kind: Group + name: "oidc:namespace-admins" + roleBindings: + - clusterRole: admin + namespaceSelector: + matchLabels: + rbac.opencenter.io/admin: "true" + +--- +# Security team — cluster read + admin in security namespaces +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: oidc-security-team + namespace: rbac-system +rbacBindings: + - name: security-read + subjects: + - kind: Group + name: "oidc:security-team" + clusterRoleBindings: + - clusterRole: view + - name: security-ns-admin + subjects: + - kind: Group + name: "oidc:security-team" + roleBindings: + - clusterRole: admin + namespaceSelector: + matchLabels: + security.opencenter.io/managed: "true" + +--- +# Platform team — manage only rbac-manager CRDs +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: oidc-platform-team + namespace: rbac-system +rbacBindings: + - name: platform-rbacdefs-admin + subjects: + - kind: Group + name: "oidc:platform-team" + clusterRoleBindings: + - clusterRole: rbacmanager-crd-admin +--- +# oidc-k8s-ops – bind ops group to k8s-ops +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: oidc-k8s-ops + namespace: rbac-system +rbacBindings: + - name: k8s-ops + subjects: + - kind: Group + name: "oidc:k8s-ops" + apiGroup: rbac.authorization.k8s.io + clusterRoleBindings: + - clusterRole: k8s-ops diff --git a/applications/base/services/keycloak/20-keycloak/rbac/kustomization.yaml b/applications/base/services/keycloak/30-oidc-rbac/kustomization.yaml similarity index 71% rename from applications/base/services/keycloak/20-keycloak/rbac/kustomization.yaml rename to applications/base/services/keycloak/30-oidc-rbac/kustomization.yaml index c91361c..f3c4993 100644 --- a/applications/base/services/keycloak/20-keycloak/rbac/kustomization.yaml +++ b/applications/base/services/keycloak/30-oidc-rbac/kustomization.yaml @@ -2,4 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - "k8s-ops-cluster-role.yaml" + - "default-rbac.yaml" From ca33ef6d72d436d6caa344a43b98807287fc13a9 Mon Sep 17 00:00:00 2001 From: Pratik Bandarkar Date: Wed, 29 Oct 2025 14:33:25 +0000 Subject: [PATCH 2/2] fix: fix rbacdefination of oidc-k8s-ops --- .../base/services/keycloak/30-oidc-rbac/default-rbac.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml b/applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml index 50a9592..aa84e11 100644 --- a/applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml +++ b/applications/base/services/keycloak/30-oidc-rbac/default-rbac.yaml @@ -215,6 +215,5 @@ rbacBindings: subjects: - kind: Group name: "oidc:k8s-ops" - apiGroup: rbac.authorization.k8s.io clusterRoleBindings: - clusterRole: k8s-ops