Skip to content

[Feature] Run the PD, Store and Server images as a non-root user #3211

Open

Description

@bitflicker64

Feature Description (功能描述)

The published hugegraph/pd, hugegraph/store and hugegraph/server images all run their Java process as root: none of the three declares a USER, checked against the current latest image configs on Docker Hub (registry config blob, .config.User empty on all three, 2026-09-17).

Why it matters on Kubernetes:

  1. A namespace under the restricted Pod Security Standard rejects these pods outright (runAsNonRoot != true).
  2. The Helm chart in feat(helm): add HStore deployment chart #3132 cannot set runAsNonRoot: true or readOnlyRootFilesystem: true as defaults; it documents this in its Limitations and ships the remaining hardening it can (allowPrivilegeEscalation: false, capabilities.drop: [ALL], seccompProfile: RuntimeDefault).
  3. Security scanners (kube-score, polaris, kubescape) flag every workload for it, which any adopter evaluating the chart sees on day one; the 2026-09-10 chart test campaign recorded it as a failing kubescape NSA control on both branches.

Proposal:

  • Create a fixed-UID user in each Dockerfile (the toolchain's Hubble image can follow the same pattern later) and chown the data and log directories to it.
  • Declare USER in the image and keep the entrypoints from writing outside the data, log and temp directories, so readOnlyRootFilesystem becomes possible as a follow-up.
  • Ship it in a minor release with an upgrade note: existing PVC data written as root needs a one-time chown, or an initContainer / fsGroup note in the chart.

The chart side is ready to adopt this the release it lands: podSecurityContext and securityContext are fully configurable per component today, so only the defaults would change.

Activity

  1. SebastianGruza commented on Sep 20, 2026

    @SebastianGruza
    Contributor

    I'd like to take this, but before writing code I want to agree on the shape, since it touches all three images at once and existing data on PVCs. What I checked in the repo and in the :latest images of 2026-09-18:

    • None of the three Dockerfiles declares USER; each has a VOLUME on the whole install directory (/hugegraph-server, /hugegraph-pd, /hugegraph-store), so data, logs, conf and bin/pid are one root-owned tree; the entrypoint is dumb-init + docker-entrypoint.sh, HEALTHCHECK through curl. Hubble starts as root too.
    • What writes at runtime: all three start scripts write bin/pid and logs/* (including heap dumps via -XX:HeapDumpPath=logs, and logs/gc.log on the Store); Jetty unpacks into /tmp; the Server entrypoint appends to conf/graphs/hugegraph.properties and conf/rest-server.properties and creates an init marker; the PD and Store entrypoints write nothing (their config goes through SPRING_APPLICATION_JSON). Data: pd_data, storage, rocksdb-data under the install directory.
    • The fix NPE that task id will be null when creating indexlabel already exists #221 chart already has podSecurityContext/securityContext per component and mounts the PVC only at dataPath, so logs, conf and bin live in the image layer today.

    Proposal: two steps

    Step 1, this PR: non-root. A fixed UID/GID and user (hugegraph) in each Dockerfile, chown of the install directory, USER before ENTRYPOINT; dumb-init and HEALTHCHECK unchanged. Start scripts unchanged except one thing: the pid file out of bin/ (question 2). CI: extend the existing image tests (docker/test-compose.sh smoke, test-wait-storage.sh) with an id -u check inside the container and a start under --user/runAsNonRoot. Upgrade note: data on existing volumes was written as root, one-time chown, and in the chart fsGroup plus an optional initContainer that does it for the operator.

    Step 2, follow-up: readOnlyRootFilesystem. Requires everything written to live on mounted volumes: logs and /tmp on emptyDir, the pid next to the logs, and the Server entrypoint rendering its config into a writable directory instead of editing conf/ in place. A separate PR, since it changes the Server entrypoint and the chart templates.

    Validation I can do

    On a three-node k3s with the #221 chart: a namespace with pod-security.kubernetes.io/enforce: restricted, kubescape before and after, the full fault battery of 2026-09-16 and the readiness scenarios on the new images, plus an upgrade of an existing cluster whose data was written as root, through the initContainer. I'd build the images with docker/bake.hcl and overlay them on the cluster the way I tested #3221.

    Four questions

    1. UID. I'd propose a fixed 1000:1000: least friction with fsGroup and with provisioners like local-path, and the default user of many base images. The alternative is a dedicated high UID (e.g. 10001) that collides with nothing on the host. Do you have a preference or a requirement from the chart / scanner side?
    2. Pid file. The scripts write bin/pid; in step 2 bin/ becomes read-only. Move the pid to logs/ now (one change in the three start/stop scripts, consistent with the tarball), or leave it in bin/ for step 1 and move it together with read-only?
    3. Server config. The entrypoint edits conf/ in place. For step 1 it is enough that conf/ belongs to the image user. For step 2 I'd render into /hugegraph-server/run/conf (emptyDir) and start the server from there. Any reason to do that right away?
    4. Existing data. The upgrade note plus fsGroup in the chart cover volumes where fsGroup works; hostPath/local-path it does not. Do you want an optional initContainer (chown -R on dataPath, off by default) in the chart as part of this step, or the note only?

    After the answers I'll do the PR for the images and tests, and the chart diff under #221.

  2. github-actions commented on Oct 5, 2026

    @github-actions

    Due to the lack of activity, the current issue is marked as stale and will be closed after 20 days, any update will remove the stale label

  3. SebastianGruza commented on Oct 10, 2026

    @SebastianGruza
    Contributor

    Still open on my side: the four questions in the design comment above are what I need before writing code. A yes or no on the direction is enough for me to start with one image as a first PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions