Skip to content
10 changes: 7 additions & 3 deletions charts/graylog/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -390,13 +390,17 @@ backoffLimit: 2
activeDeadlineSeconds: 900
template:
spec:
{{- with index . 3 }}
securityContext:
runAsUser: 1100
runAsGroup: 1100
fsGroup: 1100
{{- toYaml . | nindent 6 }}
{{- end }}
containers:
- name: geoipupdate
image: maxmindinc/geoipupdate:latest
{{- with index . 4 }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
envFrom:
- secretRef:
name: {{ index . 0 }}
Expand Down
8 changes: 5 additions & 3 deletions charts/graylog/templates/workload/cronjobs/geoip.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ data:
{{- $claimName := printf "%s-%s" (include "graylog.volume.name" .) (include "graylog.fullname" .) }}
{{- $cronSchedule := .Values.graylog.config.geolocation.maxmindGeoIp.cronSchedule | default "0 0 * * *" }}
{{- $hookIsEnabled := .Values.graylog.config.geolocation.maxmindGeoIp.postInstallRun | default true }}
{{- $podSecurityContext := .Values.graylog.podSecurityContext }}
{{- $containerSecurityContext := .Values.graylog.containerSecurityContext }}
{{- range $i := include "graylog.replicas" . | default 2 | int | until }}
---
apiVersion: batch/v1
Expand All @@ -25,7 +27,7 @@ spec:
schedule: {{ $cronSchedule }}
jobTemplate:
spec:
{{- list $geoSecretName $claimName $i | include "graylog.geoip.job.spec" | nindent 6 }}
{{- list $geoSecretName $claimName $i $podSecurityContext $containerSecurityContext | include "graylog.geoip.job.spec" | nindent 6 }}
{{- if $hookIsEnabled }}
---
apiVersion: batch/v1
Expand All @@ -37,7 +39,7 @@ metadata:
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
spec:
{{- list $geoSecretName $claimName $i | include "graylog.geoip.job.spec" | nindent 2 }}
{{- list $geoSecretName $claimName $i $podSecurityContext $containerSecurityContext | include "graylog.geoip.job.spec" | nindent 2 }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
8 changes: 8 additions & 0 deletions charts/graylog/templates/workload/statefulsets/datanode.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,18 @@ spec:
{{- if .Values.serviceAccount.create }}
serviceAccountName: {{ include "graylog.serviceAccountName" . }}
{{- end }}
{{- with .Values.datanode.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: graylog-datanode
image: {{ include "graylog.datanode.image" . }}
imagePullPolicy: {{ .Values.datanode.image.imagePullPolicy }}
{{- with .Values.datanode.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
envFrom:
- configMapRef:
name: {{ include "graylog.datanode.configmap.name" . }}
Expand Down
21 changes: 18 additions & 3 deletions charts/graylog/templates/workload/statefulsets/graylog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,18 @@ spec:
{{- if .Values.serviceAccount.create }}
serviceAccountName: {{ include "graylog.serviceAccountName" . }}
{{- end }}
{{- with .Values.graylog.podSecurityContext }}
securityContext:
runAsUser: 1100
runAsGroup: 1100
fsGroup: 1100
{{- toYaml . | nindent 8 }}
{{- end }}
initContainers:
- name: copy-data
image: {{ include "graylog.image" . }}
imagePullPolicy: {{ .Values.graylog.image.imagePullPolicy }}
{{- with .Values.graylog.initContainerSecurityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
command: [ "/bin/sh", "/scripts/init-script.sh" ]
env:
- name: INIT_GRAYLOG_PLUGIN_URLS
Expand Down Expand Up @@ -91,6 +95,13 @@ spec:
{{- if empty .existingClaim | and .image }}
- name: {{ printf "copy-plugin-%s" .name }}
image: {{ .image }}
{{- with $.Values.graylog.initContainerSecurityContext }}
securityContext:
{{- if not (hasKey . "readOnlyRootFilesystem") }}
readOnlyRootFilesystem: true
{{- end }}
{{- toYaml . | nindent 12 }}
{{- end }}
command: [ "/bin/sh", "-c", "cp *.jar /mnt/plugins/" ]
volumeMounts:
- name: init-plugins
Expand All @@ -102,6 +113,10 @@ spec:
- name: graylog-app
image: {{ include "graylog.image" . }}
imagePullPolicy: {{ .Values.graylog.image.imagePullPolicy }}
{{- with .Values.graylog.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
- name: POD_NAME
valueFrom:
Expand Down
57 changes: 57 additions & 0 deletions charts/graylog/tests/datanode_statefulset_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
suite: datanode StatefulSet
templates:
# The StatefulSet's pod-spec annotations reference two checksum helpers that
# `include` other templates by path. helm-unittest's `templates:` filter must
# list those dependencies so the includes resolve. Assertions below use the
# `template:` field to scope each assert to the StatefulSet specifically.
- workload/statefulsets/datanode.yaml
- config/datanode.yaml # checksum/config dependency
- config/secret/secrets.yaml # checksum/secret dependency
release:
name: graylog
namespace: graylog
tests:
# Security contexts (issue #70): defaults come from values.yaml, each field is overridable
- it: renders the default pod securityContext
asserts:
- equal:
path: spec.template.spec.securityContext
value:
fsGroup: 999
fsGroupChangePolicy: "OnRootMismatch"
seccompProfile:
type: RuntimeDefault
template: workload/statefulsets/datanode.yaml

- it: omits pod securityContext when datanode.podSecurityContext is set to null
set:
datanode.podSecurityContext: null
asserts:
- notExists:
path: spec.template.spec.securityContext
template: workload/statefulsets/datanode.yaml

- it: renders containerSecurityContext with the startup capabilities on the datanode container
asserts:
- equal:
path: spec.template.spec.containers[0].name
value: graylog-datanode
template: workload/statefulsets/datanode.yaml
- equal:
path: spec.template.spec.containers[0].securityContext
value:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
add: ["CHOWN", "DAC_OVERRIDE", "FOWNER", "SETUID", "SETGID"]
seccompProfile:
type: RuntimeDefault
template: workload/statefulsets/datanode.yaml

- it: omits datanode container securityContext when datanode.containerSecurityContext is set to null
set:
datanode.containerSecurityContext: null
asserts:
- notExists:
path: spec.template.spec.containers[0].securityContext
template: workload/statefulsets/datanode.yaml
55 changes: 55 additions & 0 deletions charts/graylog/tests/geoip_cronjob_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
suite: geoip update CronJob
templates:
- workload/cronjobs/geoip.yaml
release:
name: graylog
namespace: graylog
tests:
# The geoip job spec pulls its security contexts from the graylog values and
# threads them through the graylog.geoip.job.spec helper as positional args.
# Pin down that plumbing so the arg order can't silently drift.
- it: propagates graylog pod/container securityContexts into the CronJob job spec
set:
graylog.replicas: 1
graylog.config.geolocation.enabled: true
graylog.config.geolocation.maxmindGeoIp.enabled: true
graylog.config.geolocation.maxmindGeoIp.postInstallRun: false
asserts:
# doc 0 is the geoip Secret, doc 1 is the per-replica CronJob
- equal:
path: spec.jobTemplate.spec.template.spec.securityContext
value:
runAsUser: 1100
runAsGroup: 1100
runAsNonRoot: true
fsGroup: 1100
seccompProfile:
type: RuntimeDefault
documentIndex: 1
- equal:
path: spec.jobTemplate.spec.template.spec.containers[0].securityContext
value:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
seccompProfile:
type: RuntimeDefault
documentIndex: 1

- it: omits securityContexts from the job spec when graylog contexts are empty
set:
graylog.replicas: 1
graylog.podSecurityContext: null
graylog.containerSecurityContext: null
graylog.config.geolocation.enabled: true
graylog.config.geolocation.maxmindGeoIp.enabled: true
graylog.config.geolocation.maxmindGeoIp.postInstallRun: false
asserts:
- notExists:
path: spec.jobTemplate.spec.template.spec.securityContext
documentIndex: 1
- notExists:
path: spec.jobTemplate.spec.template.spec.containers[0].securityContext
documentIndex: 1
128 changes: 128 additions & 0 deletions charts/graylog/tests/graylog_statefulset_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,131 @@ tests:
- notExists:
path: spec.template.spec.imagePullSecrets
template: workload/statefulsets/graylog.yaml

# Security contexts (issue #70): defaults come from values.yaml, each field is overridable
- it: renders the default pod securityContext
asserts:
- equal:
path: spec.template.spec.securityContext
value:
runAsUser: 1100
runAsGroup: 1100
runAsNonRoot: true
fsGroup: 1100
seccompProfile:
type: RuntimeDefault
template: workload/statefulsets/graylog.yaml

- it: omits pod securityContext when graylog.podSecurityContext is set to null
set:
graylog.podSecurityContext: null
asserts:
- notExists:
path: spec.template.spec.securityContext
template: workload/statefulsets/graylog.yaml

- it: renders initContainerSecurityContext on the copy-data init container without NET_BIND_SERVICE
asserts:
- equal:
path: spec.template.spec.initContainers[0].name
value: copy-data
template: workload/statefulsets/graylog.yaml
- equal:
path: spec.template.spec.initContainers[0].securityContext
value:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
template: workload/statefulsets/graylog.yaml

- it: omits copy-data securityContext when graylog.initContainerSecurityContext is set to null
set:
graylog.initContainerSecurityContext: null
asserts:
- notExists:
path: spec.template.spec.initContainers[0].securityContext
template: workload/statefulsets/graylog.yaml

- it: renders containerSecurityContext with NET_BIND_SERVICE on the graylog-app container
asserts:
- equal:
path: spec.template.spec.containers[0].securityContext
value:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
seccompProfile:
type: RuntimeDefault
template: workload/statefulsets/graylog.yaml

- it: omits graylog-app securityContext when graylog.containerSecurityContext is set to null
set:
graylog.containerSecurityContext: null
asserts:
- notExists:
path: spec.template.spec.containers[0].securityContext
template: workload/statefulsets/graylog.yaml

- it: defaults readOnlyRootFilesystem to true on copy-plugin init containers
set:
graylog.config.plugins.enabled: true
graylog.plugins:
- name: my-plugin
image: example/my-plugin:1.0.0
asserts:
- equal:
path: spec.template.spec.initContainers[1].name
value: copy-plugin-my-plugin
template: workload/statefulsets/graylog.yaml
- equal:
path: spec.template.spec.initContainers[1].securityContext.readOnlyRootFilesystem
value: true
template: workload/statefulsets/graylog.yaml
- equal:
path: spec.template.spec.initContainers[1].securityContext.seccompProfile
value:
type: RuntimeDefault
template: workload/statefulsets/graylog.yaml

# The default is only applied when the key is absent (hasKey), so an explicit
# false is preserved rather than being overwritten back to true.
- it: preserves an explicit readOnlyRootFilesystem false on copy-plugin init containers
set:
graylog.config.plugins.enabled: true
graylog.initContainerSecurityContext:
readOnlyRootFilesystem: false
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
graylog.plugins:
- name: my-plugin
image: example/my-plugin:1.0.0
asserts:
- equal:
path: spec.template.spec.initContainers[1].securityContext.readOnlyRootFilesystem
value: false
template: workload/statefulsets/graylog.yaml

- it: omits copy-plugin securityContext when graylog.initContainerSecurityContext is set to null
set:
graylog.config.plugins.enabled: true
graylog.initContainerSecurityContext: null
graylog.plugins:
- name: my-plugin
image: example/my-plugin:1.0.0
asserts:
- equal:
path: spec.template.spec.initContainers[1].name
value: copy-plugin-my-plugin
template: workload/statefulsets/graylog.yaml
- notExists:
path: spec.template.spec.initContainers[1].securityContext
template: workload/statefulsets/graylog.yaml
20 changes: 20 additions & 0 deletions charts/graylog/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,18 @@
"minAvailable": { "type": "integer" }
}
},
"podSecurityContext": {
"type": ["object", "null"],
"description": "Pod-level securityContext for the Graylog StatefulSet. Set to null to omit it entirely ({} is coalesced back to the chart defaults)."
},
"initContainerSecurityContext": {
"type": ["object", "null"],
"description": "Container securityContext applied to the Graylog init containers. Set to null to omit it entirely ({} is coalesced back to the chart defaults)."
},
"containerSecurityContext": {
"type": ["object", "null"],
"description": "Container securityContext applied to the graylog-app container. Set to null to omit it entirely ({} is coalesced back to the chart defaults)."
},
"podAnnotations": {
"type": "object"
},
Expand Down Expand Up @@ -570,6 +582,14 @@
"minAvailable": { "type": "integer" }
}
},
"podSecurityContext": {
"type": ["object", "null"],
"description": "Pod-level securityContext for the Datanode StatefulSet. Set to null to omit it entirely ({} is coalesced back to the chart defaults)."
},
"containerSecurityContext": {
"type": ["object", "null"],
"description": "Container securityContext applied to the graylog-datanode container. Set to null to omit it entirely ({} is coalesced back to the chart defaults)."
},
"podAnnotations": {
"type": "object"
},
Expand Down
Loading
Loading