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
6 changes: 6 additions & 0 deletions DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,9 @@ Also adds `tzdata` to Noble's distro `extraPackages` (matching Jammy). FB3 relie
**Decision:** The `update-repo` job in `publish-fork.yaml` only commits and pushes regenerated `generated/` and `README.md` when running on the fork's default branch (`github.event.repository.default_branch`). Dispatches on PR or feature branches still run `Invoke-Build Prepare` and `Invoke-Build Update-Readme` (so a template-substitution regression still fails the workflow) but skip the `git commit` / `git push`. Amends D-014 for the publish-fork case; `publish.yaml` (the official-repo publish) is unchanged.

**Rationale:** `publish-fork.yaml` passes `-Registry 'ghcr.io/<owner>'` to `Update-Readme`, which substitutes the fork's registry into the README table header. The previous unguarded auto-commit pushed that fork-specific README back to whatever branch was dispatched, including branches with open upstream PRs — directly polluting the PR diff with content that must not land upstream, and breaking GitHub's linear rebase when the upstream master had its own concurrent `README.md` changes (observed during PR #43, which required a force-pushed clean rebase to unblock). Branch-gating preserves D-014's "generated/ tracked in git" invariant on the fork's default branch while keeping PR/feature branches diff-clean against upstream. Confines the `-Registry` rewrite to the only place the fork wants it (its own showcased README on `master`).

## D-020: Non-root capable image, root remains the default user

**Decision:** The image keeps running as `root` by default (no `USER` directive), but also supports running as `firebird` (UID 84) or as any UID with GID 0. Runtime-writable paths — `/opt/firebird` itself, `firebird.conf`, `SYSDBA.password`, `firebird.log`, `fb_guard`, `replication.log`, `security*.fdb`, `/tmp/firebird` and `$FIREBIRD_DATA` — are owned by `firebird:0` with group permissions equal to owner permissions (`g=u`). Binaries, libraries and plugins stay owned by `root`. The installer's leftover lock and shared memory files in `/tmp/firebird` are removed at build time. Every local `isql` connection in the entrypoint names its user explicitly (`-user SYSDBA`, or `FIREBIRD_USER` in `process_sql`). A non-root user without write access gets a warning on startup.

**Rationale:** Requested in [issue #46](https://github.com/FirebirdSQL/firebird-docker/issues/46) (security policies requiring non-root containers; OpenShift). OpenShift's `restricted` SCC ignores the image's `USER` and injects a random UID with GID 0, so group-0 ownership is what makes it work, not a `USER` line; owner `firebird` keeps `--user firebird` working with GID 84. Local (embedded) connections take the OS user name as the Firebird user: `root` is mapped to SYSDBA, but UID 84 becomes `FIREBIRD` and a random UID has no name at all, which made `CREATE USER` fail and changed database/object ownership. `$FIREBIRD_DATA` is a `VOLUME`, so its ownership must be set in the image layer. Changing the default to `USER firebird` was rejected for now: existing volumes and bind mounts contain root-owned databases which a non-root container cannot open, so it would break deployments on upgrade. It belongs in a major release with explicit release notes.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,27 @@ Alternatively, you can use the same time zone as your host system by mapping the



## Running as a non-root user

The container runs as `root` by default. It can also run as a non-root user, without any change in behavior:

- as the `firebird` user (UID `84`), e.g. `docker run --user firebird ...`; or
- as **any** UID with GID `0` (`root` group), e.g. `docker run --user 12345:0 ...`. This is how OpenShift runs containers under its default `restricted` security context constraint, which assigns a random UID.

```yaml
# Kubernetes
securityContext:
runAsNonRoot: true
runAsUser: 84 # or any UID...
runAsGroup: 0 # ...as long as the group is 0
```

Other UID/GID combinations are not supported: the entrypoint shows a warning and Firebird cannot write its runtime files.

> **IMPORTANT:** When using a bind mount or a pre-existing volume for `/var/lib/firebird/data`, it must be writable by the chosen user. Databases created while running as `root` are owned by `root`, and a non-root container cannot open them until you change their ownership (e.g. `chown -R 84:0` on the data directory).



## Backup and Restore

### For online databases
Expand Down
17 changes: 15 additions & 2 deletions generated/3.0.10/bookworm/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,23 @@ ENV PATH=/opt/firebird/bin:$PATH

# Data directory
ENV FIREBIRD_DATA=/var/lib/firebird/data

# Non-root support: runtime-writable paths are owned by 'firebird' with group 0 (root), and group permissions equal
# owner permissions. The image still runs as root by default, but it also runs as 'firebird' (--user firebird) or as
# an arbitrary UID with GID 0 (OpenShift restricted SCC). Binaries, libraries and plugins stay owned by root.
# The data directory is a VOLUME: its ownership must be set here, in the image layer.
# Lock and shared memory files left in /tmp/firebird by the installer are removed (Firebird recreates them at runtime).
# See DECISIONS.md D-020 and https://github.com/FirebirdSQL/firebird-docker/issues/46
RUN set -eux; \
mkdir -p "$FIREBIRD_DATA"; \
chown -R firebird:firebird "$FIREBIRD_DATA"; \
chmod 755 "$FIREBIRD_DATA"
rm -rf /tmp/firebird/*; \
cd /opt/firebird; \
for f in . SYSDBA.password firebird.conf firebird.log fb_guard replication.log security*.fdb /tmp/firebird "$FIREBIRD_DATA"; do \
if [ -e "$f" ]; then \
chown firebird:0 "$f"; \
chmod g=u,o-w "$f"; \
fi; \
done
VOLUME $FIREBIRD_DATA

# Entrypoint
Expand Down
27 changes: 25 additions & 2 deletions generated/3.0.10/bookworm/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ indent() {
sed 's/^/ /';
}

# Warns when a non-root user cannot write to Firebird runtime files.
# Supported non-root users are 'firebird' and any UID with GID 0 (e.g. OpenShift restricted SCC).
check_permissions() {
if [ "$(id -u)" = '0' ]; then
return
fi

if [ ! -w /opt/firebird ] || [ ! -w "$FIREBIRD_DATA" ]; then
# [Tabs ahead]
cat >&2 <<-EOL
-----
WARNING: Running as UID $(id -u) / GID $(id -g), which cannot write to /opt/firebird or $FIREBIRD_DATA.

Run the container as root, as user 'firebird' (UID 84), or as any UID with GID 0.
-----
EOL
fi
}

# Set Firebird configuration parameters from environment variables.
set_config() {
read_from_file_or_env 'FIREBIRD_USE_LEGACY_AUTH'
Expand Down Expand Up @@ -203,7 +222,7 @@ create_user() {
escaped_password=$(escape_sql_string "$FIREBIRD_PASSWORD")

# [Tabs ahead]
/opt/firebird/bin/isql -b security.db <<-EOL
/opt/firebird/bin/isql -b -user SYSDBA security.db <<-EOL
CREATE OR ALTER USER ${quoted_user}
PASSWORD '${escaped_password}'
GRANT ADMIN ROLE;
Expand All @@ -221,6 +240,9 @@ process_sql() {
# authentication, and the server then normalizes the name exactly like it
# normalized the database owner name, so DDL permissions work in init scripts.
isql_command+=( -u "$(unquote_sql_identifier "$(quote_sql_identifier "$FIREBIRD_USER")")" -p "$FIREBIRD_PASSWORD" )
else
# Local connections otherwise take the OS user name, which is SYSDBA only for root.
isql_command+=( -u SYSDBA )
fi

if [ -n "$FIREBIRD_DATABASE" ]; then
Expand Down Expand Up @@ -302,7 +324,7 @@ create_db() {
[ -n "$FIREBIRD_DATABASE_DEFAULT_CHARSET" ] && default_charset="DEFAULT CHARACTER SET $FIREBIRD_DATABASE_DEFAULT_CHARSET"

# [Tabs ahead]
/opt/firebird/bin/isql -b -q <<-EOL
/opt/firebird/bin/isql -b -q -user SYSDBA <<-EOL
CREATE DATABASE '${escaped_database}'
$user_and_password
$page_size
Expand Down Expand Up @@ -345,6 +367,7 @@ run_daemon_and_wait() {
# main()
#
if [ "$1" = 'firebird' ]; then
check_permissions
set_config
set_sysdba

Expand Down
17 changes: 15 additions & 2 deletions generated/3.0.10/bullseye/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,23 @@ ENV PATH=/opt/firebird/bin:$PATH

# Data directory
ENV FIREBIRD_DATA=/var/lib/firebird/data

# Non-root support: runtime-writable paths are owned by 'firebird' with group 0 (root), and group permissions equal
# owner permissions. The image still runs as root by default, but it also runs as 'firebird' (--user firebird) or as
# an arbitrary UID with GID 0 (OpenShift restricted SCC). Binaries, libraries and plugins stay owned by root.
# The data directory is a VOLUME: its ownership must be set here, in the image layer.
# Lock and shared memory files left in /tmp/firebird by the installer are removed (Firebird recreates them at runtime).
# See DECISIONS.md D-020 and https://github.com/FirebirdSQL/firebird-docker/issues/46
RUN set -eux; \
mkdir -p "$FIREBIRD_DATA"; \
chown -R firebird:firebird "$FIREBIRD_DATA"; \
chmod 755 "$FIREBIRD_DATA"
rm -rf /tmp/firebird/*; \
cd /opt/firebird; \
for f in . SYSDBA.password firebird.conf firebird.log fb_guard replication.log security*.fdb /tmp/firebird "$FIREBIRD_DATA"; do \
if [ -e "$f" ]; then \
chown firebird:0 "$f"; \
chmod g=u,o-w "$f"; \
fi; \
done
VOLUME $FIREBIRD_DATA

# Entrypoint
Expand Down
27 changes: 25 additions & 2 deletions generated/3.0.10/bullseye/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ indent() {
sed 's/^/ /';
}

# Warns when a non-root user cannot write to Firebird runtime files.
# Supported non-root users are 'firebird' and any UID with GID 0 (e.g. OpenShift restricted SCC).
check_permissions() {
if [ "$(id -u)" = '0' ]; then
return
fi

if [ ! -w /opt/firebird ] || [ ! -w "$FIREBIRD_DATA" ]; then
# [Tabs ahead]
cat >&2 <<-EOL
-----
WARNING: Running as UID $(id -u) / GID $(id -g), which cannot write to /opt/firebird or $FIREBIRD_DATA.

Run the container as root, as user 'firebird' (UID 84), or as any UID with GID 0.
-----
EOL
fi
}

# Set Firebird configuration parameters from environment variables.
set_config() {
read_from_file_or_env 'FIREBIRD_USE_LEGACY_AUTH'
Expand Down Expand Up @@ -203,7 +222,7 @@ create_user() {
escaped_password=$(escape_sql_string "$FIREBIRD_PASSWORD")

# [Tabs ahead]
/opt/firebird/bin/isql -b security.db <<-EOL
/opt/firebird/bin/isql -b -user SYSDBA security.db <<-EOL
CREATE OR ALTER USER ${quoted_user}
PASSWORD '${escaped_password}'
GRANT ADMIN ROLE;
Expand All @@ -221,6 +240,9 @@ process_sql() {
# authentication, and the server then normalizes the name exactly like it
# normalized the database owner name, so DDL permissions work in init scripts.
isql_command+=( -u "$(unquote_sql_identifier "$(quote_sql_identifier "$FIREBIRD_USER")")" -p "$FIREBIRD_PASSWORD" )
else
# Local connections otherwise take the OS user name, which is SYSDBA only for root.
isql_command+=( -u SYSDBA )
fi

if [ -n "$FIREBIRD_DATABASE" ]; then
Expand Down Expand Up @@ -302,7 +324,7 @@ create_db() {
[ -n "$FIREBIRD_DATABASE_DEFAULT_CHARSET" ] && default_charset="DEFAULT CHARACTER SET $FIREBIRD_DATABASE_DEFAULT_CHARSET"

# [Tabs ahead]
/opt/firebird/bin/isql -b -q <<-EOL
/opt/firebird/bin/isql -b -q -user SYSDBA <<-EOL
CREATE DATABASE '${escaped_database}'
$user_and_password
$page_size
Expand Down Expand Up @@ -345,6 +367,7 @@ run_daemon_and_wait() {
# main()
#
if [ "$1" = 'firebird' ]; then
check_permissions
set_config
set_sysdba

Expand Down
17 changes: 15 additions & 2 deletions generated/3.0.10/jammy/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,23 @@ ENV PATH=/opt/firebird/bin:$PATH

# Data directory
ENV FIREBIRD_DATA=/var/lib/firebird/data

# Non-root support: runtime-writable paths are owned by 'firebird' with group 0 (root), and group permissions equal
# owner permissions. The image still runs as root by default, but it also runs as 'firebird' (--user firebird) or as
# an arbitrary UID with GID 0 (OpenShift restricted SCC). Binaries, libraries and plugins stay owned by root.
# The data directory is a VOLUME: its ownership must be set here, in the image layer.
# Lock and shared memory files left in /tmp/firebird by the installer are removed (Firebird recreates them at runtime).
# See DECISIONS.md D-020 and https://github.com/FirebirdSQL/firebird-docker/issues/46
RUN set -eux; \
mkdir -p "$FIREBIRD_DATA"; \
chown -R firebird:firebird "$FIREBIRD_DATA"; \
chmod 755 "$FIREBIRD_DATA"
rm -rf /tmp/firebird/*; \
cd /opt/firebird; \
for f in . SYSDBA.password firebird.conf firebird.log fb_guard replication.log security*.fdb /tmp/firebird "$FIREBIRD_DATA"; do \
if [ -e "$f" ]; then \
chown firebird:0 "$f"; \
chmod g=u,o-w "$f"; \
fi; \
done
VOLUME $FIREBIRD_DATA

# Entrypoint
Expand Down
27 changes: 25 additions & 2 deletions generated/3.0.10/jammy/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ indent() {
sed 's/^/ /';
}

# Warns when a non-root user cannot write to Firebird runtime files.
# Supported non-root users are 'firebird' and any UID with GID 0 (e.g. OpenShift restricted SCC).
check_permissions() {
if [ "$(id -u)" = '0' ]; then
return
fi

if [ ! -w /opt/firebird ] || [ ! -w "$FIREBIRD_DATA" ]; then
# [Tabs ahead]
cat >&2 <<-EOL
-----
WARNING: Running as UID $(id -u) / GID $(id -g), which cannot write to /opt/firebird or $FIREBIRD_DATA.

Run the container as root, as user 'firebird' (UID 84), or as any UID with GID 0.
-----
EOL
fi
}

# Set Firebird configuration parameters from environment variables.
set_config() {
read_from_file_or_env 'FIREBIRD_USE_LEGACY_AUTH'
Expand Down Expand Up @@ -203,7 +222,7 @@ create_user() {
escaped_password=$(escape_sql_string "$FIREBIRD_PASSWORD")

# [Tabs ahead]
/opt/firebird/bin/isql -b security.db <<-EOL
/opt/firebird/bin/isql -b -user SYSDBA security.db <<-EOL
CREATE OR ALTER USER ${quoted_user}
PASSWORD '${escaped_password}'
GRANT ADMIN ROLE;
Expand All @@ -221,6 +240,9 @@ process_sql() {
# authentication, and the server then normalizes the name exactly like it
# normalized the database owner name, so DDL permissions work in init scripts.
isql_command+=( -u "$(unquote_sql_identifier "$(quote_sql_identifier "$FIREBIRD_USER")")" -p "$FIREBIRD_PASSWORD" )
else
# Local connections otherwise take the OS user name, which is SYSDBA only for root.
isql_command+=( -u SYSDBA )
fi

if [ -n "$FIREBIRD_DATABASE" ]; then
Expand Down Expand Up @@ -302,7 +324,7 @@ create_db() {
[ -n "$FIREBIRD_DATABASE_DEFAULT_CHARSET" ] && default_charset="DEFAULT CHARACTER SET $FIREBIRD_DATABASE_DEFAULT_CHARSET"

# [Tabs ahead]
/opt/firebird/bin/isql -b -q <<-EOL
/opt/firebird/bin/isql -b -q -user SYSDBA <<-EOL
CREATE DATABASE '${escaped_database}'
$user_and_password
$page_size
Expand Down Expand Up @@ -345,6 +367,7 @@ run_daemon_and_wait() {
# main()
#
if [ "$1" = 'firebird' ]; then
check_permissions
set_config
set_sysdba

Expand Down
17 changes: 15 additions & 2 deletions generated/3.0.10/noble/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,23 @@ ENV PATH=/opt/firebird/bin:$PATH

# Data directory
ENV FIREBIRD_DATA=/var/lib/firebird/data

# Non-root support: runtime-writable paths are owned by 'firebird' with group 0 (root), and group permissions equal
# owner permissions. The image still runs as root by default, but it also runs as 'firebird' (--user firebird) or as
# an arbitrary UID with GID 0 (OpenShift restricted SCC). Binaries, libraries and plugins stay owned by root.
# The data directory is a VOLUME: its ownership must be set here, in the image layer.
# Lock and shared memory files left in /tmp/firebird by the installer are removed (Firebird recreates them at runtime).
# See DECISIONS.md D-020 and https://github.com/FirebirdSQL/firebird-docker/issues/46
RUN set -eux; \
mkdir -p "$FIREBIRD_DATA"; \
chown -R firebird:firebird "$FIREBIRD_DATA"; \
chmod 755 "$FIREBIRD_DATA"
rm -rf /tmp/firebird/*; \
cd /opt/firebird; \
for f in . SYSDBA.password firebird.conf firebird.log fb_guard replication.log security*.fdb /tmp/firebird "$FIREBIRD_DATA"; do \
if [ -e "$f" ]; then \
chown firebird:0 "$f"; \
chmod g=u,o-w "$f"; \
fi; \
done
VOLUME $FIREBIRD_DATA

# Entrypoint
Expand Down
27 changes: 25 additions & 2 deletions generated/3.0.10/noble/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ indent() {
sed 's/^/ /';
}

# Warns when a non-root user cannot write to Firebird runtime files.
# Supported non-root users are 'firebird' and any UID with GID 0 (e.g. OpenShift restricted SCC).
check_permissions() {
if [ "$(id -u)" = '0' ]; then
return
fi

if [ ! -w /opt/firebird ] || [ ! -w "$FIREBIRD_DATA" ]; then
# [Tabs ahead]
cat >&2 <<-EOL
-----
WARNING: Running as UID $(id -u) / GID $(id -g), which cannot write to /opt/firebird or $FIREBIRD_DATA.

Run the container as root, as user 'firebird' (UID 84), or as any UID with GID 0.
-----
EOL
fi
}

# Set Firebird configuration parameters from environment variables.
set_config() {
read_from_file_or_env 'FIREBIRD_USE_LEGACY_AUTH'
Expand Down Expand Up @@ -203,7 +222,7 @@ create_user() {
escaped_password=$(escape_sql_string "$FIREBIRD_PASSWORD")

# [Tabs ahead]
/opt/firebird/bin/isql -b security.db <<-EOL
/opt/firebird/bin/isql -b -user SYSDBA security.db <<-EOL
CREATE OR ALTER USER ${quoted_user}
PASSWORD '${escaped_password}'
GRANT ADMIN ROLE;
Expand All @@ -221,6 +240,9 @@ process_sql() {
# authentication, and the server then normalizes the name exactly like it
# normalized the database owner name, so DDL permissions work in init scripts.
isql_command+=( -u "$(unquote_sql_identifier "$(quote_sql_identifier "$FIREBIRD_USER")")" -p "$FIREBIRD_PASSWORD" )
else
# Local connections otherwise take the OS user name, which is SYSDBA only for root.
isql_command+=( -u SYSDBA )
fi

if [ -n "$FIREBIRD_DATABASE" ]; then
Expand Down Expand Up @@ -302,7 +324,7 @@ create_db() {
[ -n "$FIREBIRD_DATABASE_DEFAULT_CHARSET" ] && default_charset="DEFAULT CHARACTER SET $FIREBIRD_DATABASE_DEFAULT_CHARSET"

# [Tabs ahead]
/opt/firebird/bin/isql -b -q <<-EOL
/opt/firebird/bin/isql -b -q -user SYSDBA <<-EOL
CREATE DATABASE '${escaped_database}'
$user_and_password
$page_size
Expand Down Expand Up @@ -345,6 +367,7 @@ run_daemon_and_wait() {
# main()
#
if [ "$1" = 'firebird' ]; then
check_permissions
set_config
set_sysdba

Expand Down
Loading
Loading