diff --git a/library/common-test/tests/pod/securityContext.yaml b/library/common-test/tests/pod/securityContext.yaml index 9b9ec45a19..0e0c4416c6 100644 --- a/library/common-test/tests/pod/securityContext.yaml +++ b/library/common-test/tests/pod/securityContext.yaml @@ -12,10 +12,10 @@ tests: - 1000 - 1001 sysctls: - - name: net.ipv4.ip_forward - value: "1" - - name: net.ipv4.ping_group_range - value: "0 65535" + - name: some_name + value: "some_value" + - name: some_other_name + value: "some_other_value" workload: workload-name1: enabled: true @@ -36,10 +36,10 @@ tests: - 1000 - 1001 sysctls: - - name: net.ipv4.ip_forward - value: "1" - - name: net.ipv4.ping_group_range - value: "0 65535" + - name: some_name + value: "some_value" + - name: some_other_name + value: "some_other_value" - it: should pass with securityContext from "global" and partial override with "pod" set: @@ -51,10 +51,10 @@ tests: - 1000 - 1001 sysctls: - - name: net.ipv4.ip_forward - value: "1" - - name: net.ipv4.ping_group_range - value: "0 65535" + - name: some_name + value: "some_value" + - name: some_other_name + value: "some_other_value" workload: workload-name1: enabled: true @@ -77,14 +77,14 @@ tests: - 1000 - 1001 sysctls: - - name: net.ipv4.ip_forward - value: "1" - - name: net.ipv4.ping_group_range - value: "0 65535" + - name: some_name + value: "some_value" + - name: some_other_name + value: "some_other_value" - it: should pass with securityContext from "global" and full override with "pod" set: - some_sysctl_name: net.ipv4.ip_forward + some_sysctl_name: some_name some_sysctl_value: 2 securityContext: pod: @@ -94,10 +94,10 @@ tests: - 1000 - 1001 sysctls: - - name: net.ipv4.ip_forward - value: "1" - - name: net.ipv4.ping_group_range - value: "0 65535" + - name: some_name + value: "some_value" + - name: some_other_name + value: "some_other_value" workload: workload-name1: enabled: true @@ -113,8 +113,8 @@ tests: sysctls: - name: "{{ .Values.some_sysctl_name }}" value: "{{ .Values.some_sysctl_value }}" - - name: net.ipv4.ping_group_range - value: "1 65534" + - name: some_other_name + value: "some_different_value" asserts: - documentIndex: &statefulSetDoc 0 isKind: @@ -129,13 +129,102 @@ tests: - 1002 - 1003 sysctls: - - name: net.ipv4.ip_forward + - name: some_name value: "2" + - name: some_other_name + value: "some_different_value" + + - it: should pass with sysctls automatically appended based on services + set: + some_sysctl_name: some_name + some_sysctl_value: 2 + workload: + workload-name1: + enabled: true + primary: true + type: StatefulSet + podSpec: + securityContext: + fsGroup: 1001 + fsGroupChangePolicy: Always + supplementalGroups: + - 1002 + - 1003 + sysctls: + - name: "{{ .Values.some_sysctl_name }}" + value: "{{ .Values.some_sysctl_value }}" + - name: some_other_name + value: "some_different_value" + workload-name2: + enabled: true + type: StatefulSet + podSpec: {} + service: + service-name1: + enabled: true + primary: true + type: ClusterIP + ports: + port-name: + enabled: true + primary: true + port: 80 + service-name2: + enabled: true + type: ClusterIP + ports: + port-name: + enabled: true + primary: true + port: 53 + service-name3: + enabled: true + type: ClusterIP + targetSelector: workload-name2 + ports: + port-name: + enabled: true + primary: true + port: 443 + asserts: + - documentIndex: &statefulSetDoc 0 + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.template.spec.securityContext + value: + fsGroup: 1001 + fsGroupChangePolicy: Always + supplementalGroups: + - 1002 + - 1003 + sysctls: + - name: some_name + value: "2" + - name: some_other_name + value: "some_different_value" + - name: net.ipv4.ip_unprivileged_port_start + value: "53" - name: net.ipv4.ping_group_range - value: "1 65534" - -# Failures + value: "53 80" + - documentIndex: &otherStatefulSetDoc 1 + isKind: + of: StatefulSet + - documentIndex: *otherStatefulSetDoc + equal: + path: spec.template.spec.securityContext + value: + fsGroup: 568 + fsGroupChangePolicy: OnRootMismatch + supplementalGroups: [] + sysctls: + - name: net.ipv4.ip_unprivileged_port_start + value: "443" + - name: net.ipv4.ping_group_range + value: "443 443" + # Failures - it: should fail with empty securityContext from "global" set: securityContext: @@ -205,7 +294,7 @@ tests: fsGroupChangePolicy: OnRootMismatch sysctls: - name: "" - value: "1" + value: "some_value" workload: workload-name1: enabled: true @@ -223,7 +312,7 @@ tests: fsGroup: 568 fsGroupChangePolicy: OnRootMismatch sysctls: - - name: net.ipv4.ip_forward + - name: some_name value: "" workload: workload-name1: diff --git a/library/common/1.0.0/docs/workload.md b/library/common/1.0.0/docs/workload.md index 4e3b04829c..38fe93be13 100644 --- a/library/common/1.0.0/docs/workload.md +++ b/library/common/1.0.0/docs/workload.md @@ -48,6 +48,8 @@ Notes > `dnsPolicy` is set automatically to `ClusterFirstWithHostNet` when `hostNetwork` is `true` > `runtimeClassName` will ignore any value set and use the `.Values.global.ixChartContext.nvidiaRuntimeClassName`, > if a GPU is assigned to a container and Scale Middleware sets `.Values.global.ixChartContext.addNvidiaRuntimeClass` to `true`. > Note that it will only set the `runtimeClassName` on the pod that this container belongs to. +> **sysctl** `net.ipv4.ip_unprivileged_port_start` will be automatically set to the lowest `targetPort` (or `port` if targetPort is not defined) number assigned to the pod. +> **sysctl** `net.ipv4.ping_group_range` will be automatically set to the lowest and highest `targetPort` (or `port` if targetPort is not defined) number assigned to the pod. --- diff --git a/library/common/1.0.0/templates/lib/pod/_podSecurityContext.tpl b/library/common/1.0.0/templates/lib/pod/_podSecurityContext.tpl index 25556d7af9..dad6ac4ef4 100644 --- a/library/common/1.0.0/templates/lib/pod/_podSecurityContext.tpl +++ b/library/common/1.0.0/templates/lib/pod/_podSecurityContext.tpl @@ -22,12 +22,14 @@ objectData: The object data to be used to render the Pod. {{/* TODO: Add supplemental groups scaleGPU (44) (Only when GPU is enabled on the pod's containers) - devices (5, 10, 20, 24) (Only when devices is assigned on the pod's containers) */}} - {{/* TODO: Add sysctls - net.ipv4.ip_unprivileged_port_start: (Set to the lowest port on the pod's containers) - net.ipv4.ping_group_range: (Set to the lowest port and highest port on the pod's containers) + devices (5, 10, 20, 24) (Only when devices is assigned on the pod's containers) TODO: Unit Test the above cases - */}} + */}} + {{- $portRange := fromJson (include "ix.v1.common.lib.pod.securityContext.getPortRange" (dict "rootCtx" $rootCtx "objectData" $objectData)) -}} + {{- if and $portRange.low $portRange.high -}} + {{- $_ := set $secContext "sysctls" (mustAppend $secContext.sysctls (dict "name" "net.ipv4.ip_unprivileged_port_start" "value" (printf "%v" $portRange.low))) -}} + {{- $_ := set $secContext "sysctls" (mustAppend $secContext.sysctls (dict "name" "net.ipv4.ping_group_range" "value" (printf "%v %v" $portRange.low $portRange.high))) -}} + {{- end -}} {{- if not $secContext.fsGroup -}} {{- fail "Pod - Expected non-empty " -}} @@ -67,3 +69,64 @@ sysctls: sysctls: [] {{- end -}} {{- end -}} + +{{/* Returns Lowest and Highest ports assigned to the any container in the pod */}} +{{/* Call this template: +{{ include "ix.v1.common.lib.pod.securityContext.getPortRange" (dict "rootCtx" $ "objectData" $objectData) }} +rootCtx: The root context of the template. It is used to access the global context. +objectData: The object data to be used to render the Pod. +*/}} +{{- define "ix.v1.common.lib.pod.securityContext.getPortRange" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{ $portRange := (dict "high" 0 "low" 0) }} + + {{- range $name, $service := $rootCtx.Values.service -}} + {{- $selected := false -}} + {{/* If service is enabled... */}} + {{- if $service.enabled -}} + + {{/* If there is a selector */}} + {{- if $service.targetSelector -}} + + {{/* And pod is selected */}} + {{- if eq $service.targetSelector $objectData.shortName -}} + {{- $selected = true -}} + {{- end -}} + + {{- else -}} + {{/* If no selector is defined but pod is primary */}} + {{- if $objectData.primary -}} + {{- $selected = true -}} + {{- end -}} + + {{- end -}} + {{- end -}} + + {{- if $selected -}} + {{- range $name, $portValues := $service.ports -}} + {{- if $portValues.enabled -}} + + {{- $portToCheck := ($portValues.targetPort | default $portValues.port) -}} + {{- if kindIs "string" $portToCheck -}} + {{/* Helm stores ints as floats, so convert string to float before comparing */}} + {{- $portToCheck = (tpl $portToCheck $rootCtx) | float64 -}} + {{- end -}} + + {{- if or (not $portRange.low) (lt $portToCheck $portRange.low) -}} + {{- $_ := set $portRange "low" $portToCheck -}} + {{- end -}} + + {{- if or (not $portRange.high) (gt $portToCheck $portRange.high) -}} + {{- $_ := set $portRange "high" $portToCheck -}} + {{- end -}} + + {{- end -}} + {{- end -}} + {{- end -}} + + {{- end -}} + + {{- $portRange | toJson -}} +{{- end -}}