Improve security and modernize Docker configuration

- Replace deprecated MAINTAINER with LABEL and add OCI metadata
- Pin Alpine version via ARG for reproducible builds
- Fix command injection vulnerability by replacing eval with safe parser
- Modernize docker-compose: remove version, add resource limits
- Move passwords to environment variables instead of hardcoded values
- Improve healthcheck with start-period and retries
- Add .env.example template and update .gitignore

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Struchkov Mark
2026-01-07 16:17:15 +03:00
parent 183f0a8642
commit 1ee7f1ae6e
5 changed files with 62 additions and 15 deletions

8
.env.example Normal file
View File

@@ -0,0 +1,8 @@
# Samba configuration
# Copy this file to .env and set your values
# User passwords
SAMBA_BOB_PASSWORD=changeme
# Timezone
TZ=EST5EDT

4
.gitignore vendored
View File

@@ -1 +1,3 @@
.idea/
.idea/
.env
.DS_Store

View File

@@ -1,5 +1,9 @@
FROM hub.docker.struchkov.dev/alpine:latest
MAINTAINER Struchkov Mark <mark@struchkov.dev>
ARG ALPINE_VERSION=3.21
FROM hub.docker.struchkov.dev/alpine:${ALPINE_VERSION}
LABEL maintainer="Struchkov Mark <mark@struchkov.dev>"
LABEL org.opencontainers.image.source="https://github.com/upagge/samba"
LABEL org.opencontainers.image.description="Samba file server with Time Machine support"
# Install samba
RUN apk --no-cache --no-progress upgrade && \
@@ -59,8 +63,8 @@ COPY samba.sh /usr/bin/
EXPOSE 137/udp 138/udp 139 445
HEALTHCHECK --interval=60s --timeout=15s \
CMD smbclient -L \\localhost -U % -m SMB3
HEALTHCHECK --interval=60s --timeout=15s --start-period=10s --retries=3 \
CMD smbclient -L \\localhost -U % -m SMB3 || exit 1
VOLUME ["/etc", "/var/cache/samba", "/var/lib/samba", "/var/log/samba",\
"/run/samba"]

View File

@@ -1,10 +1,15 @@
version: '3.4'
services:
samba:
image: docker.struchkov.dev/samba
environment:
TZ: 'EST5EDT'
# Use environment variables for shares and users instead of command line
# SHARE: "Mount;/mnt"
# SHARE2: "Bobs Volume;/mnt2;yes;no;no;bob"
# USER: "bob;${SAMBA_BOB_PASSWORD}"
# PERMISSIONS: "true"
env_file:
- .env # Put sensitive data like passwords here
networks:
- default
ports:
@@ -21,7 +26,13 @@ services:
volumes:
- /mnt:/mnt:z
- /mnt2:/mnt2:z
command: '-s "Mount;/mnt" -s "Bobs Volume;/mnt2;yes;no;no;bob" -u "bob;bobspasswd" -p'
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 128M
command: '-s "Mount;/mnt" -s "Bobs Volume;/mnt2;yes;no;no;bob" -u "bob;${SAMBA_BOB_PASSWORD:-changeme}" -p'
networks:
default:
default:

View File

@@ -18,6 +18,28 @@
set -o nounset # Treat unset variables as an error
### parse_args: safely parse semicolon-separated arguments
# Arguments:
# input) semicolon-separated string
# Return: array PARSED_ARGS with parsed values
parse_args() {
local input="$1"
PARSED_ARGS=()
local current=""
local i=0
while [ $i -lt ${#input} ]; do
local char="${input:$i:1}"
if [ "$char" = ";" ]; then
PARSED_ARGS+=("$current")
current=""
else
current+="$char"
fi
i=$((i + 1))
done
PARSED_ARGS+=("$current")
}
### charmap: setup character mapping for file/directory names
# Arguments:
# chars) from:to character mappings separated by ','
@@ -245,15 +267,15 @@ while getopts ":hc:G:g:i:nprs:Su:Ww:I:" opt; do
case "$opt" in
h) usage ;;
c) charmap "$OPTARG" ;;
G) eval generic $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;;
G) parse_args "$OPTARG"; generic "${PARSED_ARGS[@]}" ;;
g) global "$OPTARG" ;;
i) import "$OPTARG" ;;
n) NMBD="true" ;;
p) PERMISSIONS="true" ;;
r) recycle ;;
s) eval share $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;;
s) parse_args "$OPTARG"; share "${PARSED_ARGS[@]}" ;;
S) smb ;;
u) eval user $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;;
u) parse_args "$OPTARG"; user "${PARSED_ARGS[@]}" ;;
w) workgroup "$OPTARG" ;;
W) widelinks ;;
I) include "$OPTARG" ;;
@@ -265,7 +287,7 @@ shift $(( OPTIND - 1 ))
[[ "${CHARMAP:-""}" ]] && charmap "$CHARMAP"
while read i; do
eval generic $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i)
parse_args "$i"; generic "${PARSED_ARGS[@]}"
done < <(env | awk '/^GENERIC[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
while read i; do
global "$i"
@@ -273,11 +295,11 @@ done < <(env | awk '/^GLOBAL[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
[[ "${IMPORT:-""}" ]] && import "$IMPORT"
[[ "${RECYCLE:-""}" ]] && recycle
while read i; do
eval share $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i)
parse_args "$i"; share "${PARSED_ARGS[@]}"
done < <(env | awk '/^SHARE[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
[[ "${SMB:-""}" ]] && smb
while read i; do
eval user $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i)
parse_args "$i"; user "${PARSED_ARGS[@]}"
done < <(env | awk '/^USER[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
[[ "${WORKGROUP:-""}" ]] && workgroup "$WORKGROUP"
[[ "${WIDELINKS:-""}" ]] && widelinks