Skip to content

0.7.0 Runtime User Change Breaks Startup When Loaders Write Generated Files Under /opt/rustguac #57

@PureOxygen-Dev

Description

@PureOxygen-Dev

Summary

After updating to sol1/rustguac:0.7.0, the container now runs as:

uid=996(rustguac) gid=996(rustguac) groups=996(rustguac)

We understand this user change was made to address the blank-screen issue seen with web sessions, so the move to an unprivileged runtime user makes sense and should remain in place.

The problem is that some existing startup patterns still assume parts of /opt/rustguac are writable at runtime. With the new user, those assumptions no longer hold, and startup fails for deployments that render config and stage generated cert material there.

What Breaks

Our startup loader:

  • renders config to /opt/rustguac/config.toml
  • writes OpenBao client cert/key and CA bundle to /opt/rustguac/certs/...

Startup fails with:

mkdir: cannot create directory '/opt/rustguac/certs': Permission denied
/usr/local/bin/rustguac-loader.sh: 27: cannot create /opt/rustguac/certs/openbao/client.pem: Directory nonexistent
chmod: cannot access '/opt/rustguac/certs/openbao/client.pem': No such file or directory
grep: /opt/rustguac/certs/openbao/client.pem: No such file or directory
[rustguac-loader] ERROR: /opt/rustguac/certs/openbao/client.pem does not contain a PEM block for CERTIFICATE

There is also a second failure mode once cert staging is worked around:

/usr/local/bin/rustguac-loader.sh: 90: cannot create /opt/rustguac/config.toml: Permission denied

Repro Context

Image:

sol1/rustguac:0.7.0

Runtime user:

uid=996(rustguac) gid=996(rustguac)

Relevant stack mounts:

volumes:
  - /opt/docker/shared/static/rustguac/data:/opt/rustguac/data:rw
  - /opt/docker/shared/glusterfs/rustguac/drives:/opt/rustguac/drives:rw
  - /opt/docker/shared/glusterfs/rustguac/recordings:/opt/rustguac/recordings:rw
  - /opt/docker/shared/glusterfs/rustguac/scripts:/opt/rustguac/scripts:ro

Notably, /opt/rustguac/certs is not a mounted writable volume, and /opt/rustguac/config.toml is expected to be rendered inside the container filesystem.

Relevant Loader Behavior

TEMPLATE="/usr/local/etc/rustguac.toml"
OUT="/opt/rustguac/config.toml"

VAULT_CERT_DIR="/opt/rustguac/certs/openbao"
VAULT_SERVER_CA_BUNDLE_PATH="$VAULT_CERT_DIR/server-ca-bundle.pem"
VAULT_CLIENT_CERT_PATH="$VAULT_CERT_DIR/client.pem"
VAULT_CLIENT_KEY_PATH="$VAULT_CERT_DIR/client-key.pem"

if copy_secret_file VAULT_CLIENT_CERT "$VAULT_CLIENT_CERT_PATH" 0644; then
  require_pem_block "$VAULT_CLIENT_CERT_PATH" "CERTIFICATE"
fi

if copy_secret_file VAULT_CLIENT_KEY "$VAULT_CLIENT_KEY_PATH" 0600; then
  ...
fi

sed ... "$TEMPLATE" > "$OUT"

mkdir -p "$VAULT_CERT_DIR"
: > "$VAULT_SERVER_CA_BUNDLE_PATH"

Relevant config:

db_path = "/opt/rustguac/data/rustguac.db"

[vault]
ca_cert = "/opt/rustguac/certs/openbao/server-ca-bundle.pem"
__VAULT_CLIENT_CERT_LINE__
__VAULT_CLIENT_KEY_LINE__

Expected Behavior

The image should keep the new unprivileged runtime user, but should also define a small, explicit set of writable runtime paths for generated files.

One of these should be true and documented:

  1. /opt/rustguac/certs/openbao exists in the image and is writable by UID/GID 996:996.
  2. The rendered config path is moved to a documented writable runtime directory such as /run/rustguac or /var/lib/rustguac.
  3. The image creates the required writable runtime paths before dropping privileges.

Actual Behavior

With the new unprivileged runtime user, startup helpers can no longer reliably write under /opt/rustguac, and service startup fails.

Why This Looks Like a Packaging Gap Rather Than a User-Model Problem

The runtime user change itself appears valid, especially if it was required to fix the web-session blank-screen issue.

The regression is that mutable runtime paths were not clearly separated from immutable application paths:

  • application files live under /opt/rustguac
  • loaders and startup helpers still expect to create files there at runtime
  • the image now correctly restricts those writes

So the issue is not that the container should go back to running as root. The issue is that the image now needs explicit writable runtime locations for generated config and cert material.

Suggested Fixes

  • Keep USER 996:996 in place.
  • Do not make all of /opt/rustguac broadly writable again.
  • Pre-create and chown only the required runtime-write paths, for example:
    • /opt/rustguac/certs/openbao
    • a dedicated writable config path such as /run/rustguac/config.toml or /var/lib/rustguac/config.toml
  • Or move all generated runtime files out of /opt/rustguac and into a dedicated writable runtime directory.

Suggested Dockerfile Direction

Something along these lines would solve the packaging issue without undoing the runtime-user hardening:

RUN mkdir -p \
    /opt/rustguac/data \
    /opt/rustguac/recordings \
    /opt/rustguac/drives \
    /opt/rustguac/certs/openbao \
    /run/rustguac \
 && chown -R 996:996 \
    /opt/rustguac/data \
    /opt/rustguac/recordings \
    /opt/rustguac/drives \
    /opt/rustguac/certs \
    /run/rustguac

USER 996:996

Then loaders could write:

  • certs to /opt/rustguac/certs/openbao
  • rendered config to /run/rustguac/config.toml

while keeping the rest of /opt/rustguac effectively immutable.

Request

Please keep the new runtime user model, but add explicit writable runtime paths so startup helpers that generate config and certificate material can work without needing broad write access under /opt/rustguac.

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