From 2378706a2d4dfcbea45bd05e839416dc6085c810 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 11:43:09 +0200 Subject: [PATCH 01/11] feat(rhdh): add base NetworkPolicies for RHDH deployment [RHIDP-16476] Add default-deny + selective-allow NetworkPolicies for the RHDH backend and built-in PostgreSQL, replicating the operator's NP behavior (RHIDP-16475) in the Helm chart. Policies are always enabled to provide a secure-by-default deployment; customers can add additive NPs as needed. Backend NPs (always created): - default-deny (ingress + egress) - allow-dns-egress (53/5353 UDP+TCP) - allow-https-egress (443 TCP) - allow-psql-egress (5432 TCP to DB pods; broad egress for external DB) - allow-metrics-ingress (9464 TCP from monitoring namespaces) - allow-router-ingress (7007 TCP; OpenShift-aware namespace selector) DB NPs (only when postgresql.enabled=true): - db-default-deny, db-allow-dns-egress, db-allow-backend-ingress - Replication-aware: additional NPs for read replicas and primary-read communication when postgresql.architecture=replication Orchestrator NPs: - allow-all-egress (when orchestrator.enabled=true) Disables bitnami postgresql subchart's own NPs (primary + readReplicas) since they default to allow-all egress and unrestricted ingress, which is too permissive. Assisted-by: Claude --- charts/rhdh/Chart.yaml | 2 +- charts/rhdh/README.md | 6 +- charts/rhdh/templates/network-policies.yaml | 421 ++++++++++++++++++ .../orchestrator/network-policies.yaml | 19 + charts/rhdh/values.yaml | 10 + 5 files changed, 454 insertions(+), 4 deletions(-) create mode 100644 charts/rhdh/templates/network-policies.yaml diff --git a/charts/rhdh/Chart.yaml b/charts/rhdh/Chart.yaml index ef40439d..3c71b5b2 100644 --- a/charts/rhdh/Chart.yaml +++ b/charts/rhdh/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: redhat-developer-hub type: application -version: 2.1.1 +version: 2.2.0 appVersion: 2.1.0 annotations: artifacthub.io/category: integration-delivery diff --git a/charts/rhdh/README.md b/charts/rhdh/README.md index f728974a..7dc7bcdf 100644 --- a/charts/rhdh/README.md +++ b/charts/rhdh/README.md @@ -1,7 +1,7 @@ # RHDH Helm Chart for OpenShift and Kubernetes -![Version: 2.1.1](https://img.shields.io/badge/Version-2.1.1-informational?style=flat-square) +![Version: 2.2.0](https://img.shields.io/badge/Version-2.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) A Helm chart for deploying Red Hat Developer Hub, which is a Red Hat supported version of Backstage. @@ -36,7 +36,7 @@ For the **Generally Available** version of this chart, see: helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart -helm install my-rhdh redhat-developer/redhat-developer-hub --version 2.1.1 +helm install my-rhdh redhat-developer/redhat-developer-hub --version 2.2.0 ``` ## Introduction @@ -288,7 +288,7 @@ Kubernetes: `>= 1.31.0-0` | podDisruptionBudget | Pod Disruption Budget configuration. | object | `{"create":false,"maxUnavailable":1,"minAvailable":""}` | | podLabels | Labels to add to the pod. | object | `{}` | | podSecurityContext | Pod-level security context. | object | `{}` | -| postgresql | Built-in PostgreSQL database (bitnami subchart). | object | `{"auth":{"secretKeys":{"adminPasswordKey":"postgres-password","userPasswordKey":"password"}},"enabled":true,"image":{"digest":"","registry":"quay.io","repository":"fedora/postgresql-15","tag":"latest"},"postgresqlDataDir":"/var/lib/pgsql/data/userdata","primary":{"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"enabled":false},"extraEnvVars":[{"name":"POSTGRESQL_ADMIN_PASSWORD","valueFrom":{"secretKeyRef":{"key":"{{- include \"rhdh.postgresql.adminPasswordKey\" . }}","name":"{{- include \"rhdh.postgresql.secretName\" . }}"}}}],"persistence":{"enabled":true,"mountPath":"/var/lib/pgsql/data","size":"1Gi"},"podSecurityContext":{"enabled":false},"resources":{"limits":{"cpu":"250m","ephemeral-storage":"20Mi","memory":"1024Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}},"serviceBindings":{"enabled":true}}` | +| postgresql | Built-in PostgreSQL database (bitnami subchart). | object | `{"auth":{"secretKeys":{"adminPasswordKey":"postgres-password","userPasswordKey":"password"}},"enabled":true,"image":{"digest":"","registry":"quay.io","repository":"fedora/postgresql-15","tag":"latest"},"postgresqlDataDir":"/var/lib/pgsql/data/userdata","primary":{"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"enabled":false},"extraEnvVars":[{"name":"POSTGRESQL_ADMIN_PASSWORD","valueFrom":{"secretKeyRef":{"key":"{{- include \"rhdh.postgresql.adminPasswordKey\" . }}","name":"{{- include \"rhdh.postgresql.secretName\" . }}"}}}],"networkPolicy":{"enabled":false},"persistence":{"enabled":true,"mountPath":"/var/lib/pgsql/data","size":"1Gi"},"podSecurityContext":{"enabled":false},"resources":{"limits":{"cpu":"250m","ephemeral-storage":"20Mi","memory":"1024Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}},"readReplicas":{"networkPolicy":{"enabled":false}},"serviceBindings":{"enabled":true}}` | | preInitContainers | Init containers to run BEFORE the system init containers (e.g. inject auth credentials before install-dynamic-plugins runs). | list | `[]` | | readinessProbe | Readiness probe configuration. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/readiness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":2,"timeoutSeconds":4}` | | replicaCount | Number of desired pods. | int | `1` | diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml new file mode 100644 index 00000000..06b9ce03 --- /dev/null +++ b/charts/rhdh/templates/network-policies.yaml @@ -0,0 +1,421 @@ +{{- /* +Base NetworkPolicies for RHDH backend and built-in PostgreSQL. +These cover the network requirements of a base RHDH deployment with all enabled-by-default plugins. +See https://github.com/redhat-developer/rhdh-plugin-export-overlays/blob/main/default.packages.yaml +Disabled plugins (e.g. LDAP catalog, email notifications, scaffolder HTTP requests) may need +additional user-created additive NetworkPolicies for ports not covered here. +*/ -}} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-default-deny + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-dns-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Egress + egress: + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-https-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Egress + egress: + - ports: + - port: 443 + protocol: TCP +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-psql-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Egress + egress: + - {{- if .Values.postgresql.enabled }} + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: primary + {{- if eq (default "standalone" .Values.postgresql.architecture) "replication" }} + - podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + {{- end }} + {{- end }} + ports: + - port: {{ if .Values.postgresql.enabled }}5432{{ else }}{{ .Values.externalDatabase.port | default 5432 }}{{ end }} + protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-metrics-ingress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: openshift-monitoring + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: gmp-system + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: gke-gmp-system + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: monitoring + ports: + - port: 9464 + protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-router-ingress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + {{- if .Values.openshift.route.enabled }} + matchLabels: + policy-group.network.openshift.io/ingress: "" + {{- else }} + {} + {{- end }} + ports: + - port: 7007 + protocol: TCP +{{- if .Values.postgresql.enabled }} +{{- $isReplication := eq (default "standalone" .Values.postgresql.architecture) "replication" }} +--- +{{- /* +The following db-* policies are only created when the built-in PostgreSQL is enabled. +When using an external database (postgresql.enabled=false), only the backend NPs above +are created, and allow-psql-egress has no 'to' selector (broad egress on the configured port). + +These replace the bitnami subchart's own NPs (disabled via +postgresql.primary.networkPolicy.enabled=false and +postgresql.readReplicas.networkPolicy.enabled=false in values.yaml) +so we can enforce tighter rules. +*/ -}} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-default-deny + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: primary + policyTypes: + - Ingress + - Egress + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-allow-dns-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: primary + policyTypes: + - Egress + egress: + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-allow-backend-ingress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: primary + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 14 }} + ports: + - port: 5432 + protocol: TCP + +{{- if $isReplication }} + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-allow-replication + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: primary + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + ports: + - port: 5432 + protocol: TCP + egress: + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + ports: + - port: 5432 + protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-read-default-deny + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + policyTypes: + - Ingress + - Egress + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-read-allow-dns-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + policyTypes: + - Egress + egress: + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + - port: 5353 + protocol: UDP + - port: 5353 + protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-read-allow-primary-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: primary + ports: + - port: 5432 + protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-read-allow-backend-ingress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 14 }} + ports: + - port: 5432 + protocol: TCP + +{{- end }} + +{{- end }} diff --git a/charts/rhdh/templates/orchestrator/network-policies.yaml b/charts/rhdh/templates/orchestrator/network-policies.yaml index 27afbbae..bd2b073b 100644 --- a/charts/rhdh/templates/orchestrator/network-policies.yaml +++ b/charts/rhdh/templates/orchestrator/network-policies.yaml @@ -62,6 +62,25 @@ spec: - podSelector: {} {{- end }} --- +{{- if .Values.orchestrator.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-all-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: {} + policyTypes: + - Egress + egress: + - {} +{{- end }} +--- {{- if and .Values.orchestrator.enabled .Values.orchestrator.sonataflowPlatform.monitoring.enabled }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy diff --git a/charts/rhdh/values.yaml b/charts/rhdh/values.yaml index 1639f37f..498bfbd8 100644 --- a/charts/rhdh/values.yaml +++ b/charts/rhdh/values.yaml @@ -421,6 +421,11 @@ postgresql: adminPasswordKey: "postgres-password" userPasswordKey: "password" primary: + # The bitnami subchart ships its own NP, but it defaults to allow-all egress + # and unrestricted ingress on 5432. We disable it and provide tighter + # replacements in templates/network-policies.yaml. + networkPolicy: + enabled: false podSecurityContext: enabled: false containerSecurityContext: @@ -447,6 +452,11 @@ postgresql: secretKeyRef: key: '{{- include "rhdh.postgresql.adminPasswordKey" . }}' name: '{{- include "rhdh.postgresql.secretName" . }}' + readReplicas: + # Same rationale as primary.networkPolicy above; our own read-replica NPs + # in templates/network-policies.yaml are tighter. + networkPolicy: + enabled: false # -- External database connection. Used when postgresql.enabled is false. # See docs/external-db.md for TLS setup and privilege requirements. From e753e87b9e819a9797dd3e9ac9e4658e29b99bbf Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 14:58:04 +0200 Subject: [PATCH 02/11] fix(rhdh): fix helm lint YAML separator error in network-policies Move the Go template comment block before the conditional so that the */-}} whitespace trimming does not merge --- and apiVersion: onto the same line. Also remove the top-level comment that caused a similar issue with the first document. Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index 06b9ce03..538a32b2 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -1,10 +1,3 @@ -{{- /* -Base NetworkPolicies for RHDH backend and built-in PostgreSQL. -These cover the network requirements of a base RHDH deployment with all enabled-by-default plugins. -See https://github.com/redhat-developer/rhdh-plugin-export-overlays/blob/main/default.packages.yaml -Disabled plugins (e.g. LDAP catalog, email notifications, scaffolder HTTP requests) may need -additional user-created additive NetworkPolicies for ports not covered here. -*/ -}} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -173,9 +166,6 @@ spec: ports: - port: 7007 protocol: TCP -{{- if .Values.postgresql.enabled }} -{{- $isReplication := eq (default "standalone" .Values.postgresql.architecture) "replication" }} ---- {{- /* The following db-* policies are only created when the built-in PostgreSQL is enabled. When using an external database (postgresql.enabled=false), only the backend NPs above @@ -186,6 +176,10 @@ postgresql.primary.networkPolicy.enabled=false and postgresql.readReplicas.networkPolicy.enabled=false in values.yaml) so we can enforce tighter rules. */ -}} +{{- if .Values.postgresql.enabled }} +{{- $isReplication := eq (default "standalone" .Values.postgresql.architecture) "replication" }} + +--- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: From 90dc998ee0fef087977f8c6f23acde5ff45ed2b1 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 15:09:36 +0200 Subject: [PATCH 03/11] fix(rhdh): fix helm lint YAML separator error in network-policies Move the Go template comment before the conditional block so that whitespace trimming does not merge --- and apiVersion: onto the same line, which caused helm lint to reject the template. Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index 538a32b2..ef6adff8 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -166,6 +166,35 @@ spec: ports: - port: 7007 protocol: TCP + +{{- if .Values.test.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-test-connection + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + rhdh.redhat.com/test-connection: "true" + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 14 }} + ports: + - port: 7007 + protocol: TCP +{{- end }} {{- /* The following db-* policies are only created when the built-in PostgreSQL is enabled. When using an external database (postgresql.enabled=false), only the backend NPs above From e4fd573dd1e8aa451adf940a422a65207909093c Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 15:09:50 +0200 Subject: [PATCH 04/11] fix(rhdh): allow test-connection pod through NetworkPolicies Add rhdh.redhat.com/test-connection label to the test-connection pod and a dedicated allow-test-connection NP (gated on test.enabled) that permits the test pod to egress on port 7007 to the backend. Without this, default-deny blocks the test pod's connectivity check. Assisted-by: Claude --- charts/rhdh/templates/tests/test-connection.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/rhdh/templates/tests/test-connection.yaml b/charts/rhdh/templates/tests/test-connection.yaml index 92e6156e..3ed604be 100644 --- a/charts/rhdh/templates/tests/test-connection.yaml +++ b/charts/rhdh/templates/tests/test-connection.yaml @@ -5,6 +5,7 @@ metadata: name: "{{ include "rhdh.fullname" . }}-test-connection" labels: {{- include "rhdh.labels" . | nindent 4 }} + rhdh.redhat.com/test-connection: "true" annotations: {{- with .Values.commonAnnotations }} {{- toYaml . | nindent 4 }} From 0ca53f07c575bf36ea5adcce8276d70d099d3239 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 15:13:30 +0200 Subject: [PATCH 05/11] fix(rhdh): allow backend ingress from test-connection pod The test pod's egress NP alone is not enough; the backend also needs an ingress rule accepting connections on port 7007 from pods with the rhdh.redhat.com/test-connection label. Gated on test.enabled. Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index ef6adff8..36e0aacb 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -194,6 +194,33 @@ spec: ports: - port: 7007 protocol: TCP + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-test-connection-ingress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 14 }} + rhdh.redhat.com/test-connection: "true" + ports: + - port: 7007 + protocol: TCP {{- end }} {{- /* The following db-* policies are only created when the built-in PostgreSQL is enabled. From 27c9ef777f3eaf0fe63bfb3e16a6fa577e4e48b7 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 15:27:49 +0200 Subject: [PATCH 06/11] chore(rhdh): add TODO and inline comments to orchestrator NPs Mirror the comments from the operator repo so the namespace-wide podSelector concern and per-rule rationale are visible in the chart. Assisted-by: Claude --- .../orchestrator/network-policies.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/charts/rhdh/templates/orchestrator/network-policies.yaml b/charts/rhdh/templates/orchestrator/network-policies.yaml index bd2b073b..39e5d65d 100644 --- a/charts/rhdh/templates/orchestrator/network-policies.yaml +++ b/charts/rhdh/templates/orchestrator/network-policies.yaml @@ -1,3 +1,12 @@ +{{- /* +TODO: these Orchestrator policies use podSelector: {} (namespace-wide) and conflict with +the ADR's "default deny with selective allow" and "label-scoped policies" principles. +They weaken per-component ingress isolation for RHDH backend and DB pods in the same namespace. +Even though only one Orchestrator-flavoured RHDH instance is supported per namespace (the +SonataFlow Operator enforces one SonataFlowPlatform per namespace), a non-Orchestrator RHDH +instance could coexist in the same namespace; these namespace-wide policies would affect it too. +Review and make stricter by scoping to SonataFlow-specific labels where possible. +*/ -}} {{- if .Values.orchestrator.enabled }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy @@ -15,12 +24,15 @@ spec: - from: - namespaceSelector: matchLabels: + # Allow knative events to be delivered to workflows. kubernetes.io/metadata.name: knative-eventing - namespaceSelector: matchLabels: + # Allow auxiliary knative function for workflow (such as m2k-save-transformation) kubernetes.io/metadata.name: knative-serving - namespaceSelector: matchLabels: + # Allow openshift serverless logic operator controller pod to access all pods in sonataflow kubernetes.io/metadata.name: openshift-serverless-logic --- apiVersion: networking.k8s.io/v1 @@ -41,6 +53,7 @@ spec: - from: - namespaceSelector: matchLabels: + # Allow knative events to be delivered to workflows. policy-group.network.openshift.io/ingress: "" --- apiVersion: networking.k8s.io/v1 @@ -62,6 +75,11 @@ spec: - podSelector: {} {{- end }} --- +{{- /* +Allow all egress from all pods in the namespace. +The Orchestrator backend plugin needs HTTP egress to reach SonataFlow and Data Index services; +SonataFlow workflows may also need arbitrary outbound access. +*/ -}} {{- if .Values.orchestrator.enabled }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy @@ -100,5 +118,6 @@ spec: - from: - namespaceSelector: matchLabels: + # Allow openshift-user-workload-monitoring pods to access the workflow. kubernetes.io/metadata.name: openshift-user-workload-monitoring {{- end }} From 05ac8bc0f9d7ec43e87b34c882f48d60328a55e1 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 16:18:47 +0200 Subject: [PATCH 07/11] feat(rhdh): add Redis egress rule (port 6379) to backend NPs Redis is part of the recommended checklist for production deployments. RHDH does not deploy Redis OOTB; users bring their own, which could be in the same namespace, a different namespace, or an external managed service. The rule has no pod or namespace selector so it covers all cases. Ref: RHDHBUGS-3724 Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index 36e0aacb..48686731 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -65,6 +65,35 @@ spec: - ports: - port: 443 protocol: TCP +{{- /* +Redis is part of the recommended checklist for production deployments +(see https://docs.redhat.com/en/documentation/red_hat_developer_hub/1.10/html/setting_up_and_configuring_your_first_red_hat_developer_hub_instance/checklist-to-run-your-first-rhdh-instance-in-production_setting-up-and-configuring-your-first-red-hat-developer-hub-instance). +RHDH does not deploy Redis OOTB; users bring their own, which could be in the same +namespace, a different namespace, or an external managed service. The rule therefore +has no pod or namespace selector. +*/ -}} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-allow-redis-egress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "rhdh.selectorLabels" . | nindent 6 }} + policyTypes: + - Egress + egress: + - ports: + - port: 6379 + protocol: TCP + --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy From 41254129ab9980cfe53ff527731224d2ff015ef2 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 21:41:40 +0200 Subject: [PATCH 08/11] fix(rhdh): fix whitespace trimming merging allow-https-egress with separator The Go template comment before allow-redis-egress used */ -}} which stripped the newline before the --- separator, merging the preceding NP's last line with --- and producing invalid YAML. Changed to */}} to preserve the newline. Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index 48686731..8658a817 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -71,7 +71,7 @@ Redis is part of the recommended checklist for production deployments RHDH does not deploy Redis OOTB; users bring their own, which could be in the same namespace, a different namespace, or an external managed service. The rule therefore has no pod or namespace selector. -*/ -}} +*/}} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy From c9b6125477bd03b6260d3205849224f887de1e5e Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 21:49:34 +0200 Subject: [PATCH 09/11] refactor(rhdh): use YAML comments instead of Go template comments in NPs Go template comments with whitespace trimming (e.g. */ -}}) have caused YAML separator merging bugs twice. YAML comments avoid this entirely; they survive rendering but Kubernetes ignores them. Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 32 +++++++++---------- .../orchestrator/network-policies.yaml | 24 ++++++-------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index 8658a817..91ca29f2 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -65,14 +65,13 @@ spec: - ports: - port: 443 protocol: TCP -{{- /* -Redis is part of the recommended checklist for production deployments -(see https://docs.redhat.com/en/documentation/red_hat_developer_hub/1.10/html/setting_up_and_configuring_your_first_red_hat_developer_hub_instance/checklist-to-run-your-first-rhdh-instance-in-production_setting-up-and-configuring-your-first-red-hat-developer-hub-instance). -RHDH does not deploy Redis OOTB; users bring their own, which could be in the same -namespace, a different namespace, or an external managed service. The rule therefore -has no pod or namespace selector. -*/}} + --- +# Redis is part of the recommended checklist for production deployments +# (see https://docs.redhat.com/en/documentation/red_hat_developer_hub/1.10/html/setting_up_and_configuring_your_first_red_hat_developer_hub_instance/checklist-to-run-your-first-rhdh-instance-in-production_setting-up-and-configuring-your-first-red-hat-developer-hub-instance). +# RHDH does not deploy Redis OOTB; users bring their own, which could be in the same +# namespace, a different namespace, or an external managed service. The rule therefore +# has no pod or namespace selector. apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -251,17 +250,18 @@ spec: - port: 7007 protocol: TCP {{- end }} -{{- /* -The following db-* policies are only created when the built-in PostgreSQL is enabled. -When using an external database (postgresql.enabled=false), only the backend NPs above -are created, and allow-psql-egress has no 'to' selector (broad egress on the configured port). -These replace the bitnami subchart's own NPs (disabled via -postgresql.primary.networkPolicy.enabled=false and -postgresql.readReplicas.networkPolicy.enabled=false in values.yaml) -so we can enforce tighter rules. -*/ -}} {{- if .Values.postgresql.enabled }} + +# The following db-* policies are only created when the built-in PostgreSQL is enabled. +# When using an external database (postgresql.enabled=false), only the backend NPs above +# are created, and allow-psql-egress has no 'to' selector (broad egress on the configured port). +# +# These replace the bitnami subchart's own NPs (disabled via +# postgresql.primary.networkPolicy.enabled=false and +# postgresql.readReplicas.networkPolicy.enabled=false in values.yaml) +# so we can enforce tighter rules. + {{- $isReplication := eq (default "standalone" .Values.postgresql.architecture) "replication" }} --- diff --git a/charts/rhdh/templates/orchestrator/network-policies.yaml b/charts/rhdh/templates/orchestrator/network-policies.yaml index 39e5d65d..cc05a766 100644 --- a/charts/rhdh/templates/orchestrator/network-policies.yaml +++ b/charts/rhdh/templates/orchestrator/network-policies.yaml @@ -1,12 +1,10 @@ -{{- /* -TODO: these Orchestrator policies use podSelector: {} (namespace-wide) and conflict with -the ADR's "default deny with selective allow" and "label-scoped policies" principles. -They weaken per-component ingress isolation for RHDH backend and DB pods in the same namespace. -Even though only one Orchestrator-flavoured RHDH instance is supported per namespace (the -SonataFlow Operator enforces one SonataFlowPlatform per namespace), a non-Orchestrator RHDH -instance could coexist in the same namespace; these namespace-wide policies would affect it too. -Review and make stricter by scoping to SonataFlow-specific labels where possible. -*/ -}} +# TODO: these Orchestrator policies use podSelector: {} (namespace-wide) and conflict with +# the ADR's "default deny with selective allow" and "label-scoped policies" principles. +# They weaken per-component ingress isolation for RHDH backend and DB pods in the same namespace. +# Even though only one Orchestrator-flavoured RHDH instance is supported per namespace (the +# SonataFlow Operator enforces one SonataFlowPlatform per namespace), a non-Orchestrator RHDH +# instance could coexist in the same namespace; these namespace-wide policies would affect it too. +# Review and make stricter by scoping to SonataFlow-specific labels where possible. {{- if .Values.orchestrator.enabled }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy @@ -74,12 +72,10 @@ spec: - from: - podSelector: {} {{- end }} +# Allow all egress from all pods in the namespace. +# The Orchestrator backend plugin needs HTTP egress to reach SonataFlow and Data Index services; +# SonataFlow workflows may also need arbitrary outbound access. --- -{{- /* -Allow all egress from all pods in the namespace. -The Orchestrator backend plugin needs HTTP egress to reach SonataFlow and Data Index services; -SonataFlow workflows may also need arbitrary outbound access. -*/ -}} {{- if .Values.orchestrator.enabled }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy From a654f049fa675eb6104b36702f811e4fd4381313 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Sat, 5 Sep 2026 22:45:24 +0200 Subject: [PATCH 10/11] fix(rhdh): add missing read replica ingress NP from primary The db-allow-replication NP allows the primary to egress to read replicas, but the read replica's default-deny blocks the incoming connection. Add db-read-allow-primary-ingress to accept ingress from the primary on port 5432. Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index 91ca29f2..76dc3f31 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -467,6 +467,36 @@ spec: - port: 5432 protocol: TCP +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "rhdh.fullname" . }}-db-read-allow-primary-ingress + labels: + {{- include "rhdh.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- include "common.tplvalues.render" (dict "value" . "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: read + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: primary + ports: + - port: 5432 + protocol: TCP + --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy From 1cc9f34f88d4ab27fc6d1d3386f13603a4273165 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Mon, 7 Sep 2026 10:51:53 +0200 Subject: [PATCH 11/11] fix(rhdh): allow metrics ingress from openshift-user-workload-monitoring The chart's ServiceMonitor is a user workload, scraped by the Prometheus in openshift-user-workload-monitoring, not by the platform Prometheus in openshift-monitoring. Without this namespace in the allow list, enabling metrics.serviceMonitor would deploy the resource but its scraper would be blocked by the default-deny NP. Assisted-by: Claude --- charts/rhdh/templates/network-policies.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/charts/rhdh/templates/network-policies.yaml b/charts/rhdh/templates/network-policies.yaml index 76dc3f31..a4c9c9f1 100644 --- a/charts/rhdh/templates/network-policies.yaml +++ b/charts/rhdh/templates/network-policies.yaml @@ -152,6 +152,9 @@ spec: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: openshift-monitoring + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: openshift-user-workload-monitoring - namespaceSelector: matchLabels: kubernetes.io/metadata.name: gmp-system