From b8b395e8b5dcc98da33c5a589b44f73d36edace4 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Sat, 11 Jul 2026 18:37:51 +0200 Subject: [PATCH] Run SMB dev connector as non-root --- dev/connectors/README.md | 8 +++++ dev/connectors/docker-compose.yml | 8 ++--- dev/connectors/smb/Dockerfile | 23 ++++++++++-- dev/connectors/smb/entrypoint.sh | 60 +++++++++++++++++++++++-------- 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/dev/connectors/README.md b/dev/connectors/README.md index 57c73ad..1087b37 100644 --- a/dev/connectors/README.md +++ b/dev/connectors/README.md @@ -9,6 +9,7 @@ binds services to localhost high ports. ```bash cd /mnt/DATA/git/govoplan-files/dev/connectors cp .env.example .env +mkdir -p data/smb data/webdav docker compose up -d nextcloud nextcloud-db webdav smb docker compose up -d seafile-db seafile-memcached seafile ``` @@ -128,3 +129,10 @@ the script: The SMB service is built from `dev/connectors/smb/` so the development share is deterministic: one `files` share backed by `data/smb`, with the credentials from `.env`. + +The SMB image runs as the non-root `govoplan` user with UID/GID `1000` and +listens on unprivileged container port `1445`. The default host endpoint remains +`smb://127.0.0.1:1445/files`. `SMB_USER` must stay `govoplan` unless the image is +rebuilt with a matching user; `SMB_PORT` must be `1024` or higher. `SMB_PASSWORD` +is applied when the image is built, so rebuild the `smb` service after changing +it in `.env`. diff --git a/dev/connectors/docker-compose.yml b/dev/connectors/docker-compose.yml index 4e0a914..2921ae3 100644 --- a/dev/connectors/docker-compose.yml +++ b/dev/connectors/docker-compose.yml @@ -86,16 +86,16 @@ services: smb: build: context: ./smb + args: + SMB_PASSWORD: ${SMB_PASSWORD:-govoplan-smb} image: govoplan-files-samba-dev:latest restart: unless-stopped environment: SMB_SHARE_NAME: ${SMB_SHARE_NAME:-files} SMB_USER: ${SMB_USER:-govoplan} - SMB_PASSWORD: ${SMB_PASSWORD:-govoplan-smb} - SMB_UID: ${SMB_UID:-1000} - SMB_GID: ${SMB_GID:-1000} + SMB_PORT: ${SMB_PORT:-1445} ports: - - "127.0.0.1:${SMB_HOST_PORT:-1445}:445" + - "127.0.0.1:${SMB_HOST_PORT:-1445}:${SMB_PORT:-1445}" volumes: - ./data/smb:/storage diff --git a/dev/connectors/smb/Dockerfile b/dev/connectors/smb/Dockerfile index 304d5a8..1b61123 100644 --- a/dev/connectors/smb/Dockerfile +++ b/dev/connectors/smb/Dockerfile @@ -1,10 +1,29 @@ FROM alpine:3.20 -RUN apk add --no-cache samba-server samba-common-tools +ARG SMB_PASSWORD=govoplan-smb + +RUN apk add --no-cache samba-server samba-common-tools \ + && addgroup -S -g 1000 govoplan \ + && adduser -S -D -H -h /nonexistent -s /sbin/nologin -u 1000 -G govoplan govoplan \ + && mkdir -p /storage /var/lib/samba/private /var/cache/samba /run/samba /etc/samba /var/log/samba/cores \ + && printf '%s\n' \ + '[global]' \ + ' passdb backend = tdbsam' \ + ' private dir = /var/lib/samba/private' \ + ' lock directory = /run/samba' \ + ' state directory = /var/lib/samba' \ + ' cache directory = /var/cache/samba' \ + ' pid directory = /run/samba' \ + > /etc/samba/smb.conf \ + && printf '%s\n%s\n' "$SMB_PASSWORD" "$SMB_PASSWORD" | smbpasswd -s -a govoplan \ + && smbpasswd -e govoplan \ + && chown -R govoplan:govoplan /storage /var/lib/samba /var/cache/samba /run/samba /etc/samba /var/log/samba COPY entrypoint.sh /usr/local/bin/govoplan-samba-entrypoint RUN chmod +x /usr/local/bin/govoplan-samba-entrypoint -EXPOSE 445 +EXPOSE 1445 + +USER govoplan:govoplan ENTRYPOINT ["/usr/local/bin/govoplan-samba-entrypoint"] diff --git a/dev/connectors/smb/entrypoint.sh b/dev/connectors/smb/entrypoint.sh index 27aa56c..4aff8d3 100644 --- a/dev/connectors/smb/entrypoint.sh +++ b/dev/connectors/smb/entrypoint.sh @@ -3,21 +3,42 @@ set -eu share_name="${SMB_SHARE_NAME:-files}" user_name="${SMB_USER:-govoplan}" -password="${SMB_PASSWORD:-govoplan-smb}" -uid="${SMB_UID:-1000}" -gid="${SMB_GID:-1000}" +smb_port="${SMB_PORT:-1445}" +runtime_user="$(id -un)" +runtime_group="$(id -gn)" -mkdir -p /storage /var/lib/samba/private /run/samba +case "$share_name" in + "" | *[!A-Za-z0-9_.-]*) + printf 'SMB_SHARE_NAME must contain only letters, numbers, dot, dash, or underscore.\n' >&2 + exit 1 + ;; +esac -if ! getent group "$user_name" >/dev/null 2>&1; then - addgroup -g "$gid" "$user_name" +case "$user_name" in + "" | *[!A-Za-z0-9_.-]*) + printf 'SMB_USER must contain only letters, numbers, dot, dash, or underscore.\n' >&2 + exit 1 + ;; +esac + +case "$smb_port" in + "" | *[!0-9]*) + printf 'SMB_PORT must be numeric.\n' >&2 + exit 1 + ;; +esac + +if [ "$smb_port" -lt 1024 ]; then + printf 'SMB_PORT must be >= 1024 because the dev Samba container runs as a non-root user.\n' >&2 + exit 1 fi -if ! id "$user_name" >/dev/null 2>&1; then - adduser -D -H -s /sbin/nologin -u "$uid" -G "$user_name" "$user_name" +if [ "$user_name" != "$runtime_user" ]; then + printf 'SMB_USER=%s is not supported by the non-root dev image; use %s or rebuild the image with a matching user.\n' "$user_name" "$runtime_user" >&2 + exit 1 fi -chown -R "$user_name:$user_name" /storage +mkdir -p /storage /var/lib/samba/private /var/cache/samba /run/samba /etc/samba cat > /etc/samba/smb.conf < /etc/samba/smb.conf < /etc/samba/smb.conf </dev/null -smbpasswd -e "$user_name" >/dev/null +if ! pdbedit -L -u "$user_name" >/dev/null 2>&1; then + printf 'Samba user %s is missing from passdb. Rebuild the smb image so the non-root passdb is seeded.\n' "$user_name" >&2 + printf 'Run: docker compose build --no-cache smb && docker compose up -d smb\n' >&2 + exit 1 +fi -exec smbd --foreground --no-process-group --debug-stdout +exec smbd --foreground --no-process-group --debug-stdout -p "$smb_port"