From a0bf21dc7dd2600ac3d11a8f5b084027e913499f Mon Sep 17 00:00:00 2001 From: Giulio Calzolari Date: Wed, 1 Apr 2026 16:15:40 +0200 Subject: [PATCH 1/5] feat(chart): add NetworkPolicy templates for all Slurm components Add opt-in Kubernetes NetworkPolicy Helm templates for controller, nodeset, accounting, restapi, and loginset. Disabled by default via `networkPolicy.enabled: false` with per-component toggles and support for extra ingress/egress rules at both global and component level. --- .../networkpolicy/operator-netpol.yaml | 56 +++ .../networkpolicy/webhook-netpol.yaml | 51 +++ .../__snapshot__/networkpolicy_test.yaml.snap | 78 ++++ .../tests/networkpolicy_test.yaml | 234 +++++++++++ helm/slurm-operator/values.yaml | 26 ++ .../networkpolicy/accounting-netpol.yaml | 57 +++ .../networkpolicy/controller-netpol.yaml | 72 ++++ .../networkpolicy/loginset-netpol.yaml | 51 +++ .../networkpolicy/nodeset-netpol.yaml | 73 ++++ .../networkpolicy/restapi-netpol.yaml | 50 +++ .../__snapshot__/networkpolicy_test.yaml.snap | 221 +++++++++++ helm/slurm/tests/networkpolicy_test.yaml | 364 ++++++++++++++++++ helm/slurm/values.yaml | 42 ++ 13 files changed, 1375 insertions(+) create mode 100644 helm/slurm-operator/templates/networkpolicy/operator-netpol.yaml create mode 100644 helm/slurm-operator/templates/networkpolicy/webhook-netpol.yaml create mode 100644 helm/slurm-operator/tests/__snapshot__/networkpolicy_test.yaml.snap create mode 100644 helm/slurm-operator/tests/networkpolicy_test.yaml create mode 100644 helm/slurm/templates/networkpolicy/accounting-netpol.yaml create mode 100644 helm/slurm/templates/networkpolicy/controller-netpol.yaml create mode 100644 helm/slurm/templates/networkpolicy/loginset-netpol.yaml create mode 100644 helm/slurm/templates/networkpolicy/nodeset-netpol.yaml create mode 100644 helm/slurm/templates/networkpolicy/restapi-netpol.yaml create mode 100644 helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap create mode 100644 helm/slurm/tests/networkpolicy_test.yaml diff --git a/helm/slurm-operator/templates/networkpolicy/operator-netpol.yaml b/helm/slurm-operator/templates/networkpolicy/operator-netpol.yaml new file mode 100644 index 000000000..8af7164bb --- /dev/null +++ b/helm/slurm-operator/templates/networkpolicy/operator-netpol.yaml @@ -0,0 +1,56 @@ +{{- /* +SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. +SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if and .Values.networkPolicy.enabled .Values.operator.enabled .Values.operator.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "slurm-operator.name" . }} + namespace: {{ include "slurm-operator.namespace" . }} + labels: + {{- include "slurm-operator.operator.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + {{- include "slurm-operator.operator.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + {{- if ne (int .Values.operator.metricsPort) 0 }} + - ports: + - protocol: TCP + port: {{ .Values.operator.metricsPort | default 8080 }} + {{- end }} + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.operator.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: TCP + port: 443 + - ports: + - protocol: TCP + port: 6820 + to: + - namespaceSelector: {} + podSelector: + matchLabels: + app.kubernetes.io/name: slurmrestd + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.operator.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/slurm-operator/templates/networkpolicy/webhook-netpol.yaml b/helm/slurm-operator/templates/networkpolicy/webhook-netpol.yaml new file mode 100644 index 000000000..669c5e013 --- /dev/null +++ b/helm/slurm-operator/templates/networkpolicy/webhook-netpol.yaml @@ -0,0 +1,51 @@ +{{- /* +SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. +SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if and .Values.networkPolicy.enabled .Values.webhook.enabled .Values.webhook.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "slurm-operator.webhook.name" . }} + namespace: {{ include "slurm-operator.namespace" . }} + labels: + {{- include "slurm-operator.webhook.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + {{- include "slurm-operator.webhook.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + - ports: + - protocol: TCP + port: {{ .Values.webhook.serverPort | default 9443 }} + {{- if ne (int .Values.webhook.metricsPort) 0 }} + - ports: + - protocol: TCP + port: {{ .Values.webhook.metricsPort }} + {{- end }} + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.webhook.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: TCP + port: 443 + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.webhook.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/slurm-operator/tests/__snapshot__/networkpolicy_test.yaml.snap b/helm/slurm-operator/tests/__snapshot__/networkpolicy_test.yaml.snap new file mode 100644 index 000000000..589b15849 --- /dev/null +++ b/helm/slurm-operator/tests/__snapshot__/networkpolicy_test.yaml.snap @@ -0,0 +1,78 @@ +operator manifest should match snapshot: + 1: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + labels: + app.kubernetes.io/instance: test-release + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: slurm-operator + app.kubernetes.io/part-of: slurm-operator + app.kubernetes.io/version: 1.2.3 + helm.sh/chart: slurm-operator-1.2.3 + name: slurm-operator + namespace: test-namespace + spec: + egress: + - ports: + - port: 443 + protocol: TCP + - ports: + - port: 6820 + protocol: TCP + to: + - namespaceSelector: {} + podSelector: + matchLabels: + app.kubernetes.io/name: slurmrestd + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + ingress: + - ports: + - port: 8080 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/instance: test-release + app.kubernetes.io/name: slurm-operator + policyTypes: + - Ingress + - Egress +webhook manifest should match snapshot: + 1: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + labels: + app.kubernetes.io/instance: test-release + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: slurm-operator-webhook + app.kubernetes.io/part-of: slurm-operator + app.kubernetes.io/version: 1.2.3 + helm.sh/chart: slurm-operator-1.2.3 + name: slurm-operator-webhook + namespace: test-namespace + spec: + egress: + - ports: + - port: 443 + protocol: TCP + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + ingress: + - ports: + - port: 9443 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/instance: test-release + app.kubernetes.io/name: slurm-operator-webhook + policyTypes: + - Ingress + - Egress diff --git a/helm/slurm-operator/tests/networkpolicy_test.yaml b/helm/slurm-operator/tests/networkpolicy_test.yaml new file mode 100644 index 000000000..376d73f1c --- /dev/null +++ b/helm/slurm-operator/tests/networkpolicy_test.yaml @@ -0,0 +1,234 @@ +--- +suite: test networkpolicy +templates: + - networkpolicy/operator-netpol.yaml + - networkpolicy/webhook-netpol.yaml +chart: + version: 1.2.3 + appVersion: 1.2.3 +release: + name: test-release + namespace: test-namespace +tests: + - it: should not create any networkpolicy when disabled + set: + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: operator manifest should match snapshot + template: networkpolicy/operator-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create operator networkpolicy when operator.networkPolicy.enabled is false + template: networkpolicy/operator-netpol.yaml + set: + networkPolicy: + enabled: true + operator: + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should not create operator networkpolicy when operator is disabled + template: networkpolicy/operator-netpol.yaml + set: + networkPolicy: + enabled: true + operator: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: operator should include metrics ingress when metricsPort is non-zero + template: networkpolicy/operator-netpol.yaml + set: + networkPolicy: + enabled: true + operator: + metricsPort: 8080 + asserts: + - contains: + path: spec.ingress + content: + ports: + - protocol: TCP + port: 8080 + + - it: operator should include slurmrestd egress + template: networkpolicy/operator-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - contains: + path: spec.egress + content: + ports: + - protocol: TCP + port: 6820 + to: + - namespaceSelector: {} + podSelector: + matchLabels: + app.kubernetes.io/name: slurmrestd + + - it: operator should not include metrics ingress when metricsPort is zero + template: networkpolicy/operator-netpol.yaml + set: + networkPolicy: + enabled: true + operator: + metricsPort: 0 + asserts: + - isEmpty: + path: spec.ingress + + - it: webhook manifest should match snapshot + template: networkpolicy/webhook-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create webhook networkpolicy when webhook.networkPolicy.enabled is false + template: networkpolicy/webhook-netpol.yaml + set: + networkPolicy: + enabled: true + webhook: + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should not create webhook networkpolicy when webhook is disabled + template: networkpolicy/webhook-netpol.yaml + set: + networkPolicy: + enabled: true + webhook: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: webhook should use custom serverPort + template: networkpolicy/webhook-netpol.yaml + set: + networkPolicy: + enabled: true + webhook: + serverPort: 8443 + asserts: + - contains: + path: spec.ingress + content: + ports: + - protocol: TCP + port: 8443 + + - it: should append global extraIngress to all networkpolicies + set: + networkPolicy: + enabled: true + extraIngress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: monitoring + ports: + - protocol: TCP + port: 9090 + asserts: + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: monitoring + ports: + - protocol: TCP + port: 9090 + + - it: should append global extraEgress to all networkpolicies + set: + networkPolicy: + enabled: true + extraEgress: + - to: + - ipBlock: + cidr: 10.0.0.0/8 + ports: + - protocol: TCP + port: 443 + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 10.0.0.0/8 + ports: + - protocol: TCP + port: 443 + + - it: should append operator-specific extraEgress + template: networkpolicy/operator-netpol.yaml + set: + networkPolicy: + enabled: true + operator: + networkPolicy: + extraEgress: + - to: + - ipBlock: + cidr: 192.168.0.0/16 + ports: + - protocol: TCP + port: 6443 + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 192.168.0.0/16 + ports: + - protocol: TCP + port: 6443 + + - it: should append webhook-specific extraIngress + template: networkpolicy/webhook-netpol.yaml + set: + networkPolicy: + enabled: true + webhook: + networkPolicy: + extraIngress: + - from: + - namespaceSelector: {} + ports: + - protocol: TCP + port: 9443 + asserts: + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: {} + ports: + - protocol: TCP + port: 9443 diff --git a/helm/slurm-operator/values.yaml b/helm/slurm-operator/values.yaml index df813e263..c6541d1b7 100644 --- a/helm/slurm-operator/values.yaml +++ b/helm/slurm-operator/values.yaml @@ -30,6 +30,14 @@ crds: operator: # -- Enables the operator. enabled: true + # NetworkPolicy settings for this component. + networkPolicy: + # -- Enable NetworkPolicy for the operator. + enabled: true + # -- Extra ingress rules appended to the operator NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to the operator NetworkPolicy. + extraEgress: [] # -- Set the number of replicas to deploy. replicas: 1 # -- Set the image pull policy. @@ -132,6 +140,14 @@ operator: webhook: # -- Enable the webhook. enabled: true + # NetworkPolicy settings for this component. + networkPolicy: + # -- Enable NetworkPolicy for the webhook. + enabled: true + # -- Extra ingress rules appended to the webhook NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to the webhook NetworkPolicy. + extraEgress: [] # -- Set the number of replicas to deploy. replicas: 1 # -- Set the image pull policy. @@ -248,6 +264,16 @@ certManager: propagatedNodeConditions: [] # - KubeletUnhealthy +# Configure Kubernetes NetworkPolicies for slurm-operator components. +# Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +networkPolicy: + # -- Enable NetworkPolicy resources for all slurm-operator components. + enabled: false + # -- Extra ingress rules appended to every NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to every NetworkPolicy. + extraEgress: [] + # -- Extra Kubernetes objects to deploy alongside the chart. # Each entry is rendered as a standalone Kubernetes object. # Supports Helm templating (e.g. {{ .Release.Namespace }}). diff --git a/helm/slurm/templates/networkpolicy/accounting-netpol.yaml b/helm/slurm/templates/networkpolicy/accounting-netpol.yaml new file mode 100644 index 000000000..0446fa397 --- /dev/null +++ b/helm/slurm/templates/networkpolicy/accounting-netpol.yaml @@ -0,0 +1,57 @@ +{{- /* +SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. +SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if and .Values.networkPolicy.enabled .Values.accounting.networkPolicy.enabled .Values.accounting.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "slurm.fullname" . }}-accounting + namespace: {{ include "slurm.namespace" . }} + labels: + {{- include "slurm.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + policyTypes: + - Ingress + - Egress + ingress: + - ports: + - protocol: TCP + port: 6819 + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.accounting.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: TCP + port: {{ include "slurm.controller.port" . }} + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - protocol: TCP + port: 3306 + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.accounting.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/slurm/templates/networkpolicy/controller-netpol.yaml b/helm/slurm/templates/networkpolicy/controller-netpol.yaml new file mode 100644 index 000000000..8acf6efe4 --- /dev/null +++ b/helm/slurm/templates/networkpolicy/controller-netpol.yaml @@ -0,0 +1,72 @@ +{{- /* +SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. +SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if and .Values.networkPolicy.enabled .Values.controller.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "slurm.fullname" . }}-controller + namespace: {{ include "slurm.namespace" . }} + labels: + {{- include "slurm.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + policyTypes: + - Ingress + - Egress + ingress: + - ports: + - protocol: TCP + port: {{ include "slurm.controller.port" . }} + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmrestd + - podSelector: + matchLabels: + app.kubernetes.io/name: login + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.controller.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: TCP + port: {{ include "slurm.worker.port" . }} + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + {{- if .Values.accounting.enabled }} + - ports: + - protocol: TCP + port: 6819 + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + {{- end }} + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.controller.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/slurm/templates/networkpolicy/loginset-netpol.yaml b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml new file mode 100644 index 000000000..ee41f2768 --- /dev/null +++ b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml @@ -0,0 +1,51 @@ +{{- /* +SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. +SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if and .Values.networkPolicy.enabled .Values.networkPolicy.loginset }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "slurm.fullname" . }}-loginset + namespace: {{ include "slurm.namespace" . }} + labels: + {{- include "slurm.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: login + policyTypes: + - Ingress + - Egress + ingress: + - ports: + - protocol: TCP + port: 22 + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: TCP + port: {{ include "slurm.controller.port" . }} + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - protocol: TCP + port: 22 + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml new file mode 100644 index 000000000..25e6c9056 --- /dev/null +++ b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml @@ -0,0 +1,73 @@ +{{- /* +SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. +SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if and .Values.networkPolicy.enabled .Values.networkPolicy.nodeset }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "slurm.fullname" . }}-nodeset + namespace: {{ include "slurm.namespace" . }} + labels: + {{- include "slurm.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + policyTypes: + - Ingress + - Egress + ingress: + - ports: + - protocol: TCP + port: {{ include "slurm.worker.port" . }} + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + {{- $sshEnabled := false }} + {{- range $key, $nodeset := .Values.nodesets }} + {{- if and $nodeset.enabled (dig "ssh" "enabled" false $nodeset) }} + {{- $sshEnabled = true }} + {{- end }} + {{- end }} + {{- if $sshEnabled }} + - ports: + - protocol: TCP + port: 22 + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: login + {{- end }} + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: TCP + port: {{ include "slurm.controller.port" . }} + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - protocol: TCP + port: {{ include "slurm.worker.port" . }} + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/slurm/templates/networkpolicy/restapi-netpol.yaml b/helm/slurm/templates/networkpolicy/restapi-netpol.yaml new file mode 100644 index 000000000..3a4aead31 --- /dev/null +++ b/helm/slurm/templates/networkpolicy/restapi-netpol.yaml @@ -0,0 +1,50 @@ +{{- /* +SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. +SPDX-License-Identifier: Apache-2.0 +*/}} + +{{- if and .Values.networkPolicy.enabled .Values.restapi.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "slurm.fullname" . }}-restapi + namespace: {{ include "slurm.namespace" . }} + labels: + {{- include "slurm.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: slurmrestd + policyTypes: + - Ingress + - Egress + ingress: + - ports: + - protocol: TCP + port: {{ include "slurm.restapi.port" . }} + {{- with .Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.restapi.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: TCP + port: {{ include "slurm.controller.port" . }} + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + {{- with .Values.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.restapi.networkPolicy.extraEgress }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap new file mode 100644 index 000000000..dabc27a5e --- /dev/null +++ b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap @@ -0,0 +1,221 @@ +accounting manifest should match snapshot: + 1: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + labels: + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: slurm + app.kubernetes.io/version: 1.2.3 + helm.sh/chart: slurm-1.2.3 + name: test-release-slurm-accounting + namespace: test-namespace + spec: + egress: + - ports: + - port: 6817 + protocol: TCP + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - port: 3306 + protocol: TCP + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + ports: + - port: 6819 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + policyTypes: + - Ingress + - Egress +controller manifest should match snapshot: + 1: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + labels: + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: slurm + app.kubernetes.io/version: 1.2.3 + helm.sh/chart: slurm-1.2.3 + name: test-release-slurm-controller + namespace: test-namespace + spec: + egress: + - ports: + - port: 6818 + protocol: TCP + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmrestd + - podSelector: + matchLabels: + app.kubernetes.io/name: login + ports: + - port: 6817 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + policyTypes: + - Ingress + - Egress +loginset manifest should match snapshot: + 1: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + labels: + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: slurm + app.kubernetes.io/version: 1.2.3 + helm.sh/chart: slurm-1.2.3 + name: test-release-slurm-loginset + namespace: test-namespace + spec: + egress: + - ports: + - port: 6817 + protocol: TCP + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - port: 22 + protocol: TCP + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + ingress: + - ports: + - port: 22 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/name: login + policyTypes: + - Ingress + - Egress +nodeset manifest should match snapshot: + 1: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + labels: + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: slurm + app.kubernetes.io/version: 1.2.3 + helm.sh/chart: slurm-1.2.3 + name: test-release-slurm-nodeset + namespace: test-namespace + spec: + egress: + - ports: + - port: 6817 + protocol: TCP + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - port: 6818 + protocol: TCP + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + ports: + - port: 6818 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + policyTypes: + - Ingress + - Egress +restapi manifest should match snapshot: + 1: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + labels: + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: slurm + app.kubernetes.io/version: 1.2.3 + helm.sh/chart: slurm-1.2.3 + name: test-release-slurm-restapi + namespace: test-namespace + spec: + egress: + - ports: + - port: 6817 + protocol: TCP + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmctld + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + ingress: + - ports: + - port: 6820 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/name: slurmrestd + policyTypes: + - Ingress + - Egress diff --git a/helm/slurm/tests/networkpolicy_test.yaml b/helm/slurm/tests/networkpolicy_test.yaml new file mode 100644 index 000000000..20b9d04c2 --- /dev/null +++ b/helm/slurm/tests/networkpolicy_test.yaml @@ -0,0 +1,364 @@ +--- +suite: test networkpolicy +templates: + - networkpolicy/controller-netpol.yaml + - networkpolicy/nodeset-netpol.yaml + - networkpolicy/accounting-netpol.yaml + - networkpolicy/restapi-netpol.yaml + - networkpolicy/loginset-netpol.yaml +release: + name: test-release + namespace: test-namespace +chart: + version: 1.2.3 + appVersion: 1.2.3 +tests: + - it: should not create any networkpolicy when disabled + set: + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: controller manifest should match snapshot + template: networkpolicy/controller-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create controller networkpolicy when controller.networkPolicy.enabled is false + template: networkpolicy/controller-netpol.yaml + set: + networkPolicy: + enabled: true + controller: + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: nodeset manifest should match snapshot + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create nodeset networkpolicy when networkPolicy.nodeset is false + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + nodeset: false + asserts: + - hasDocuments: + count: 0 + + - it: nodeset should include SSH ingress from login when ssh is enabled + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + nodesets: + slinky: + enabled: true + ssh: + enabled: true + asserts: + - contains: + path: spec.ingress + content: + ports: + - protocol: TCP + port: 22 + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: login + + - it: loginset should include SSH egress to nodeset + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - contains: + path: spec.egress + content: + ports: + - protocol: TCP + port: 22 + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + + - it: accounting manifest should match snapshot + template: networkpolicy/accounting-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create accounting networkpolicy when accounting is disabled + template: networkpolicy/accounting-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should not create accounting networkpolicy when accounting.networkPolicy.enabled is false + template: networkpolicy/accounting-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: true + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: restapi manifest should match snapshot + template: networkpolicy/restapi-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create restapi networkpolicy when restapi.networkPolicy.enabled is false + template: networkpolicy/restapi-netpol.yaml + set: + networkPolicy: + enabled: true + restapi: + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: loginset manifest should match snapshot + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create loginset networkpolicy when networkPolicy.loginset is false + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + loginset: false + asserts: + - hasDocuments: + count: 0 + + - it: controller should include accounting egress when accounting is enabled + template: networkpolicy/controller-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: true + asserts: + - contains: + path: spec.egress + content: + ports: + - protocol: TCP + port: 6819 + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + + - it: controller should not include accounting egress when accounting is disabled + template: networkpolicy/controller-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: false + asserts: + - notContains: + path: spec.egress + content: + ports: + - protocol: TCP + port: 6819 + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + + - it: should append global extraIngress to all networkpolicies + set: + networkPolicy: + enabled: true + extraIngress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: monitoring + ports: + - protocol: TCP + port: 9090 + accounting: + enabled: true + asserts: + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: monitoring + ports: + - protocol: TCP + port: 9090 + + - it: should append global extraEgress to all networkpolicies + set: + networkPolicy: + enabled: true + extraEgress: + - to: + - ipBlock: + cidr: 10.0.0.0/8 + ports: + - protocol: TCP + port: 443 + accounting: + enabled: true + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 10.0.0.0/8 + ports: + - protocol: TCP + port: 443 + + - it: should append controller-specific extraIngress + template: networkpolicy/controller-netpol.yaml + set: + networkPolicy: + enabled: true + controller: + networkPolicy: + extraIngress: + - from: + - podSelector: + matchLabels: + app: custom-client + ports: + - protocol: TCP + port: 8080 + asserts: + - contains: + path: spec.ingress + content: + from: + - podSelector: + matchLabels: + app: custom-client + ports: + - protocol: TCP + port: 8080 + + - it: should append controller-specific extraEgress + template: networkpolicy/controller-netpol.yaml + set: + networkPolicy: + enabled: true + controller: + networkPolicy: + extraEgress: + - to: + - ipBlock: + cidr: 192.168.0.0/16 + ports: + - protocol: TCP + port: 8443 + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 192.168.0.0/16 + ports: + - protocol: TCP + port: 8443 + + - it: should append restapi-specific extraIngress + template: networkpolicy/restapi-netpol.yaml + set: + networkPolicy: + enabled: true + restapi: + networkPolicy: + extraIngress: + - from: + - namespaceSelector: + matchLabels: + name: ingress + ports: + - protocol: TCP + port: 6820 + asserts: + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + name: ingress + ports: + - protocol: TCP + port: 6820 + + - it: should append accounting-specific extraEgress + template: networkpolicy/accounting-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: true + networkPolicy: + extraEgress: + - to: + - ipBlock: + cidr: 10.1.0.0/16 + ports: + - protocol: TCP + port: 5432 + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 10.1.0.0/16 + ports: + - protocol: TCP + port: 5432 diff --git a/helm/slurm/values.yaml b/helm/slurm/values.yaml index 9529ddd3f..3d668ca28 100644 --- a/helm/slurm/values.yaml +++ b/helm/slurm/values.yaml @@ -160,6 +160,14 @@ epilogScripts: {} # Slurm controller (slurmctld) configuration. controller: + # NetworkPolicy settings for this component. + networkPolicy: + # -- Enable NetworkPolicy for the Controller. + enabled: true + # -- Extra ingress rules appended to the Controller NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to the Controller NetworkPolicy. + extraEgress: [] # -- Configures this component as external (not in Kubernetes). external: false # Details required to communicate with an external slurmdbd. @@ -344,6 +352,14 @@ controller: # Slurm REST API (slurmrestd) configuration. restapi: + # NetworkPolicy settings for this component. + networkPolicy: + # -- Enable NetworkPolicy for the REST API. + enabled: true + # -- Extra ingress rules appended to the REST API NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to the REST API NetworkPolicy. + extraEgress: [] # -- Number of replicas to deploy. replicas: 1 # slurmrestd container configurations. @@ -417,6 +433,14 @@ restapi: # Slurm accounting (slurmdbd) configuration. accounting: + # NetworkPolicy settings for this component. + networkPolicy: + # -- Enable NetworkPolicy for Accounting. + enabled: true + # -- Extra ingress rules appended to the Accounting NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to the Accounting NetworkPolicy. + extraEgress: [] # -- Enables Slurm accounting subsystem, stores job/step historical records. # Ref: https://slurm.schedmd.com/accounting.html#Overview enabled: false @@ -882,6 +906,24 @@ vendor: # - vpc7 # - vpc8 +# Configure Kubernetes NetworkPolicies for Slurm components. +# Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +networkPolicy: + # -- Enable NetworkPolicy resources for all Slurm components. + enabled: false + # -- Enable NetworkPolicy for NodeSets (slurmd). + # Kept here because `nodesets` is a map and cannot hold a scalar alongside instance entries. + nodeset: true + # -- Enable NetworkPolicy for LoginSets (sackd/sshd). + # Kept here because `loginsets` is a map and cannot hold a scalar alongside instance entries. + loginset: true + # -- Extra ingress rules appended to every NetworkPolicy. + # Ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#networkpolicyingressrule-v1-networking-k8s-io + extraIngress: [] + # -- Extra egress rules appended to every NetworkPolicy. + # Ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#networkpolicyegressrule-v1-networking-k8s-io + extraEgress: [] + # -- Extra Kubernetes objects to deploy alongside the chart. # Each entry is rendered as a standalone Kubernetes object. # Supports Helm templating (e.g. {{ .Release.Namespace }}). From beead551218ae7f41e05f85dc210c2cb3d74a533 Mon Sep 17 00:00:00 2001 From: Giulio Calzolari Date: Wed, 1 Apr 2026 20:21:30 +0200 Subject: [PATCH 2/5] feat(chart): per-instance NetworkPolicy for loginsets and nodesets Generate one NetworkPolicy per enabled loginset/nodeset map entry instead of a single blanket policy, scoped via app.kubernetes.io/instance. Move networkPolicy config (enabled, extraIngress, extraEgress) into each map entry and remove the now-redundant top-level nodeset/loginset flags. --- .../networkpolicy/loginset-netpol.yaml | 26 +- .../networkpolicy/nodeset-netpol.yaml | 38 +-- .../__snapshot__/networkpolicy_test.yaml.snap | 6 +- helm/slurm/tests/networkpolicy_test.yaml | 231 ++++++++++++++++-- helm/slurm/values.yaml | 24 +- 5 files changed, 274 insertions(+), 51 deletions(-) diff --git a/helm/slurm/templates/networkpolicy/loginset-netpol.yaml b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml index ee41f2768..09740eef2 100644 --- a/helm/slurm/templates/networkpolicy/loginset-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml @@ -3,18 +3,23 @@ SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. SPDX-License-Identifier: Apache-2.0 */}} -{{- if and .Values.networkPolicy.enabled .Values.networkPolicy.loginset }} +{{- range $key, $loginset := $.Values.loginsets }} +{{- $loginset = mergeOverwrite (dict) (deepCopy ($.Values.loginsetDefaults | default dict)) (deepCopy ($loginset | default dict)) -}} +{{- if and $.Values.networkPolicy.enabled $loginset.enabled (dig "networkPolicy" "enabled" true $loginset) }} +{{- $name := printf "%s-%s" (include "slurm.login.name" $) $key }} +--- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - name: {{ include "slurm.fullname" . }}-loginset - namespace: {{ include "slurm.namespace" . }} + name: {{ $name }} + namespace: {{ include "slurm.namespace" $ }} labels: - {{- include "slurm.labels" . | nindent 4 }} + {{- include "slurm.labels" $ | nindent 4 }} spec: podSelector: matchLabels: app.kubernetes.io/name: login + app.kubernetes.io/instance: {{ $name }} policyTypes: - Ingress - Egress @@ -22,13 +27,16 @@ spec: - ports: - protocol: TCP port: 22 - {{- with .Values.networkPolicy.extraIngress }} + {{- with $.Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with (dig "networkPolicy" "extraIngress" nil $loginset) }} {{- toYaml . | nindent 4 }} {{- end }} egress: - ports: - protocol: TCP - port: {{ include "slurm.controller.port" . }} + port: {{ include "slurm.controller.port" $ }} to: - podSelector: matchLabels: @@ -45,7 +53,11 @@ spec: port: 53 - protocol: TCP port: 53 - {{- with .Values.networkPolicy.extraEgress }} + {{- with $.Values.networkPolicy.extraEgress }} {{- toYaml . | nindent 4 }} {{- end }} + {{- with (dig "networkPolicy" "extraEgress" nil $loginset) }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} {{- end }} diff --git a/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml index 25e6c9056..1655c61da 100644 --- a/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml @@ -3,25 +3,30 @@ SPDX-FileCopyrightText: Copyright (C) SchedMD LLC. SPDX-License-Identifier: Apache-2.0 */}} -{{- if and .Values.networkPolicy.enabled .Values.networkPolicy.nodeset }} +{{- range $key, $nodeset := $.Values.nodesets }} +{{- $nodeset = mergeOverwrite (dict) (deepCopy ($.Values.nodesetDefaults | default dict)) (deepCopy ($nodeset | default dict)) -}} +{{- if and $.Values.networkPolicy.enabled $nodeset.enabled (dig "networkPolicy" "enabled" true $nodeset) }} +{{- $name := printf "%s-%s" (include "slurm.worker.name" $) $key }} +--- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - name: {{ include "slurm.fullname" . }}-nodeset - namespace: {{ include "slurm.namespace" . }} + name: {{ $name }} + namespace: {{ include "slurm.namespace" $ }} labels: - {{- include "slurm.labels" . | nindent 4 }} + {{- include "slurm.labels" $ | nindent 4 }} spec: podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: {{ $name }} policyTypes: - Ingress - Egress ingress: - ports: - protocol: TCP - port: {{ include "slurm.worker.port" . }} + port: {{ include "slurm.worker.port" $ }} from: - podSelector: matchLabels: @@ -29,13 +34,7 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmd - {{- $sshEnabled := false }} - {{- range $key, $nodeset := .Values.nodesets }} - {{- if and $nodeset.enabled (dig "ssh" "enabled" false $nodeset) }} - {{- $sshEnabled = true }} - {{- end }} - {{- end }} - {{- if $sshEnabled }} + {{- if dig "ssh" "enabled" false $nodeset }} - ports: - protocol: TCP port: 22 @@ -44,20 +43,23 @@ spec: matchLabels: app.kubernetes.io/name: login {{- end }} - {{- with .Values.networkPolicy.extraIngress }} + {{- with $.Values.networkPolicy.extraIngress }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with (dig "networkPolicy" "extraIngress" nil $nodeset) }} {{- toYaml . | nindent 4 }} {{- end }} egress: - ports: - protocol: TCP - port: {{ include "slurm.controller.port" . }} + port: {{ include "slurm.controller.port" $ }} to: - podSelector: matchLabels: app.kubernetes.io/name: slurmctld - ports: - protocol: TCP - port: {{ include "slurm.worker.port" . }} + port: {{ include "slurm.worker.port" $ }} to: - podSelector: matchLabels: @@ -67,7 +69,11 @@ spec: port: 53 - protocol: TCP port: 53 - {{- with .Values.networkPolicy.extraEgress }} + {{- with $.Values.networkPolicy.extraEgress }} {{- toYaml . | nindent 4 }} {{- end }} + {{- with (dig "networkPolicy" "extraEgress" nil $nodeset) }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} {{- end }} diff --git a/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap index dabc27a5e..2d683455e 100644 --- a/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap +++ b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap @@ -100,7 +100,7 @@ loginset manifest should match snapshot: app.kubernetes.io/part-of: slurm app.kubernetes.io/version: 1.2.3 helm.sh/chart: slurm-1.2.3 - name: test-release-slurm-loginset + name: test-release-slurm-login-slinky namespace: test-namespace spec: egress: @@ -129,6 +129,7 @@ loginset manifest should match snapshot: protocol: TCP podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-login-slinky app.kubernetes.io/name: login policyTypes: - Ingress @@ -143,7 +144,7 @@ nodeset manifest should match snapshot: app.kubernetes.io/part-of: slurm app.kubernetes.io/version: 1.2.3 helm.sh/chart: slurm-1.2.3 - name: test-release-slurm-nodeset + name: test-release-slurm-worker-slinky namespace: test-namespace spec: egress: @@ -179,6 +180,7 @@ nodeset manifest should match snapshot: protocol: TCP podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-worker-slinky app.kubernetes.io/name: slurmd policyTypes: - Ingress diff --git a/helm/slurm/tests/networkpolicy_test.yaml b/helm/slurm/tests/networkpolicy_test.yaml index 20b9d04c2..0a6b0fb7a 100644 --- a/helm/slurm/tests/networkpolicy_test.yaml +++ b/helm/slurm/tests/networkpolicy_test.yaml @@ -49,12 +49,16 @@ tests: asserts: - matchSnapshot: {} - - it: should not create nodeset networkpolicy when networkPolicy.nodeset is false + - it: should not create nodeset networkpolicy when per-instance networkPolicy.enabled is false template: networkpolicy/nodeset-netpol.yaml set: networkPolicy: enabled: true - nodeset: false + nodesets: + slinky: + enabled: true + networkPolicy: + enabled: false asserts: - hasDocuments: count: 0 @@ -81,11 +85,98 @@ tests: matchLabels: app.kubernetes.io/name: login + - it: nodeset should use per-instance podSelector + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - equal: + path: spec.podSelector.matchLabels + value: + app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: test-release-slurm-worker-slinky + + - it: nodeset should create one networkpolicy per enabled instance + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + nodesets: + gpu: + enabled: true + cpu: + enabled: true + disabled: + enabled: false + asserts: + - hasDocuments: + count: 3 + + - it: loginset manifest should match snapshot + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + loginsets: + slinky: + enabled: true + asserts: + - matchSnapshot: {} + + - it: should not create loginset networkpolicy when per-instance networkPolicy.enabled is false + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + loginsets: + slinky: + enabled: true + networkPolicy: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: loginset should use per-instance podSelector + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + loginsets: + slinky: + enabled: true + asserts: + - equal: + path: spec.podSelector.matchLabels + value: + app.kubernetes.io/name: login + app.kubernetes.io/instance: test-release-slurm-login-slinky + + - it: loginset should create one networkpolicy per enabled instance + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + loginsets: + alpha: + enabled: true + beta: + enabled: true + gamma: + enabled: false + asserts: + - hasDocuments: + count: 2 + - it: loginset should include SSH egress to nodeset template: networkpolicy/loginset-netpol.yaml set: networkPolicy: enabled: true + loginsets: + slinky: + enabled: true asserts: - contains: path: spec.egress @@ -152,24 +243,6 @@ tests: - hasDocuments: count: 0 - - it: loginset manifest should match snapshot - template: networkpolicy/loginset-netpol.yaml - set: - networkPolicy: - enabled: true - asserts: - - matchSnapshot: {} - - - it: should not create loginset networkpolicy when networkPolicy.loginset is false - template: networkpolicy/loginset-netpol.yaml - set: - networkPolicy: - enabled: true - loginset: false - asserts: - - hasDocuments: - count: 0 - - it: controller should include accounting egress when accounting is enabled template: networkpolicy/controller-netpol.yaml set: @@ -222,6 +295,9 @@ tests: port: 9090 accounting: enabled: true + loginsets: + slinky: + enabled: true asserts: - contains: path: spec.ingress @@ -247,6 +323,9 @@ tests: port: 443 accounting: enabled: true + loginsets: + slinky: + enabled: true asserts: - contains: path: spec.egress @@ -362,3 +441,115 @@ tests: ports: - protocol: TCP port: 5432 + + - it: should append nodeset-specific extraIngress + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + nodesets: + slinky: + enabled: true + networkPolicy: + extraIngress: + - from: + - podSelector: + matchLabels: + app: gpu-monitor + ports: + - protocol: TCP + port: 9100 + asserts: + - contains: + path: spec.ingress + content: + from: + - podSelector: + matchLabels: + app: gpu-monitor + ports: + - protocol: TCP + port: 9100 + + - it: should append nodeset-specific extraEgress + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + nodesets: + slinky: + enabled: true + networkPolicy: + extraEgress: + - to: + - ipBlock: + cidr: 10.2.0.0/16 + ports: + - protocol: TCP + port: 2049 + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 10.2.0.0/16 + ports: + - protocol: TCP + port: 2049 + + - it: should append loginset-specific extraIngress + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + loginsets: + slinky: + enabled: true + networkPolicy: + extraIngress: + - from: + - namespaceSelector: + matchLabels: + name: bastion + ports: + - protocol: TCP + port: 22 + asserts: + - contains: + path: spec.ingress + content: + from: + - namespaceSelector: + matchLabels: + name: bastion + ports: + - protocol: TCP + port: 22 + + - it: should append loginset-specific extraEgress + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + loginsets: + slinky: + enabled: true + networkPolicy: + extraEgress: + - to: + - ipBlock: + cidr: 10.3.0.0/16 + ports: + - protocol: TCP + port: 636 + asserts: + - contains: + path: spec.egress + content: + to: + - ipBlock: + cidr: 10.3.0.0/16 + ports: + - protocol: TCP + port: 636 diff --git a/helm/slurm/values.yaml b/helm/slurm/values.yaml index 3d668ca28..b430408c2 100644 --- a/helm/slurm/values.yaml +++ b/helm/slurm/values.yaml @@ -582,6 +582,15 @@ sssd: loginsetDefaults: # -- Enable use of this LoginSet. enabled: true + # NetworkPolicy settings for this LoginSet (applied when the chart-wide + # `networkPolicy.enabled` is true). Can be overridden per LoginSet entry. + networkPolicy: + # -- Enable NetworkPolicy for this LoginSet. + enabled: true + # -- Extra ingress rules appended to this LoginSet NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to this LoginSet NetworkPolicy. + extraEgress: [] # -- Number of replicas to deploy. replicas: 1 # -- Deployment strategy configuration. @@ -701,6 +710,15 @@ loginsets: {} nodesetDefaults: # -- Enable use of this NodeSet. enabled: true + # NetworkPolicy settings for this NodeSet (applied when the chart-wide + # `networkPolicy.enabled` is true). Can be overridden per NodeSet entry. + networkPolicy: + # -- Enable NetworkPolicy for this NodeSet. + enabled: true + # -- Extra ingress rules appended to this NodeSet NetworkPolicy. + extraIngress: [] + # -- Extra egress rules appended to this NodeSet NetworkPolicy. + extraEgress: [] # -- Scaling mode: "StatefulSet" (fixed replica count) or "DaemonSet" (one pod per matching node). scalingMode: StatefulSet # -- Number of replicas to deploy. Ignored when scalingMode is daemonset. @@ -911,12 +929,6 @@ vendor: networkPolicy: # -- Enable NetworkPolicy resources for all Slurm components. enabled: false - # -- Enable NetworkPolicy for NodeSets (slurmd). - # Kept here because `nodesets` is a map and cannot hold a scalar alongside instance entries. - nodeset: true - # -- Enable NetworkPolicy for LoginSets (sackd/sshd). - # Kept here because `loginsets` is a map and cannot hold a scalar alongside instance entries. - loginset: true # -- Extra ingress rules appended to every NetworkPolicy. # Ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#networkpolicyingressrule-v1-networking-k8s-io extraIngress: [] From d25731cde77392da4c4d229dac71ee0f88faf0f0 Mon Sep 17 00:00:00 2001 From: Giulio Calzolari Date: Wed, 8 Apr 2026 13:17:13 +0200 Subject: [PATCH 3/5] feat(chart): add srun/sacct flows and instance-scoped selectors - LoginSet: add all-TCP egress to slurmd (srun), conditional accounting egress (sacct/sacctmgr on TCP 6819) - NodeSet: allow all TCP from slurmd and login pods (srun ephemeral ports), all TCP egress to slurmd - All templates: add app.kubernetes.io/instance to from/to selectors for singleton components (slurmctld, slurmdbd, slurmrestd) --- .../networkpolicy/accounting-netpol.yaml | 3 + .../networkpolicy/controller-netpol.yaml | 4 + .../networkpolicy/loginset-netpol.yaml | 10 ++- .../networkpolicy/nodeset-netpol.yaml | 15 ++-- .../networkpolicy/restapi-netpol.yaml | 2 + .../__snapshot__/networkpolicy_test.yaml.snap | 32 ++++--- helm/slurm/tests/networkpolicy_test.yaml | 89 ++++++++++++++++--- 7 files changed, 121 insertions(+), 34 deletions(-) diff --git a/helm/slurm/templates/networkpolicy/accounting-netpol.yaml b/helm/slurm/templates/networkpolicy/accounting-netpol.yaml index 0446fa397..5339edb77 100644 --- a/helm/slurm/templates/networkpolicy/accounting-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/accounting-netpol.yaml @@ -15,6 +15,7 @@ spec: podSelector: matchLabels: app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} policyTypes: - Ingress - Egress @@ -26,6 +27,7 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmctld + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} {{- with .Values.networkPolicy.extraIngress }} {{- toYaml . | nindent 4 }} {{- end }} @@ -40,6 +42,7 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmctld + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} - ports: - protocol: TCP port: 3306 diff --git a/helm/slurm/templates/networkpolicy/controller-netpol.yaml b/helm/slurm/templates/networkpolicy/controller-netpol.yaml index 8acf6efe4..abe922039 100644 --- a/helm/slurm/templates/networkpolicy/controller-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/controller-netpol.yaml @@ -15,6 +15,7 @@ spec: podSelector: matchLabels: app.kubernetes.io/name: slurmctld + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} policyTypes: - Ingress - Egress @@ -29,9 +30,11 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} - podSelector: matchLabels: app.kubernetes.io/name: slurmrestd + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} - podSelector: matchLabels: app.kubernetes.io/name: login @@ -57,6 +60,7 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} {{- end }} - ports: - protocol: UDP diff --git a/helm/slurm/templates/networkpolicy/loginset-netpol.yaml b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml index 09740eef2..439c23bb9 100644 --- a/helm/slurm/templates/networkpolicy/loginset-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml @@ -41,10 +41,18 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmctld + app.kubernetes.io/instance: {{ include "slurm.fullname" $ }} + {{- if $.Values.accounting.enabled }} - ports: - protocol: TCP - port: 22 + port: 6819 to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: {{ include "slurm.fullname" $ }} + {{- end }} + - to: - podSelector: matchLabels: app.kubernetes.io/name: slurmd diff --git a/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml index 1655c61da..8c29dcbb1 100644 --- a/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml @@ -31,18 +31,15 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmctld + app.kubernetes.io/instance: {{ include "slurm.fullname" $ }} + - from: - podSelector: matchLabels: app.kubernetes.io/name: slurmd - {{- if dig "ssh" "enabled" false $nodeset }} - - ports: - - protocol: TCP - port: 22 - from: + - from: - podSelector: matchLabels: app.kubernetes.io/name: login - {{- end }} {{- with $.Values.networkPolicy.extraIngress }} {{- toYaml . | nindent 4 }} {{- end }} @@ -57,10 +54,8 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmctld - - ports: - - protocol: TCP - port: {{ include "slurm.worker.port" $ }} - to: + app.kubernetes.io/instance: {{ include "slurm.fullname" $ }} + - to: - podSelector: matchLabels: app.kubernetes.io/name: slurmd diff --git a/helm/slurm/templates/networkpolicy/restapi-netpol.yaml b/helm/slurm/templates/networkpolicy/restapi-netpol.yaml index 3a4aead31..2da514953 100644 --- a/helm/slurm/templates/networkpolicy/restapi-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/restapi-netpol.yaml @@ -15,6 +15,7 @@ spec: podSelector: matchLabels: app.kubernetes.io/name: slurmrestd + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} policyTypes: - Ingress - Egress @@ -36,6 +37,7 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: slurmctld + app.kubernetes.io/instance: {{ include "slurm.fullname" . }} - ports: - protocol: UDP port: 53 diff --git a/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap index 2d683455e..670983ddb 100644 --- a/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap +++ b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap @@ -18,6 +18,7 @@ accounting manifest should match snapshot: to: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmctld - ports: - port: 3306 @@ -31,12 +32,14 @@ accounting manifest should match snapshot: - from: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmctld ports: - port: 6819 protocol: TCP podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmdbd policyTypes: - Ingress @@ -74,9 +77,11 @@ controller manifest should match snapshot: app.kubernetes.io/name: slurmd - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmdbd - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmrestd - podSelector: matchLabels: @@ -86,6 +91,7 @@ controller manifest should match snapshot: protocol: TCP podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmctld policyTypes: - Ingress @@ -110,11 +116,9 @@ loginset manifest should match snapshot: to: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmctld - - ports: - - port: 22 - protocol: TCP - to: + - to: - podSelector: matchLabels: app.kubernetes.io/name: slurmd @@ -154,11 +158,9 @@ nodeset manifest should match snapshot: to: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmctld - - ports: - - port: 6818 - protocol: TCP - to: + - to: - podSelector: matchLabels: app.kubernetes.io/name: slurmd @@ -171,13 +173,19 @@ nodeset manifest should match snapshot: - from: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmctld - - podSelector: - matchLabels: - app.kubernetes.io/name: slurmd ports: - port: 6818 protocol: TCP + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: login podSelector: matchLabels: app.kubernetes.io/instance: test-release-slurm-worker-slinky @@ -205,6 +213,7 @@ restapi manifest should match snapshot: to: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmctld - ports: - port: 53 @@ -217,6 +226,7 @@ restapi manifest should match snapshot: protocol: TCP podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm app.kubernetes.io/name: slurmrestd policyTypes: - Ingress diff --git a/helm/slurm/tests/networkpolicy_test.yaml b/helm/slurm/tests/networkpolicy_test.yaml index 0a6b0fb7a..a21239b82 100644 --- a/helm/slurm/tests/networkpolicy_test.yaml +++ b/helm/slurm/tests/networkpolicy_test.yaml @@ -63,28 +63,48 @@ tests: - hasDocuments: count: 0 - - it: nodeset should include SSH ingress from login when ssh is enabled + - it: nodeset should allow all TCP ingress from login pods template: networkpolicy/nodeset-netpol.yaml set: networkPolicy: enabled: true - nodesets: - slinky: - enabled: true - ssh: - enabled: true asserts: - contains: path: spec.ingress content: - ports: - - protocol: TCP - port: 22 from: - podSelector: matchLabels: app.kubernetes.io/name: login + - it: nodeset should allow all TCP ingress from slurmd pods + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - contains: + path: spec.ingress + content: + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + + - it: nodeset should allow all TCP egress to slurmd pods + template: networkpolicy/nodeset-netpol.yaml + set: + networkPolicy: + enabled: true + asserts: + - contains: + path: spec.egress + content: + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + - it: nodeset should use per-instance podSelector template: networkpolicy/nodeset-netpol.yaml set: @@ -169,7 +189,7 @@ tests: - hasDocuments: count: 2 - - it: loginset should include SSH egress to nodeset + - it: loginset should allow all TCP egress to nodeset template: networkpolicy/loginset-netpol.yaml set: networkPolicy: @@ -177,17 +197,60 @@ tests: loginsets: slinky: enabled: true + asserts: + - contains: + path: spec.egress + content: + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmd + + - it: loginset should include accounting egress when accounting is enabled + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: true + loginsets: + slinky: + enabled: true asserts: - contains: path: spec.egress content: ports: - protocol: TCP - port: 22 + port: 6819 to: - podSelector: matchLabels: - app.kubernetes.io/name: slurmd + app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: test-release-slurm + + - it: loginset should not include accounting egress when accounting is disabled + template: networkpolicy/loginset-netpol.yaml + set: + networkPolicy: + enabled: true + accounting: + enabled: false + loginsets: + slinky: + enabled: true + asserts: + - notContains: + path: spec.egress + content: + ports: + - protocol: TCP + port: 6819 + to: + - podSelector: + matchLabels: + app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: test-release-slurm - it: accounting manifest should match snapshot template: networkpolicy/accounting-netpol.yaml @@ -261,6 +324,7 @@ tests: - podSelector: matchLabels: app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: test-release-slurm - it: controller should not include accounting egress when accounting is disabled template: networkpolicy/controller-netpol.yaml @@ -280,6 +344,7 @@ tests: - podSelector: matchLabels: app.kubernetes.io/name: slurmdbd + app.kubernetes.io/instance: test-release-slurm - it: should append global extraIngress to all networkpolicies set: From 48df1b6394f4d5a48d3a52cb1589bd706e9058ee Mon Sep 17 00:00:00 2001 From: Giulio Calzolari Date: Wed, 8 Apr 2026 13:27:09 +0200 Subject: [PATCH 4/5] feat(chart): use per-instance app.kubernetes.io/instance in all selectors Singletons (slurmctld, slurmdbd, slurmrestd) use slurm.fullname as instance. Map components (slurmd, login) iterate over the map to generate per-instance from/to entries with the CR name as instance. Accounting ingress now also allows from loginset pods (sacct/sacctmgr). Signed-off-by: Giulio Calzolari --- .../networkpolicy/accounting-netpol.yaml | 9 ++++ .../networkpolicy/controller-netpol.yaml | 18 +++++++ .../networkpolicy/loginset-netpol.yaml | 6 +++ .../networkpolicy/nodeset-netpol.yaml | 18 +++++++ .../__snapshot__/networkpolicy_test.yaml.snap | 7 +++ helm/slurm/tests/networkpolicy_test.yaml | 49 +++++++++++++++++-- 6 files changed, 104 insertions(+), 3 deletions(-) diff --git a/helm/slurm/templates/networkpolicy/accounting-netpol.yaml b/helm/slurm/templates/networkpolicy/accounting-netpol.yaml index 5339edb77..9f51c5835 100644 --- a/helm/slurm/templates/networkpolicy/accounting-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/accounting-netpol.yaml @@ -28,6 +28,15 @@ spec: matchLabels: app.kubernetes.io/name: slurmctld app.kubernetes.io/instance: {{ include "slurm.fullname" . }} + {{- range $key, $loginset := .Values.loginsets }} + {{- $loginset = mergeOverwrite (dict) (deepCopy ($.Values.loginsetDefaults | default dict)) (deepCopy ($loginset | default dict)) -}} + {{- if $loginset.enabled }} + - podSelector: + matchLabels: + app.kubernetes.io/name: login + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.login.name" $) $key }} + {{- end }} + {{- end }} {{- with .Values.networkPolicy.extraIngress }} {{- toYaml . | nindent 4 }} {{- end }} diff --git a/helm/slurm/templates/networkpolicy/controller-netpol.yaml b/helm/slurm/templates/networkpolicy/controller-netpol.yaml index abe922039..6054cb1c2 100644 --- a/helm/slurm/templates/networkpolicy/controller-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/controller-netpol.yaml @@ -24,9 +24,15 @@ spec: - protocol: TCP port: {{ include "slurm.controller.port" . }} from: + {{- range $key, $nodeset := .Values.nodesets }} + {{- $nodeset = mergeOverwrite (dict) (deepCopy ($.Values.nodesetDefaults | default dict)) (deepCopy ($nodeset | default dict)) -}} + {{- if $nodeset.enabled }} - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.worker.name" $) $key }} + {{- end }} + {{- end }} - podSelector: matchLabels: app.kubernetes.io/name: slurmdbd @@ -35,9 +41,15 @@ spec: matchLabels: app.kubernetes.io/name: slurmrestd app.kubernetes.io/instance: {{ include "slurm.fullname" . }} + {{- range $key, $loginset := .Values.loginsets }} + {{- $loginset = mergeOverwrite (dict) (deepCopy ($.Values.loginsetDefaults | default dict)) (deepCopy ($loginset | default dict)) -}} + {{- if $loginset.enabled }} - podSelector: matchLabels: app.kubernetes.io/name: login + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.login.name" $) $key }} + {{- end }} + {{- end }} {{- with .Values.networkPolicy.extraIngress }} {{- toYaml . | nindent 4 }} {{- end }} @@ -49,9 +61,15 @@ spec: - protocol: TCP port: {{ include "slurm.worker.port" . }} to: + {{- range $key, $nodeset := .Values.nodesets }} + {{- $nodeset = mergeOverwrite (dict) (deepCopy ($.Values.nodesetDefaults | default dict)) (deepCopy ($nodeset | default dict)) -}} + {{- if $nodeset.enabled }} - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.worker.name" $) $key }} + {{- end }} + {{- end }} {{- if .Values.accounting.enabled }} - ports: - protocol: TCP diff --git a/helm/slurm/templates/networkpolicy/loginset-netpol.yaml b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml index 439c23bb9..92f04d91e 100644 --- a/helm/slurm/templates/networkpolicy/loginset-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/loginset-netpol.yaml @@ -53,9 +53,15 @@ spec: app.kubernetes.io/instance: {{ include "slurm.fullname" $ }} {{- end }} - to: + {{- range $nk, $ns := $.Values.nodesets }} + {{- $ns = mergeOverwrite (dict) (deepCopy ($.Values.nodesetDefaults | default dict)) (deepCopy ($ns | default dict)) -}} + {{- if $ns.enabled }} - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.worker.name" $) $nk }} + {{- end }} + {{- end }} - ports: - protocol: UDP port: 53 diff --git a/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml index 8c29dcbb1..04342c1e0 100644 --- a/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml +++ b/helm/slurm/templates/networkpolicy/nodeset-netpol.yaml @@ -33,13 +33,25 @@ spec: app.kubernetes.io/name: slurmctld app.kubernetes.io/instance: {{ include "slurm.fullname" $ }} - from: + {{- range $nk, $ns := $.Values.nodesets }} + {{- $ns = mergeOverwrite (dict) (deepCopy ($.Values.nodesetDefaults | default dict)) (deepCopy ($ns | default dict)) -}} + {{- if $ns.enabled }} - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.worker.name" $) $nk }} + {{- end }} + {{- end }} - from: + {{- range $lk, $ls := $.Values.loginsets }} + {{- $ls = mergeOverwrite (dict) (deepCopy ($.Values.loginsetDefaults | default dict)) (deepCopy ($ls | default dict)) -}} + {{- if $ls.enabled }} - podSelector: matchLabels: app.kubernetes.io/name: login + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.login.name" $) $lk }} + {{- end }} + {{- end }} {{- with $.Values.networkPolicy.extraIngress }} {{- toYaml . | nindent 4 }} {{- end }} @@ -56,9 +68,15 @@ spec: app.kubernetes.io/name: slurmctld app.kubernetes.io/instance: {{ include "slurm.fullname" $ }} - to: + {{- range $nk, $ns := $.Values.nodesets }} + {{- $ns = mergeOverwrite (dict) (deepCopy ($.Values.nodesetDefaults | default dict)) (deepCopy ($ns | default dict)) -}} + {{- if $ns.enabled }} - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: {{ printf "%s-%s" (include "slurm.worker.name" $) $nk }} + {{- end }} + {{- end }} - ports: - protocol: UDP port: 53 diff --git a/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap index 670983ddb..9517dd81a 100644 --- a/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap +++ b/helm/slurm/tests/__snapshot__/networkpolicy_test.yaml.snap @@ -64,6 +64,7 @@ controller manifest should match snapshot: to: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-worker-slinky app.kubernetes.io/name: slurmd - ports: - port: 53 @@ -74,6 +75,7 @@ controller manifest should match snapshot: - from: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-worker-slinky app.kubernetes.io/name: slurmd - podSelector: matchLabels: @@ -85,6 +87,7 @@ controller manifest should match snapshot: app.kubernetes.io/name: slurmrestd - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-login-slinky app.kubernetes.io/name: login ports: - port: 6817 @@ -121,6 +124,7 @@ loginset manifest should match snapshot: - to: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-worker-slinky app.kubernetes.io/name: slurmd - ports: - port: 53 @@ -163,6 +167,7 @@ nodeset manifest should match snapshot: - to: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-worker-slinky app.kubernetes.io/name: slurmd - ports: - port: 53 @@ -181,10 +186,12 @@ nodeset manifest should match snapshot: - from: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-worker-slinky app.kubernetes.io/name: slurmd - from: - podSelector: matchLabels: + app.kubernetes.io/instance: test-release-slurm-login-slinky app.kubernetes.io/name: login podSelector: matchLabels: diff --git a/helm/slurm/tests/networkpolicy_test.yaml b/helm/slurm/tests/networkpolicy_test.yaml index a21239b82..7db8d20ef 100644 --- a/helm/slurm/tests/networkpolicy_test.yaml +++ b/helm/slurm/tests/networkpolicy_test.yaml @@ -26,6 +26,12 @@ tests: set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true + loginsets: + slinky: + enabled: true asserts: - matchSnapshot: {} @@ -46,6 +52,12 @@ tests: set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true + loginsets: + slinky: + enabled: true asserts: - matchSnapshot: {} @@ -68,6 +80,12 @@ tests: set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true + loginsets: + slinky: + enabled: true asserts: - contains: path: spec.ingress @@ -76,12 +94,16 @@ tests: - podSelector: matchLabels: app.kubernetes.io/name: login + app.kubernetes.io/instance: test-release-slurm-login-slinky - it: nodeset should allow all TCP ingress from slurmd pods template: networkpolicy/nodeset-netpol.yaml set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true asserts: - contains: path: spec.ingress @@ -90,12 +112,16 @@ tests: - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: test-release-slurm-worker-slinky - it: nodeset should allow all TCP egress to slurmd pods template: networkpolicy/nodeset-netpol.yaml set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true asserts: - contains: path: spec.egress @@ -104,12 +130,16 @@ tests: - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: test-release-slurm-worker-slinky - - it: nodeset should use per-instance podSelector + - it: nodeset podSelector should use CR name as instance template: networkpolicy/nodeset-netpol.yaml set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true asserts: - equal: path: spec.podSelector.matchLabels @@ -131,13 +161,16 @@ tests: enabled: false asserts: - hasDocuments: - count: 3 + count: 2 - it: loginset manifest should match snapshot template: networkpolicy/loginset-netpol.yaml set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true loginsets: slinky: enabled: true @@ -158,7 +191,7 @@ tests: - hasDocuments: count: 0 - - it: loginset should use per-instance podSelector + - it: loginset podSelector should use CR name as instance template: networkpolicy/loginset-netpol.yaml set: networkPolicy: @@ -194,6 +227,9 @@ tests: set: networkPolicy: enabled: true + nodesets: + slinky: + enabled: true loginsets: slinky: enabled: true @@ -205,6 +241,7 @@ tests: - podSelector: matchLabels: app.kubernetes.io/name: slurmd + app.kubernetes.io/instance: test-release-slurm-worker-slinky - it: loginset should include accounting egress when accounting is enabled template: networkpolicy/loginset-netpol.yaml @@ -360,6 +397,9 @@ tests: port: 9090 accounting: enabled: true + nodesets: + slinky: + enabled: true loginsets: slinky: enabled: true @@ -388,6 +428,9 @@ tests: port: 443 accounting: enabled: true + nodesets: + slinky: + enabled: true loginsets: slinky: enabled: true From 33c42b790a322ca4a5e53c0aa2b24b9ae33fe2fc Mon Sep 17 00:00:00 2001 From: Giulio Calzolari Date: Thu, 25 Jun 2026 20:27:43 +0200 Subject: [PATCH 5/5] docs: add NetworkPolicy usage guide with traffic diagram Document the opt-in NetworkPolicy templates as project documentation, including the component traffic mermaid diagram, enable/disable toggles, extra rule levels, and srun ephemeral-port guidance. Signed-off-by: Giulio Calzolari --- docs/usage/network-policies.md | 148 +++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 docs/usage/network-policies.md diff --git a/docs/usage/network-policies.md b/docs/usage/network-policies.md new file mode 100644 index 000000000..25c6c86c5 --- /dev/null +++ b/docs/usage/network-policies.md @@ -0,0 +1,148 @@ +# Network Policies + +## Table of Contents + + + +- [Network Policies](#network-policies) + - [Table of Contents](#table-of-contents) + - [Overview](#overview) + - [Component Traffic Diagram](#component-traffic-diagram) + - [Enabling Network Policies](#enabling-network-policies) + - [Per-Component and Per-Instance Toggles](#per-component-and-per-instance-toggles) + - [Extra Rules](#extra-rules) + - [srun and Ephemeral Ports](#srun-and-ephemeral-ports) + - [Caveats](#caveats) + + + +## Overview + +Both the `slurm-operator` and `slurm` Helm charts can render opt-in Kubernetes +[NetworkPolicy] resources that isolate each Slurm component at the network +layer. Policies are **disabled by default** and are enabled through the +`networkPolicy.enabled` value in each chart. + +When enabled, every component only accepts the ingress it needs and is only +allowed to reach the peers it must talk to (plus DNS). The diagram below +captures the intended communication boundaries between all components. + +## Component Traffic Diagram + +```mermaid +flowchart LR + subgraph kube [Kubernetes Control Plane] + kubeapi["Kube API Server (443)"] + end + subgraph operator [Slurm Operator] + op["Operator (metrics:8080)"] + wh["Webhook (server:9443)"] + end + subgraph slurm [Slurm Cluster] + ctrl["Controller (slurmctld:6817)"] + worker["NodeSet (slurmd:6818, srun:*, ssh:22)"] + acct["Accounting (slurmdbd:6819)"] + rest["RestApi (slurmrestd:6820)"] + login["LoginSet (ssh:22)"] + end + db["External DB (3306)"] + users["Users / Clients"] + + worker <-->|"6817 / 6818"| ctrl + worker <-->|"all TCP (srun)"| worker + acct <-->|"6817 / 6819"| ctrl + rest -->|"6817"| ctrl + login -->|"6817"| ctrl + login -->|"6819 (sacct)"| acct + login -->|"all TCP (srun/ssh)"| worker + op -->|"6820"| rest + op -->|"443"| kubeapi + wh -->|"443"| kubeapi + kubeapi -->|"9443"| wh + acct -->|"3306"| db + users -->|"6820"| rest + users -->|"22"| login +``` + +## Enabling Network Policies + +Enable the policies per chart with the global toggle: + +```sh +# slurm chart (controller, nodeset, accounting, restapi, loginset) +helm upgrade slurm oci://ghcr.io/slinkyproject/charts/slurm \ + --namespace slurm --set networkPolicy.enabled=true + +# slurm-operator chart (operator, webhook) +helm upgrade slurm-operator oci://ghcr.io/slinkyproject/charts/slurm-operator \ + --namespace slinky --set networkPolicy.enabled=true +``` + +DNS resolution (UDP/TCP 53) is always permitted as egress so the components can +resolve in-cluster service names. + +## Per-Component and Per-Instance Toggles + +Once the global toggle is on, each component can be disabled individually: + +- Singleton components (`controller`, `restapi`, `accounting`, `operator`, + `webhook`) expose `.networkPolicy.enabled`. +- Map components (`nodesets`, `loginsets`) expose a per-instance + `networkPolicy.enabled` flag inside each map entry, defaulting to the value in + `nodesetDefaults` / `loginsetDefaults`. One NetworkPolicy is generated per + enabled instance, scoped via the `app.kubernetes.io/instance` label. + +```yaml +networkPolicy: + enabled: true +nodesets: + gpu: + networkPolicy: + enabled: false # disable just this NodeSet's policy +``` + +## Extra Rules + +Additional ingress/egress rules can be appended at three levels: + +- Global: `networkPolicy.extraIngress` / `networkPolicy.extraEgress` (applied to + every policy in the chart). +- Per-component: `.networkPolicy.extraIngress` / + `extraEgress`. +- Per-instance: inside each `nodesets` / `loginsets` map entry under + `networkPolicy.extraIngress` / `extraEgress`. + +```yaml +networkPolicy: + enabled: true + extraEgress: + - to: + - ipBlock: + cidr: 10.0.0.0/8 + ports: + - protocol: TCP + port: 443 +``` + +## srun and Ephemeral Ports + +`srun` opens ephemeral ports for interactive job I/O. To keep these flows +working, the policies allow **all TCP** between `slurmd` <-> `slurmd` and from +`login` -> `slurmd`. In hardened environments, constrain this range with +[`SrunPortRange`] in `slurm.conf` and tighten the corresponding `extraIngress` +/ `extraEgress` rules accordingly. + +## Caveats + +- Policies use the `app.kubernetes.io/name` and `app.kubernetes.io/instance` + labels applied by the operator; a CNI that enforces NetworkPolicy is required. +- Non-default ports (Slurm, ssh, mariadb) must be reflected in your values; the + policies follow the ports configured for each component. +- The operator-to-`slurmrestd` egress uses an empty `namespaceSelector` to + support deployments where the operator and Slurm cluster live in different + namespaces. + + + +[NetworkPolicy]: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +[`SrunPortRange`]: https://slurm.schedmd.com/slurm.conf.html#OPT_SrunPortRange