Skip to main content
Radar Cloud passes the signed-in user’s identity to the in-cluster Radar. Kubernetes RBAC controls their cluster access:
  • Live operations - writes, exec, logs, attach, and uncached reads - run as the user through Kubernetes impersonation.
  • Cached reads - including ordinary resource lists, details, timeline, and topology - are filtered by Radar using Kubernetes authorization checks. For most namespaced resources, access is namespace-wide: permission to read one kind can expose other cached kinds in that namespace. Secrets and cluster-scoped resources have separate checks. See read granularity.
Shared Radar configuration, such as integration settings and Helm chart sources, also requires the appropriate Cloud role.

The header contract

For every request through the tunnel, the control plane:
  1. Strips inbound X-Forwarded-* to prevent spoofing.
  2. Injects:
    • X-Forwarded-User: <user_id> (e.g. user_01HF...)
    • X-Forwarded-Groups: a comma-separated list of the groups below.
The groups header can carry any of these, and you can bind K8s RBAC to any of them: The radar:idp:* and radar:email:* groups are the hooks the governance examples bind - they exist independently of this chart’s tier bindings. For user requests, role, org, and user groups are also emitted under the deprecated cloud: prefix. IdP and email groups use only radar:; write new bindings against radar:*. Alert-triggered investigation turns send only radar:ai:reader; hub background jobs send only radar:system. 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.

Pod trust boundary

The Radar ServiceAccount can impersonate any Kubernetes user or group. Treat the pod as a privileged authentication proxy: restrict who can modify or exec into it, or read its ServiceAccount token. Disabling the default Cloud-user bindings does not reduce this impersonation grant.

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-in view / 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 namespaced PodCertificateRequest 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: false leaves viewers on the stock view (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/ownerClusterRole and clusterScopedRead.* are independent bindings. If you want a custom namespaced role and no infra-read, set that tier’s clusterScopedRead to false too.
  • A tier you’ve disabled entirely (viewer: false) gets nothing here either - you own that tier’s RBAC.
The add-on covers the core cluster-scoped kinds above, plus a few integration kinds that a Radar screen gates on per caller, each granted only when the chart’s own collection of that group is on: Karpenter’s groups (rbac.crdGroups.karpenter, for the Capacity view), Prometheus Operator PrometheusRules (rbac.crdGroups.prometheus), and the two Cilium policy kinds CiliumNetworkPolicy and CiliumClusterwideNetworkPolicy (rbac.crdGroups.cilium, for the Traffic view’s dropped-flow panel). Other cluster-scoped CRDs that appear in topology (GatewayClass, Calico global 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.

Radar Cloud background identity

Some Radar Cloud features run without a person behind them: the alerts worker (which polls each cluster for issues) and the timeline puller (which records the cluster’s change history in Radar Cloud). They send only the radar:system group, and the chart binds that group for them: The chart supplies read-only permissions. These grants are independent of cloud.defaultRbac: they stay when you turn the tier bindings off, so alerts and the timeline keep working when IdP groups decide cluster access. To remove all of the chart’s default background grants, set cloud.systemRbac (default true) to false:
With it off, alerts and the Radar Cloud timeline read nothing unless you bind radar:system yourself. If a cluster lacks background access, upgrade its Helm chart or bind radar:system yourself.
  • Change it through the chart value. A binding you edit or delete with kubectl comes back on the next helm upgrade or GitOps sync.
  • Upgrades with --reuse-values from a chart that predates cloud.systemRbac leave it off, so an existing install never gains cluster-wide Secret read without someone choosing it. Set cloud.systemRbac=true on those installs. Fresh installs, plain helm upgrade, --reset-then-reuse-values and GitOps get the default.
  • Investigations use separate access. See AI investigation access.
Include radar:system in access reviews. Its Secret read covers every namespace: Kubernetes RBAC cannot narrow it to Helm’s Secrets.

AI investigation access

AI investigations are read-only. Hosted investigations, whether started by a person or an alert, require Radar 1.16.0 or later on the cluster. If Radar is older or offline, the investigation cannot proceed; upgrade or restore the connection first.

Requests from a person use their access

Starting an investigation or asking a follow-up uses that person’s Kubernetes identity and groups, including their Radar role and IdP groups. A user restricted to certain namespaces gets an investigation restricted to those namespaces too. This also applies when someone follows up on an investigation started by an alert. If Radar Cloud cannot confirm the person’s access, the request stops and asks them to sign in again. It does not use a broader identity instead.

Alert-triggered investigations use radar:ai:reader

The initial alert-triggered turn sends only radar:ai:reader, without a person’s groups or a Radar role. Kubernetes audit logs record these reads as radar:ai:<org_id>. By default, the chart grants: These grants are independent of cloud.defaultRbac, so disabling the human tier bindings does not remove them. Changing viewerClusterRole does not affect them, but roles labelled aggregate-to-view widen the AI role too. Review those roles before assuming it cannot read Secrets or other sensitive data. To replace the chart’s default grant with your own bindings:
Any bindings you create for radar:ai:reader still apply. For example, use RoleBindings to limit it to selected namespaces. With no grants, alert-triggered investigations cannot read the cluster. To stop automatic analysis, clear Include AI analysis on your alert rules under Settings → Organization → Notifications. When upgrading from a chart that predates cloud.aiRbac, use --reset-then-reuse-values to apply new defaults while preserving your supplied values. Plain --reuse-values can leave the key absent, which creates no default grant. An explicit cloud.aiRbac=false is preserved by either upgrade.

Who can see the results

Sharing an investigation makes its whole transcript visible to the organization. Alert-triggered investigations are organization-visible from the start. Transcripts contain results collected under each asker’s access, which can exceed another member’s own Kubernetes access. See investigation sharing. MCP clients, such as Claude Desktop and Cursor, use the user’s own Cloud identity and groups.

Overriding the defaults

The chart’s cloud.defaultRbac.* block lets you swap each binding:
To disable a binding entirely (e.g. you want only owners to have access, no members or viewers):
Members and viewers will then hit 403s when they try to do anything in the cluster. The Cloud UI still shows the cluster in the list - it’s the K8s API that’s saying no.

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 small values.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:
No cluster-scoped read for anyone - every tier is limited to its namespaced built-in role:
Non-admin owners. The default 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:
Keep cluster-scoped write off. Node cordon/drain (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-maintained admin/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:
Now every grant - operator and vendor alike - is a binding referencing one of your IdP groups: one review process, one place to look, and offboarding is group removal in your IdP. In full-IdP mode:
  • 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: Radar’s settings, its Argo CD and Kubecost connections, audit settings, agent updates, and the OCI chart sources Radar checks for Helm upgrades. 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 for people, and you own those grants in your own ClusterRoles (see the recipe above for the cluster-read set).
  • Background and AI access stay separate. Disabling human tier bindings leaves the chart’s grants for radar:system and radar:ai:reader in place. Review them separately, especially the background identity’s cluster-wide Secret read.

Full-IdP for new clusters: the organization setting

Instead of editing chart values per cluster, an owner can make IdP groups the default for new clusters with the Cluster access setting (auth.oidc.clusterAccess on a self-managed hub). Fresh installs then add cloud.defaultRbac.create=false. Existing clusters are never changed; when you connect a cluster that already runs Radar, turn on Already running Radar in this cluster? in the connect wizard to keep its bindings.

Switching an existing cluster to IdP groups

Do it in this order, or everyone loses access until a binding exists:
  1. Bind your groups in the cluster (radar:idp:<group-id>, see IdP group-based access).
  2. Check what each group alone is allowed. Checking in Radar doesn’t prove it: the tier bindings still grant access until you remove them, and Kubernetes RBAC is additive, so a binding that names the wrong group looks fine. Ask Kubernetes about the group on its own:
    An empty list means the binding doesn’t match. kubectl requires --as with --as-group; the user name is arbitrary.
  3. Upgrade the cluster to a Radar chart with the radar:system binding, then remove the tier bindings:
To undo, put the tier bindings back:
Use the release name and namespace from your installation in these commands.

Per-user bindings

If you need finer control than role-level (e.g. specific user can edit deployments but only in apps/* namespaces), bind directly to the per-user group:
Find a user’s 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 carries radar: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 in audit.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 clusterScopedRead is off - set cloud.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).
To grant cluster-scoped read directly (works on any chart version), bind the tier group to a ClusterRole. Give it a distinct name - the chart already renders a ClusterRole named 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 admin is 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-in nodeOps add-on), no PV/StorageClass. If you have non-admin owners, swap radar:owner to a custom ClusterRole.
  • Secret read permission includes values. The built-in view role denies Secrets. Granting get/list exposes their encoded data in Radar’s generic resource UI and API; Kubernetes has no names-only permission. MCP redaction does not protect that separate surface.
  • Built-in roles are aggregation targets. view/edit/admin are auto-reconciled and accept aggregate-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 with kubectl auth can-i --list --as-group=radar:viewer --as=x if you need certainty.
  • Helm runs as you. Helm install / upgrade / rollback / uninstall, and viewing a release’s values and manifests, run with your own Kubernetes identity; your Cloud role doesn’t gate them. Radar enables the Helm write actions in a namespace when you can create Secrets there (Helm stores each release as a Secret), and Kubernetes checks every resource the chart touches. With rbac.helm=true and the tier bindings on, the chart also binds the Helm add-on roles to the owner and member tiers; in Cloud mode it grants Radar’s own ServiceAccount no write access for Helm.

A user sees an empty cluster

If a user can’t list Pods or Deployments in any namespace, Radar shows a banner - “You can’t read any namespace in this cluster” - with the groups the cluster sees for them, so they can tell an admin which group to bind. On a large cluster the banner can take a page reload to appear the first time.

See also