--auth-mode=proxy) enforces it on the K8s API. Two paths, both anchored to your in-cluster RBAC:
- Direct resource access is impersonated. Live reads (pods, nodes, etc.), writes, and exec/logs are all sent to the API server impersonated as the user - Kubernetes itself authorizes and enforces them against your in-cluster RBAC. Radar adds no authorization on this path.
- Cached timeline/topology is
SubjectAccessReview-authorized, then filtered. The surfaces Radar serves from its own cache (timeline, topology) can’t be impersonated per object, so for each cached object Radar runs aSubjectAccessReviewagainst the user’s identity and filters the results to what that identity may read.
The header contract
For every request through the tunnel, the control plane:- Strips inbound
X-Forwarded-*to prevent spoofing. - Injects:
X-Forwarded-User: <user_id>(e.g.user_01HF...)X-Forwarded-Groups:a comma-separated list of the groups below.
The
radar:idp:* and radar:email:* groups are the hooks the governance examples bind - they come straight from your IdP assertion, so they exist independent of this chart’s tier bindings.
The same set is also emitted under the legacy cloud: prefix (deprecated, kept so pre-rename bindings keep working; write new bindings against radar:*).
The in-cluster Radar (under RADAR_CLOUD_MODE=true) is forced to --auth-mode=proxy with these header names pinned. The chart enforces this; you can’t override it without un-cloud-mode-ing the in-cluster Radar.
The default RBAC
The chart ships three ClusterRoleBindings out of the box:
K8s itself decides what each ClusterRole permits.
view is read-only for namespaced resources. edit adds writes. admin adds RBAC operations.
Cluster-scoped resources need an extra grant
The built-inview / edit / admin roles are namespace roles - by Kubernetes design they grant nothing on most cluster-scoped resources:
So a tier bound only to a built-in role can’t see Nodes, PVs, storage, or ClusterTrustBundles - core infrastructure and trust metadata used by an observability tool. Radar’s chart closes this with a cluster-read add-on, on by default per tier (
cloud.defaultRbac.clusterScopedRead.{viewer,member,owner}, each true). It grants get/list/watch on the kinds above - no Secrets, no RBAC objects, and no PodCertificateRequests.
Pod certificate requests are opt-in
Kubernetes 1.37 serves namespacedPodCertificateRequest resources, and Radar can display them in the generic resource browser. The default Cloud tier bindings deliberately do not grant access: certificate-request metadata is more sensitive than ordinary workload inventory. A user sees these resources only where their own Kubernetes RBAC grants get/list access.
To opt in, bind a Role or ClusterRole granting get/list/watch on certificates.k8s.io/podcertificaterequests to the intended radar:viewer, radar:member, or radar:owner group. Prefer a namespaced Role when users need access only within a specific workload boundary.
Cluster-read is its own axis, separate from which namespaced ClusterRole a tier binds to:
- Turn it off for a tier to remove this add-on’s binding. With the default built-in mappings that leaves the tier namespaced-only:
clusterScopedRead.viewer: falseleaves viewers on the stockview(namespaced read) with no cluster-scoped visibility - the usual choice for a low-trust viewer tier (see security-conscious setups). With a custom*ClusterRole, the tier’s cluster-scoped reach is whatever that role grants - the flag only controls our binding. - Swapping a tier’s namespaced role does not disable cluster-read.
viewerClusterRole/memberClusterRole/ownerClusterRoleandclusterScopedRead.*are independent bindings. If you want a custom namespaced role and no infra-read, set that tier’sclusterScopedReadtofalsetoo. - A tier you’ve disabled entirely (
viewer: false) gets nothing here either - you own that tier’s RBAC.
NodePool/NodeClaim/*NodeClass, GatewayClass, Cilium cluster policies, …) are not included - grant those per the CRD’s group if your tiers need them.
Owner node cordon/drain is a separate cluster-scoped write and is off by default - enable with cloud.defaultRbac.nodeOps: true.
Overriding the defaults
The chart’scloud.defaultRbac.* block lets you swap each binding:
Locking down for security-conscious orgs
The defaults optimize for “an observability tool should show infrastructure”: every tier gets cluster-scoped read out of the box, and writes still flow through each tier’s K8s role. If your security posture is tighter, these are the levers - each is a smallvalues.yaml change, no custom roles required:
Make the viewer tier namespaced-only (most common). Viewers keep read access to the namespaces their K8s identity allows, but cannot enumerate Nodes, PVs, or storage cluster-wide:
owner → admin reads Secrets and mutates RBAC in every namespace (namespace-scoped, not cluster-wide). Point owners at a tighter custom ClusterRole; cluster-read stays independent, so you keep infra visibility unless you also disable it:
nodeOps) is already false by default. Leave it off unless owners genuinely operate nodes from Radar - K8s RBAC cannot scope patch nodes to just the cordon field (it also permits relabeling/tainting nodes) and cannot scope pods/eviction to a single node’s pods (it permits evicting any pod in any namespace; PodDisruptionBudgets bound the impact only where they exist).
What you cannot do through values.yaml is change which cluster-scoped kinds the add-on grants (it’s a fixed, Secret-free infra set). If you need a different set for a tier - say Nodes but not PVs - set that tier’s clusterScopedRead to false and bind your own ClusterRole to the radar:<tier> group (recipe below). The radar:* groups exist independent of this chart, so your binding composes with the built-in namespaced one.
Choosing a governance model
There are two coherent ways to combine the tier defaults with group-based bindings. Both are fully supported; they differ in where cluster access is governed, and you can move from the first to the second at any time. Mixed (the default): tiers for your operators, IdP groups for scoped access. Your platform team holds Owner/Member and rides the default tier bindings - cluster-wide access through the upstream-maintainedadmin/edit roles, zero binding authoring. External or namespace-scoped users (vendor teams, contractors) get their tier binding disabled (viewer: false) and access exclusively through radar:idp:<group> / radar:user:<id> bindings you author. Each population sits on the mechanism built for it. The tradeoff: two systems of record - operator access is governed by Radar Cloud membership roles (visible in the Cloud UI and audit log), scoped access by your IdP groups and RBAC manifests.
Full-IdP: every human’s cluster access flows through your IdP groups.
For organizations whose access reviews require a single source of truth, disable all three tier bindings and bind your own groups end to end:
- Cloud roles don’t disappear - they govern the product, not the cluster. Owner/Member/Viewer still control billing, member management, SSO, cluster lifecycle, and owner-only product surfaces. The mental model: Cloud role = control-plane permissions; Kubernetes bindings = cluster access. The tier bindings are merely the default cluster access, and they’re optional.
- The add-on grants ride the tier bindings. Cluster-scoped read,
nodeOps, and the Helm add-on roles bind to tier groups - with all tiers disabled, none of them render, and you own those grants in your own ClusterRoles (see the recipe above for the cluster-read set).
Per-user bindings
If you need finer control than role-level (e.g. specific user can edit deployments but only inapps/* namespaces), bind directly to the per-user group:
user_id in:
- The audit log row metadata.
- The user’s PAT page (their own ID is shown at the top).
- Owner’s view of Settings → Organization → Members (hover the row).
Per-org bindings
Every request also carriesradar:org:<org_id> in the groups header. This is mostly useful for clusters that move between orgs - typically you wouldn’t need to bind to it directly. But if you ever need “any user from this org can do X”, that’s the hook.
Auditing what the in-cluster Radar did
K8s itself logs impersonated requests inaudit.k8s.io if you’ve enabled the audit policy on the apiserver. The user ID and groups are present in the audit log entry, so you can correlate “user X did Y” against the Cloud audit log (which shows control-plane actions) and the K8s audit log (which shows in-cluster actions).
I can’t see Nodes / PVs / StorageClasses
If a tier can’t see cluster-scoped resources, its bound role doesn’t grant them. Most likely:- That tier’s
clusterScopedReadis off - setcloud.defaultRbac.clusterScopedRead.<tier>: true(the default). - You’re on an older chart that predates the cluster-read add-on - upgrade, or grant the reads directly (below).
radar-cluster-read, so reusing that name would make kubectl apply overwrite the Helm-owned object. Use radar-cluster-read-custom:
Things to watch out for
- Default
adminis broad within namespaces, but not cluster-wide. It reads Secrets and mutates RBAC in every namespace, but as a namespace role it grants nothing cluster-scoped on its own - no Node read, no node drain (that’s the opt-innodeOpsadd-on), no PV/StorageClass. If you have non-admin owners, swapradar:ownerto a custom ClusterRole. viewdoesn’t see Secrets. That’s K8sviewdefinition, not ours. If you want viewers to see Secret names without values, use a custom ClusterRole that grantsget/listonsecrets(which lets them see Secret data too - K8s doesn’t have field-level RBAC). Since Secret data is redacted by Radar before display, this is usually safe but think it through.- Built-in roles are aggregation targets.
view/edit/adminare auto-reconciled and acceptaggregate-to-*labels, so third-party charts (metrics-server, kyverno, some operators) can widen what a tier effectively holds - the tier’s scope drifts with cluster contents, not just with this chart. Audit withkubectl auth can-i --list --as-group=radar:viewer --as=xif you need certainty. - Helm write needs more than
edit. Helm install / upgrade / rollback / uninstall need broad write access, including Secrets (Helm releases are Secrets). The chart’s defaultmember → editis intentionally not enough for Helm writes; opt in via a custom binding if you want members to manage Helm.
See also
- Authentication - how proxy / OIDC mode work generally.
- Connecting a cluster - the chart values that enable cloud-mode.
- IdP group-based access - where the
radar:idp:<group>subjects come from and how to make your IdP emit them. - Organizations & roles - the role definitions that drive these groups.