Skip to content

Change default user in container image #46

Description

@henryx

Current image uses root to run Firebird database. This is considered a security problem, and doesn't permit a correct execution without special permissions (in particular on Openshift).

Is it possible to set an unprivileged user in build stage for the images?

Activity

  1. fdcastel commented on Sep 17, 2026

    @fdcastel
    Member

    Thanks for raising this — and for pointing at OpenShift specifically, because that turns out to be the part that decides the design.

    This topic has some history: it came up twice on the predecessor image (jacobalberty/firebird-docker#35, #128, the latter also a non-root read-only Kubernetes environment), but it has never been addressed in the image itself. So let me put some measured facts on the table first, because the current situation is better than "it needs root" and worse than "just add a USER line".

    Where we are today. Everything in the container runs as uid 0 — tini, the entrypoint, fbguard and firebird. Firebird does not drop privileges by itself; the firebird account (uid/gid 84) exists and already owns the interesting runtime files, but nothing ever switches to it.

    docker run --user firebird already works for the simple case. I tested firebirdsql/firebird-amd64:5 (5.0.4): with --user 84:84 the server starts and serves normally, because security5.fdb, firebird.log, fb_guard, the /tmp/firebird lock directory and /var/lib/firebird/data are all owned by firebird already. Exactly three things break, all of them in the entrypoint:

    Symptom Cause
    sed: couldn't open temporary file /opt/firebird/sedXXXXXX when any FIREBIRD_CONF_* variable or FIREBIRD_USE_LEGACY_AUTH is set firebird.conf is root:root 0644 inside a root:root 0755 directory
    rm: cannot remove '/opt/firebird/SYSDBA.password' after FIREBIRD_ROOT_PASSWORD is applied the file is root:root 0400
    /opt/firebird/.firebird_env: Permission denied when FIREBIRD_DATABASE is set /opt/firebird is not writable by the firebird user

    OpenShift needs more than a USER directive. Under the restricted SCC the USER line is ignored and the pod gets a random UID from the project's range with GID 0, so the fix has to be permission-based (root:0 ownership plus g=u), not user-based. I simulated that (--user 12345:0 on an image with chown -R root:0 and chmod -R g=u applied to /opt/firebird, the data directory and the lock directory) and got two further results worth knowing:

    • with group-root-writable permissions, the config edits and the SYSDBA password change work fine;
    • creating FIREBIRD_USER still fails with no permission for INSERT access to TABLE PLG$SRP_VIEW, because the local (embedded) connection derives its identity from the OS user, and a random UID has no /etc/passwd entry, so it is not SYSDBA. Passing -user SYSDBA explicitly fixes it — embedded connections bypass authentication, and the entrypoint already does this in one place but not in the others.

    One implementation detail for whoever picks this up: $FIREBIRD_DATA is declared as a VOLUME, so its ownership must be set in the image layer — a runtime chown inside the container does not persist into the anonymous volume.

    Also worth noting: Firebird listens on 3050, so no NET_BIND_SERVICE capability or any other privileged capability is needed. Nothing here requires root at runtime; it is purely a file-ownership question.

    What I propose. Make the image fully non-root-capable while keeping root as the default user, rather than flipping the default straight away. Concretely: set root:0 ownership with g=u permissions on /opt/firebird, the data directory and the lock directory at build time, and make the entrypoint robust — guard the removal of SYSDBA.password, pass -user SYSDBA on the local connections that create the user and the database, and write .firebird_env somewhere writable. That makes --user firebird, --user <any-uid>:0, Kubernetes runAsUser/fsGroup and OpenShift's injected UID all work, and it costs existing users nothing.

    The reason for not simply adding USER firebird today is backwards compatibility: every existing volume and bind mount out there contains root-owned database files, so changing the default user would break running deployments on upgrade until users chown their data — and, as noted above, it would not even solve the OpenShift case. Once the image is non-root-capable, flipping the default becomes a small, well-understood change that belongs in a major release with explicit release notes.

    @henryx — two questions, if you don't mind: is your environment OpenShift's restricted SCC (random UID + GID 0), or a fixed runAsUser? And would you be able to test images from a branch before this is merged? Your environment is the one that matters here, and I'd rather validate against it than against my simulation of it.

  2. henryx commented on Sep 20, 2026

    @henryx
    Author

    Thank you for the reply.

    Currently, I don't have a Openhift or Kubernetes environment that restrict image permission.

    I'm a cloud engineer and I have dealt with these issues, in particular when custom images released by developers aren't approved from security systems.

    Also, I'm a developer, and at the moment I write vibecode a Kubernetes operator for Firebird. To do it, I've choosed to use official images becaue I think is the more afordable solution repect to made custom images. So when I viewed this particular choice for Firebird image, I've opened this issue.

    And yes, I'm able to to test images from a particular branch before this is merged (at the moment I use a kind/k3s environment for development, but I can switch a Microshift or a OKD environment without problems)

  3. fdcastel commented on Sep 26, 2026

    @fdcastel
    Member

    @henryx the non-root support is implemented in #51, and an unofficial test image is available. It would be great if you could test it in your environment.

    Unofficial test image

    ghcr.io/fdcastel/firebird (Debian Trixie, amd64), with tags 5 / 5.0.4, 4 / 4.0.7 and 3 / 3.0.14. It is for testing only: it is built from a branch that combines #51 with two other pending PRs (#49 and #52, see "Also in this image" below).

    What changed

    • The image still runs as root by default, so nothing changes for existing users.
    • It now also runs fully as user firebird (UID 84), or as any UID with GID 0, which is what OpenShift's restricted SCC assigns. This covers everything the entrypoint does: FIREBIRD_CONF_*, FIREBIRD_ROOT_PASSWORD, FIREBIRD_USER, FIREBIRD_DATABASE and init scripts.
    • /opt/firebird, the data directory and the lock directory are owned by firebird with group 0, and group permissions equal owner permissions (g=u).
    • Any other UID/GID combination is not supported: the entrypoint prints a warning and Firebird will not be able to write its files.
    • Databases created earlier by a container running as root are owned by root. Before reusing such a data directory as non-root, change its ownership, e.g. chown -R 84:0 <data dir>.

    Examples

    # As the 'firebird' user
    docker run -d --user firebird -e FIREBIRD_ROOT_PASSWORD=masterkey -e FIREBIRD_DATABASE=test.fdb ghcr.io/fdcastel/firebird:5
    
    # As an arbitrary UID with GID 0 (what OpenShift does)
    docker run -d --user 12345:0 -e FIREBIRD_ROOT_PASSWORD=masterkey -e FIREBIRD_USER=alice -e FIREBIRD_PASSWORD=bird -e FIREBIRD_DATABASE=test.fdb ghcr.io/fdcastel/firebird:5

    Kubernetes (on plain Kubernetes, runAsUser must be set, because the image's default user is still root and runAsNonRoot: true alone would reject it):

    apiVersion: v1
    kind: Pod
    metadata:
      name: firebird
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 84        # or any UID
        runAsGroup: 0
      containers:
        - name: firebird
          image: ghcr.io/fdcastel/firebird:5
          env:
            - name: FIREBIRD_ROOT_PASSWORD
              value: masterkey
            - name: FIREBIRD_DATABASE
              value: test.fdb
          ports:
            - containerPort: 3050
          volumeMounts:
            - name: data
              mountPath: /var/lib/firebird/data
      volumes:
        - name: data
          emptyDir: {}

    What would help most

    Since you offered: please test on OKD or MicroShift under the default restricted / restricted-v2 SCC, not anyuid, letting OpenShift inject the UID. That is the case the design targets and the one we can only simulate here. A run with a persistent volume for /var/lib/firebird/data (instead of emptyDir) would also be very useful. Your kind/k3s setup with runAsUser covers the plain Kubernetes case.

    Please report back here: does the pod start, does the entrypoint print any warnings, and can you connect and create/use a database? Logs are welcome if something fails.

    Also in this image

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