Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
61 changes: 41 additions & 20 deletions deploy/helm/radar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,26 +161,47 @@ Radar binary (including Radar Cloud self-upgrade) does not update RBAC. Missing
on an older `--reuse-values` installation default to enabled; set explicit false
before upgrading if the added visibility is unwanted.

### Radar Cloud background identities (`radar:system`)

The hub's alerts worker and timeline puller call Radar
as the `radar:system` group, not as a user. `cloud.systemRbac` (default `true`)
binds that group to a read-only set: `view`, the cluster-read and
integration-read add-ons above, and `get/list/watch` on Secrets. Secret read is
what Helm release alerts and Secret changes in the hub timeline need, because
Helm stores each release as a Secret.

It is independent of `cloud.defaultRbac`, so turning the role bindings off
(`cloud.defaultRbac.create=false`, for example when IdP groups decide cluster
access) leaves alerts and the hub timeline working. It is all or nothing:
`cloud.systemRbac=false` removes the whole grant, and alerts and the hub
timeline then see nothing on clusters without the role bindings unless
you bind `radar:system` yourself. Change it through this value: a binding
edited or deleted with `kubectl` comes back on the next upgrade.

An upgrade with `--reuse-values` from a release that predates the key leaves it
off, so an existing install never gains Secret read without choosing it. Set
`cloud.systemRbac=true` on those installs.
### Radar Cloud background services (`radar:system`)

Radar Cloud's alerts worker and timeline puller read as `radar:system`.
`cloud.systemRbac` (default `true`) creates the chart's default read grant:
a chart-owned role aggregated to match `view`, the cluster-read and
integration-read add-ons, and cluster-wide `get/list/watch` on Secrets.
Helm release alerts and Secret changes in the timeline need Secret read;
Helm stores releases as Secrets. The grant includes no writes.

### Radar Cloud automatic Diagnose (`radar:ai`)

Manual Diagnose turns read as the person who started them. Radar Cloud forwards
that person's identity and groups; `radar:ai` is not involved. MCP clients also
read with the user's own permissions.

Automatic (alert-triggered) Diagnose runs read as `radar:ai` only, a permanent
read-only background diagnostic reader. Never grant this group write
permissions; a future write-capable feature needs its own group.
`cloud.aiRbac` (default `true`) creates the chart's default grant: a chart-owned
role aggregated to match `view` plus the cluster-read and integration-read
add-ons. With the standard `view` role this grant includes no Kubernetes Secret
permission; it also inherits anything your cluster adds to `view` (ClusterRoles
labelled `rbac.authorization.k8s.io/aggregate-to-view`). It does include pod
logs and ConfigMaps, which may contain sensitive data.

Both values are independent of `cloud.defaultRbac`. They control only the
chart's default grants, not whether features run; Radar Cloud controls whether
Diagnose runs. False or absent creates no default grant and does not remove
customer-created bindings. To narrow the default grants, set the matching value
to false and supply your own read-only bindings for that group. With no grant,
the group has no cluster access; automatic Diagnose has no viewer fallback.

A plain `--reuse-values` upgrade from a chart predating these keys leaves them
absent and creates neither default grant. Set `cloud.aiRbac=true` and/or
`cloud.systemRbac=true` explicitly to create them. Changes made directly to
chart-managed bindings are restored on the next Helm upgrade.

Creating or updating these aggregated roles requires cluster-admin-equivalent
authority or `escalate` on ClusterRoles, in addition to normal chart installation
permissions. Restricted installers can set `cloud.aiRbac=false` and
`cloud.systemRbac=false` and supply their own read-only group bindings.

### Connecting to Argo CD (GitOps deep diff)

Expand Down
16 changes: 15 additions & 1 deletion deploy/helm/radar/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Create the name of the service account to use
{{- end -}}

{{/*
Whether the read-only binding for Radar Cloud's own background identities
Whether the default read grant for Radar Cloud's background services
(radar:system) renders. It includes cluster-wide Secret read, so an absent
value means OFF: a `--reuse-values` upgrade from a release that predates the
key renders with the previous release's tree and never gains Secret read
Expand All @@ -87,3 +87,17 @@ true
false
{{- end -}}
{{- end -}}

{{/*
Whether the default read grant for automatic Diagnose (radar:ai) renders.
An absent value means OFF, as with radar.cloudSystemRbac: a
`--reuse-values` upgrade from a release that predates the key never gains a
new reader without someone choosing it.
*/}}
{{- define "radar.cloudAiRbac" -}}
{{- if and .Values.cloud.enabled (eq (toString .Values.cloud.aiRbac) "true") -}}
true
{{- else -}}
false
{{- end -}}
{{- end -}}
49 changes: 49 additions & 0 deletions deploy/helm/radar/templates/cloud-rbac-ai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{{- /*
Read-only access for automatic (alert-triggered) Radar Cloud Diagnose runs.

Automatic runs read as radar:ai only. Manual turns read as the person who
started them, with that person's identity and groups forwarded by Radar Cloud;
radar:ai is not involved. Keep radar:ai permanently read-only; any future
write-capable feature needs its own group.

The default grant is view plus the cluster-read and integration-read add-ons.
With the standard view role it grants no Kubernetes Secret permission; it
also inherits anything a cluster adds to view (roles labelled
aggregate-to-view). view includes pod logs and ConfigMaps, which may contain
sensitive data.

cloud.aiRbac controls only this chart's default grant, independently of
cloud.defaultRbac. False or absent creates none and leaves customer bindings
untouched. Radar Cloud controls whether Diagnose runs.

A chart-owned role lets its rules change later without replacing the binding,
whose roleRef is immutable. Aggregation keeps it equal to view with no curation.
*/}}
{{- if and (include "radar.cloudAiRbac" . | eq "true") .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "radar.fullname" . }}-cloud-ai-read
labels:
{{- include "radar.labels" . | nindent 4 }}
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
# Omit rules because the aggregation controller owns them.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "radar.fullname" . }}-cloud-ai-read
labels:
{{- include "radar.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "radar.fullname" . }}-cloud-ai-read
subjects:
- kind: Group
name: radar:ai
apiGroup: rbac.authorization.k8s.io
{{- end -}}
20 changes: 19 additions & 1 deletion deploy/helm/radar/templates/cloud-rbac-cluster-read.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ from being truthy.
{{- $rbacDefaults := .Values.cloud.defaultRbac }}
{{- $anyTier := and $rbacDefaults.create (or (and $rbacDefaults.viewer (get $csrOn "viewer")) (and $rbacDefaults.member (get $csrOn "member")) (and $rbacDefaults.owner (get $csrOn "owner"))) }}
{{- $systemOn := include "radar.cloudSystemRbac" . | eq "true" }}
{{- if and .Values.cloud.enabled .Values.rbac.create (or $anyTier $systemOn) -}}
{{- $aiOn := include "radar.cloudAiRbac" . | eq "true" }}
{{- if and .Values.cloud.enabled .Values.rbac.create (or $anyTier $systemOn $aiOn) -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
Expand Down Expand Up @@ -191,4 +192,21 @@ subjects:
name: radar:system
apiGroup: rbac.authorization.k8s.io
{{- end }}
{{- if $aiOn }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ $fullname }}-cloud-ai-cluster-read
labels:
{{- $labels | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ $fullname }}-cluster-read
subjects:
- kind: Group
name: radar:ai
apiGroup: rbac.authorization.k8s.io
{{- end }}
{{- end -}}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
{{- $integration := $rbac.integrationRead | default dict -}}
{{- $cluster := $rbac.clusterScopedRead | default dict -}}
{{- $systemOn := include "radar.cloudSystemRbac" . | eq "true" -}}
{{- if and .Values.cloud.enabled .Values.rbac.create (or $rbac.create $systemOn) -}}
{{- $aiOn := include "radar.cloudAiRbac" . | eq "true" -}}
{{- if and .Values.cloud.enabled .Values.rbac.create (or $rbac.create $systemOn $aiOn) -}}
{{- $root := . -}}
{{- $baseline := .Files.Get "files/integration-read-baseline.yaml" | fromYaml -}}
{{- range $scope := list "Namespaced" "Cluster" -}}
Expand All @@ -16,6 +17,9 @@
{{- if $systemOn -}}
{{- $tiers = append $tiers "system" -}}
{{- end -}}
{{- if $aiOn -}}
{{- $tiers = append $tiers "ai" -}}
{{- end -}}
{{- $rules := list -}}
{{- range $entry := $baseline.entries -}}
{{- if and (eq $entry.decision "grant") (eq $entry.scope $scope) (or $root.Values.rbac.crdGroups.all (index $root.Values.rbac.crdGroups $entry.collection)) -}}
Expand Down Expand Up @@ -49,7 +53,7 @@ subjects:
- kind: Group
name: radar:{{ $tier }}
apiGroup: rbac.authorization.k8s.io
{{- if ne $tier "system" }}
{{- if not (has $tier (list "system" "ai")) }}
- kind: Group
name: cloud:{{ $tier }}
apiGroup: rbac.authorization.k8s.io
Expand Down
41 changes: 25 additions & 16 deletions deploy/helm/radar/templates/cloud-rbac-system.yaml
Original file line number Diff line number Diff line change
@@ -1,32 +1,41 @@
{{- /*
Read-only access for Radar Cloud's own background identities.
Read-only access for Radar Cloud's alerts worker and timeline puller.

The hub's background identities have no user or IdP groups; they assert the
radar:system group. That is the alerts worker and the timeline puller (AI
diagnose reads as radar:viewer). Without a binding of their own they would ride
on radar:owner, which disappears when an org turns the role bindings off
(cloud.defaultRbac.create=false) to let IdP groups decide cluster access —
silently stopping alerts and the hub timeline.
These background services read as radar:system. The default grant is view
plus the cluster-read and integration-read add-ons and cluster-wide Secret
read. Helm release alerts and Secret changes in the timeline need Secret read;
Helm stores releases as Secrets. No writes.

The grant is the viewer set (view here, plus the cluster-read and
integration-read add-ons, which bind radar:system in their own templates) and
Secret read. Secret read is what Helm release alerts and Secret changes in the
hub timeline need: Radar lists Helm releases as the caller, and Helm stores
each release as a Secret. Kubernetes RBAC cannot narrow that to Helm's
Secrets, so it is all Secrets, read-only. No writes. All or nothing:
cloud.systemRbac=false removes the whole grant.
cloud.systemRbac controls only this chart's default grant, independently of
cloud.defaultRbac. False or absent creates none and leaves customer bindings
untouched. It is not a feature switch.

A chart-owned role lets its rules change later without replacing the binding,
whose roleRef is immutable. Aggregation keeps it equal to view with no curation.
*/}}
{{- if and (include "radar.cloudSystemRbac" . | eq "true") .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "radar.fullname" . }}-cloud-system-read
labels:
{{- include "radar.labels" . | nindent 4 }}
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
# Omit rules because the aggregation controller owns them.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "radar.fullname" . }}-cloud-system-view
name: {{ include "radar.fullname" . }}-cloud-system-read
labels:
{{- include "radar.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: view
name: {{ include "radar.fullname" . }}-cloud-system-read
subjects:
- kind: Group
name: radar:system
Expand Down
Loading
Loading