Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ spec:
{{- toYaml . | nindent 12 }}
{{- end }}
securityContext:
runAsNonRoot: true
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ spec:
app.kubernetes.io/component: account-bootstrap
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
serviceAccountName: nvcf-api-account-bootstrap
{{- with .Values.api.accountBootstrap.schedulingGates }}
schedulingGates:
Expand All @@ -64,6 +68,13 @@ spec:
- name: account-bootstrap-creator
image: "{{ include "nvcf-api.accountBootstrapImage" . }}"
imagePullPolicy: {{ .Values.api.accountBootstrap.image.pullPolicy }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
command: ["/bin/bash"]
args: ["/scripts/account-bootstrap.sh"]
volumeMounts:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ assert_image() {

render_job "$work_dir/default.yaml"
assert_image "$work_dir/default.yaml" "docker.io/alpine/k8s:1.37.0"
test "$(yq -r '.spec.template.spec.containers[0].securityContext.runAsNonRoot' "$work_dir/default.yaml")" = true
test "$(yq -r '.spec.template.spec.containers[0].securityContext.runAsUser' "$work_dir/default.yaml")" = 1000

render_job "$work_dir/partial-override.yaml" \
--set-string api.accountBootstrap.image.repository=mirror/alpine-k8s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ spec:
{{- end }}
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 100
runAsGroup: 1000
serviceAccountName: {{ .Values.sis.lls.hmacRotation.serviceAccountName }}
{{- with (include "sis.imagePullSecrets" .) }}
imagePullSecrets:
Expand All @@ -44,6 +48,11 @@ spec:
- name: addons-lls-migrations
image: "{{ include "sis.image.full" (dict "image" .Values.sis.lls.hmacRotation.image "name" "sis.lls.hmacRotation.image") }}"
imagePullPolicy: {{ .Values.sis.lls.hmacRotation.image.pullPolicy }}
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
env:
- name: CORE_MIGRATIONS_ENABLED
value: "false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ spec:
{{- end }}
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 100
runAsGroup: 1000
serviceAccountName: {{ $pki.serviceAccountName }}
{{- with $pki.imagePullSecrets }}
imagePullSecrets:
Expand All @@ -53,6 +57,11 @@ spec:
- name: addons-llm-migrations
image: "{{ include "llm-request-router.pkiMigrationsImage" . }}"
imagePullPolicy: {{ $pki.image.pullPolicy }}
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
env:
- name: CORE_MIGRATIONS_ENABLED
value: "false"
Expand Down
6 changes: 6 additions & 0 deletions deploy/helm/nats/scripts/test-render-auth-callout.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ assert_not_contains() {

default_render="$tmpdir/default.yaml"
render > "$default_render"
test "$(yq -r 'select(.kind == "StatefulSet") | .spec.template.spec.securityContext.runAsUser' "$default_render")" = 1000
test "$(yq -r 'select(.kind == "StatefulSet") | .spec.template.spec.securityContext.fsGroup' "$default_render")" = 1000
for container in nats reloader; do
test "$(yq -r "select(.kind == \"StatefulSet\") | .spec.template.spec.containers[] | select(.name == \"$container\") | .securityContext.runAsNonRoot" "$default_render")" = true
test "$(yq -r "select(.kind == \"StatefulSet\") | .spec.template.spec.containers[] | select(.name == \"$container\") | .securityContext.runAsUser" "$default_render")" = 1000
done
reloader_image="$(yq -r '.nats.reloader.image.registry + "/" + .nats.reloader.image.repository + ":" + .nats.reloader.image.tag' "$chart_dir/values.yaml")"
assert_contains "$default_render" "image: $reloader_image"
assert_contains "$default_render" "# Source: helm-nvcf-nats/templates/nats-auth-callout-nkeys-secret.yaml"
Expand Down
25 changes: 25 additions & 0 deletions deploy/helm/nats/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ nats:
registry: ""
pullPolicy: IfNotPresent
container:
merge:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
image:
registry: ""
repository: ""
Expand Down Expand Up @@ -77,6 +85,14 @@ nats:
value: "/healthz?js-server-only=true"
reloader:
enabled: true
merge:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
image:
registry: docker.io
repository: natsio/nats-server-config-reloader
Expand All @@ -96,6 +112,15 @@ nats:
nkey:
secretName: nats-nkeys
key: user.key
podTemplate:
merge:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
# Auth callout NKey bootstrap.
# The default secret name is shared with openbao-migrations; override it only
# when every downstream consumer is configured to read the same Secret.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
securityContext:
runAsNonRoot: true
runAsUser: 100
runAsGroup: 1000
{{- with .Values.openbao.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
Expand All @@ -48,6 +52,11 @@ spec:
containers:
- name: bao-init
image: "{{ include "openbao.image" (dict "image" .Values.openbao.migrations.image "name" "openbao.migrations.image") }}"
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
command: ["/bin/bash"]
args:
- -c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
securityContext:
runAsNonRoot: true
runAsUser: 100
runAsGroup: 1000
automountServiceAccountToken: false
{{- with .Values.openbao.global.imagePullSecrets }}
imagePullSecrets:
Expand All @@ -50,6 +54,11 @@ spec:
# registered before the OnDelete StatefulSet is manually rotated.
image: "{{ include "openbao.image" (dict "image" .Values.openbao.server.image "name" "openbao.server.image") }}"
imagePullPolicy: {{ .Values.openbao.server.image.pullPolicy }}
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
command: ["/bin/sh", "-ec"]
args:
- |-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
securityContext:
runAsNonRoot: true
runAsUser: 100
runAsGroup: 1000
{{- with .Values.openbao.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
Expand All @@ -45,6 +49,11 @@ spec:
containers:
- name: bao-migrations
image: "{{ include "openbao.image" (dict "image" .Values.openbao.migrations.image "name" "openbao.migrations.image") }}"
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
imagePullPolicy: {{ .Values.openbao.migrations.image.pullPolicy }}
volumeMounts:
- name: {{ $serverFullname }}-root-token
Expand Down
5 changes: 5 additions & 0 deletions deploy/helm/openbao/tests/plugin-catalog-refresh-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ helm dependency build "${chart_dir}" >/dev/null
rendered="${test_root}/rendered.yaml"
helm template openbao "${chart_dir}" -f "${values_file}" >"${rendered}"

for hook in openbao-server-initialize-cluster openbao-server-refresh-jwt-plugin-catalog openbao-server-migrations; do
test "$(yq -r "select(.kind == \"Job\" and .metadata.name == \"$hook\") | .spec.template.spec.securityContext.runAsNonRoot" "${rendered}")" = true
test "$(yq -r "select(.kind == \"Job\" and .metadata.name == \"$hook\") | .spec.template.spec.securityContext.runAsUser" "${rendered}")" = 100
done

# Helm upgrades using --reuse-values do not add newly introduced default
# subtrees. Rendering must remain compatible with persisted pre-change values.
legacy_values="${test_root}/legacy-values.yaml"
Expand Down
1 change: 1 addition & 0 deletions deploy/stacks/self-managed/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ test:
@tests/nats-auth-callout-wiring.sh
@tests/notary-image-repository.sh
@tests/nvcf-ui-migrations-image-tag.sh
@tests/nonroot-migration-addons.sh

test-published-charts:
@: "$${NVCF_PUBLISHED_CHART_REGISTRY:?NVCF_PUBLISHED_CHART_REGISTRY is required}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ spec:
name: {{ .Release.Name }}
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
serviceAccountName: {{ .Release.Name }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
Expand All @@ -34,6 +38,13 @@ spec:
- name: receipt
image: "{{ with .Values.image.registry }}{{ . }}/{{ end }}{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
env:
- name: RECEIPT_CONFIGMAP
value: {{ .Values.configMapName | quote }}
Expand Down
26 changes: 23 additions & 3 deletions deploy/stacks/self-managed/global.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ nats:
{{- end }}
{{- end }}
container:
merge:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
image:
registry: {{ .Values.global.image.registry }}
repository: {{ .Values.global.image.repository }}/nats-server
Expand Down Expand Up @@ -256,18 +264,22 @@ nats:
registry: {{ .Values.global.image.registry }}
repository: {{ .Values.global.image.repository }}/alpine-k8s
{{- $natsNs := include "nvcf.nodeSelector" (dict "type" "controlplane" "selectors" .Values.global.nodeSelectors) -}}
{{- $natsTol := include "nvcf.tolerations" (dict "type" "controlplane" "tolerations" .Values.global.tolerations) -}}
{{- if or $natsNs $natsTol }}
{{- $natsTol := include "nvcf.tolerations" (dict "type" "controlplane" "tolerations" .Values.global.tolerations) }}
podTemplate:
merge:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
{{- with $natsNs }}
{{- . | nindent 8 }}
{{- end }}
{{- with $natsTol }}
{{- . | nindent 8 }}
{{- end }}
{{- end }}

# One merged config: block -- a second config: key under nats: would be
# silently collapsed. Surfaces server TLS for split-plane workers that reach
Expand Down Expand Up @@ -324,6 +336,14 @@ apikeys:
startupProbe:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with dig "apikeys" "livenessProbe" dict .Values }}
livenessProbe:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with dig "apikeys" "resources" dict .Values }}
resources:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with dig "apikeys" "env" dict .Values }}
env:
{{- toYaml . | nindent 4 }}
Expand Down
21 changes: 21 additions & 0 deletions deploy/stacks/self-managed/tests/api-keys-startup-probe.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ printf '%s\n' \
'apikeys:' \
' startupProbe:' \
' failureThreshold: 60' \
' livenessProbe:' \
' timeoutSeconds: 5' \
' resources:' \
' limits:' \
' cpu: 1' \
>"$test_stack_dir/environments/$environment_name.yaml"

values_file="$work_dir/api-keys-values.yaml"
Expand All @@ -33,12 +38,28 @@ HELMFILE_ENV="$environment_name" \
--state-values-set ingress.gatewayApi.gateways.grpc.name=grpc-gw \
--state-values-set ingress.gatewayApi.gateways.grpc.namespace=envoy-gateway-system \
--state-values-set apikeys.startupProbe.failureThreshold=60 \
--state-values-set apikeys.livenessProbe.timeoutSeconds=5 \
--state-values-set apikeys.resources.limits.cpu=1 \
--selector name=api-keys \
write-values \
--output-file-template "$values_file"

actual="$(yq -r '.apikeys.startupProbe.failureThreshold // "missing"' "$values_file")"
test "$actual" = "60" ||
fail "expected apikeys.startupProbe.failureThreshold=60, got $actual"
test "$(yq -r '.apikeys.livenessProbe.timeoutSeconds // "missing"' "$values_file")" = "5" ||
fail "API Keys liveness timeout override was not forwarded"
test "$(yq -r '.apikeys.resources.limits.cpu // "missing"' "$values_file")" = "1" ||
fail "API Keys CPU limit override was not forwarded"

chart_dir="$stack_dir/../../helm/api-keys-colocated/api-keys"
manifest="$work_dir/api-keys.yaml"
helm template api-keys "$chart_dir" --namespace api-keys \
--set apikeys.image.registry=example.com \
--set apikeys.image.repository=api-keys >"$manifest"
test "$(yq -r 'select(.kind == "Deployment") | .spec.template.spec.containers[0].securityContext.runAsNonRoot' "$manifest")" = true ||
fail "API Keys container must run as non-root"
test "$(yq -r 'select(.kind == "Deployment") | .spec.template.spec.containers[0].securityContext.runAsUser' "$manifest")" = 1000 ||
fail "API Keys container must use UID 1000"

echo "api-keys-startup-probe: all checks passed"
4 changes: 4 additions & 0 deletions deploy/stacks/self-managed/tests/image-override-wiring.sh
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ global:
EOF

render_values "$work_dir/default-values.yaml"
test "$(yq -r '.nats.podTemplate.merge.spec.securityContext.runAsUser' "$work_dir/default-values.yaml")" = 1000 ||
fail "nats pod user must be non-root in stack values"
test "$(yq -r '.nats.container.merge.securityContext.runAsNonRoot' "$work_dir/default-values.yaml")" = true ||
fail "nats container must run as non-root in stack values"
assert_absent "$work_dir/default-values.yaml" \
natsio/nats-server-config-reloader "nats.reloader chart default"
assert_yaml_path_absent "$work_dir/default-values.yaml" \
Expand Down
Loading
Loading