Skip to content
Open
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
23 changes: 12 additions & 11 deletions charts/graylog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -432,20 +432,21 @@ helm upgrade --install graylog graylog/graylog --namespace graylog --reuse-value

# Hardened Environments

All workloads run with tightened pod and container security contexts by default (non-root where possible, dropped
capabilities, and `seccompProfile: RuntimeDefault`). The Graylog application is compliant with the Kubernetes
All Graylog workloads run with tightened pod and container security contexts by default (non-root, dropped capabilities,
and `seccompProfile: RuntimeDefault`). Both the Graylog application and the DataNode are compliant with the Kubernetes
[`restricted` Pod Security Standard](https://kubernetes.io/docs/concepts/security/pod-security-standards/).

Two components cannot yet meet `restricted` and need an exemption if you enforce it:

- **DataNode** must currently start as root to prepare its data directory before dropping privileges to a non-root
user. We are working on updating the entrypoint upstream to remove this requirement; until then, the DataNode
requires the `baseline` level (not `restricted`) or a namespace exemption.
- **MongoDB**, when provisioned by the MCK operator, runs pods that are not `restricted`-compliant. Either exempt
them, or [bring your own MongoDB](#bring-your-own-mongodb) for hardened environments.
> [!NOTE]
> If you enforce [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) at the
> `restricted` level and let the chart provision MongoDB, you might need to exempt the MongoDB pods (or
> [bring your own MongoDB](#bring-your-own-mongodb)). With an external MongoDB, all chart-managed workloads are
> `restricted`-compliant.

If you enforce [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/), set the
namespace to `baseline` rather than `restricted`, or apply the exemptions above.
> [!NOTE]
> The DataNode runs non-root by relying on `fsGroup` for volume ownership and setting `GDN_RUN_AS_NONROOT`, which
> tells the container entrypoint to skip its root-only privilege-drop path. This requires a DataNode image whose
> entrypoint supports `GDN_RUN_AS_NONROOT` (graylog-datanode `7.1`+). If you pin an older `datanode.image.tag`,
> override `datanode.podSecurityContext` and `datanode.containerSecurityContext` to run the container as root.

# Maintenance

Expand Down
4 changes: 4 additions & 0 deletions charts/graylog/templates/config/datanode.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ kind: ConfigMap
metadata:
name: {{ include "graylog.datanode.configmap.name" . }}
data:
# Required by the datanode entrypoint to take the non-root startup path
# (mkdir + chmod instead of chown + setpriv). Ignored when the container
# runs as root. See graylog-docker entrypoint.sh (PR #306).
GDN_RUN_AS_NONROOT: "true"
JAVA_OPTS: {{ .Values.datanode.config.javaOpts | quote }}
GRAYLOG_DATANODE_NODE_ID_FILE: {{ .Values.datanode.config.nodeIdFile | default "/var/lib/graylog-datanode/node-id" | quote }}
GRAYLOG_DATANODE_OPENSEARCH_HEAP: {{ .Values.datanode.config.opensearchHeap | quote }}
Expand Down
16 changes: 14 additions & 2 deletions charts/graylog/tests/datanode_statefulset_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ tests:
- equal:
path: spec.template.spec.securityContext
value:
runAsUser: 999
runAsGroup: 999
runAsNonRoot: true
fsGroup: 999
fsGroupChangePolicy: "OnRootMismatch"
seccompProfile:
Expand All @@ -31,7 +34,7 @@ tests:
path: spec.template.spec.securityContext
template: workload/statefulsets/datanode.yaml

- it: renders containerSecurityContext with the startup capabilities on the datanode container
- it: renders the default non-root containerSecurityContext on the datanode container
asserts:
- equal:
path: spec.template.spec.containers[0].name
Expand All @@ -40,10 +43,10 @@ tests:
- equal:
path: spec.template.spec.containers[0].securityContext
value:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
add: ["CHOWN", "DAC_OVERRIDE", "FOWNER", "SETUID", "SETGID"]
seccompProfile:
type: RuntimeDefault
template: workload/statefulsets/datanode.yaml
Expand All @@ -55,3 +58,12 @@ tests:
- notExists:
path: spec.template.spec.containers[0].securityContext
template: workload/statefulsets/datanode.yaml

# The non-root securityContext above only works if the entrypoint takes its
# non-root path, which it does when GDN_RUN_AS_NONROOT is set (graylog-docker #306).
- it: sets GDN_RUN_AS_NONROOT so the datanode entrypoint takes the non-root path
asserts:
- equal:
path: data.GDN_RUN_AS_NONROOT
value: "true"
template: config/datanode.yaml
5 changes: 4 additions & 1 deletion charts/graylog/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -286,15 +286,18 @@ datanode:
enabled: false
minAvailable: 2
podSecurityContext:
runAsUser: 999
runAsGroup: 999
runAsNonRoot: true
fsGroup: 999
fsGroupChangePolicy: "OnRootMismatch"
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
add: ["CHOWN", "DAC_OVERRIDE", "FOWNER", "SETUID", "SETGID"]
seccompProfile:
type: RuntimeDefault
podAnnotations: {}
Expand Down
Loading