fix(docker): require explicit root credentials (#4278)

This commit is contained in:
Zhengchao An
2026-07-05 10:31:28 +08:00
committed by GitHub
parent 26d6c06e03
commit 6b0fcb1180
4 changed files with 223 additions and 7 deletions
+1
View File
@@ -6,6 +6,7 @@ TEST_THREADS ?= 1
script-tests: ## Run shell script tests
@echo "Running script tests..."
./scripts/test_build_rustfs_options.sh
./scripts/test_entrypoint_credentials.sh
.PHONY: test
test: core-deps test-deps script-tests ## Run all tests
-2
View File
@@ -105,8 +105,6 @@ RUN groupadd -g 10001 rustfs && \
ENV RUSTFS_ADDRESS=":9000" \
RUSTFS_CONSOLE_ADDRESS=":9001" \
RUSTFS_ACCESS_KEY="rustfsadmin" \
RUSTFS_SECRET_KEY="rustfsadmin" \
RUSTFS_CONSOLE_ENABLE="true" \
RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS="*" \
RUSTFS_VOLUMES="/data" \
+145 -5
View File
@@ -21,6 +21,151 @@ else
set -- /usr/bin/rustfs "$@"
fi
DEFAULT_ROOT_CREDENTIAL="rustfsadmin"
resolve_credential_source() {
CREDENTIAL_ENV_NAME="$1"
CREDENTIAL_FILE_ENV_NAME="$2"
CREDENTIAL_VALUE_OPTION="$3"
CREDENTIAL_FILE_OPTION="$4"
shift 4
CREDENTIAL_DIRECT_SET=false
CREDENTIAL_DIRECT_VALUE=""
CREDENTIAL_FILE_SET=false
CREDENTIAL_FILE_VALUE=""
eval "CREDENTIAL_ENV_VALUE=\${$CREDENTIAL_ENV_NAME:-}"
eval "CREDENTIAL_ENV_FILE_VALUE=\${$CREDENTIAL_FILE_ENV_NAME:-}"
if [ -n "$CREDENTIAL_ENV_VALUE" ]; then
CREDENTIAL_DIRECT_SET=true
CREDENTIAL_DIRECT_VALUE="$CREDENTIAL_ENV_VALUE"
fi
if [ -n "$CREDENTIAL_ENV_FILE_VALUE" ]; then
CREDENTIAL_FILE_SET=true
CREDENTIAL_FILE_VALUE="$CREDENTIAL_ENV_FILE_VALUE"
fi
while [ "$#" -gt 0 ]; do
arg="$1"
case "$arg" in
--)
break
;;
--"$CREDENTIAL_VALUE_OPTION"=*)
CREDENTIAL_DIRECT_SET=true
CREDENTIAL_DIRECT_VALUE="${arg#*=}"
;;
--"$CREDENTIAL_VALUE_OPTION")
shift
if [ "$#" -eq 0 ]; then
echo "error:--$CREDENTIAL_VALUE_OPTION requires a value."
return
fi
CREDENTIAL_DIRECT_SET=true
CREDENTIAL_DIRECT_VALUE="$1"
;;
--"$CREDENTIAL_FILE_OPTION"=*)
CREDENTIAL_FILE_SET=true
CREDENTIAL_FILE_VALUE="${arg#*=}"
;;
--"$CREDENTIAL_FILE_OPTION")
shift
if [ "$#" -eq 0 ]; then
echo "error:--$CREDENTIAL_FILE_OPTION requires a value."
return
fi
CREDENTIAL_FILE_SET=true
CREDENTIAL_FILE_VALUE="$1"
;;
esac
shift
done
if [ "$CREDENTIAL_DIRECT_SET" = "true" ] && [ "$CREDENTIAL_FILE_SET" = "true" ]; then
echo "conflict"
return
fi
if [ "$CREDENTIAL_DIRECT_SET" = "true" ]; then
echo "value:$CREDENTIAL_DIRECT_VALUE"
return
fi
if [ "$CREDENTIAL_FILE_SET" = "true" ]; then
echo "file:$CREDENTIAL_FILE_VALUE"
return
fi
echo "missing"
}
validate_credential_source() {
CREDENTIAL_NAME="$1"
FILE_NAME="$2"
CREDENTIAL_SOURCE="$3"
case "$CREDENTIAL_SOURCE" in
error:*)
echo "ERROR: ${CREDENTIAL_SOURCE#error:}" >&2
exit 1
;;
conflict)
echo "ERROR: Set either $CREDENTIAL_NAME or $FILE_NAME, not both." >&2
exit 1
;;
missing)
echo "ERROR: $CREDENTIAL_NAME or $FILE_NAME must be set explicitly for container startup." >&2
exit 1
;;
value:*)
CREDENTIAL_VALUE="${CREDENTIAL_SOURCE#value:}"
if [ -z "$CREDENTIAL_VALUE" ]; then
echo "ERROR: $CREDENTIAL_NAME must not be empty." >&2
exit 1
fi
if [ "$CREDENTIAL_VALUE" = "$DEFAULT_ROOT_CREDENTIAL" ]; then
echo "ERROR: $CREDENTIAL_NAME must not use the default $DEFAULT_ROOT_CREDENTIAL credential." >&2
exit 1
fi
;;
file:*)
CREDENTIAL_FILE="${CREDENTIAL_SOURCE#file:}"
if [ -z "$CREDENTIAL_FILE" ]; then
echo "ERROR: $FILE_NAME must not be empty." >&2
exit 1
fi
if [ ! -r "$CREDENTIAL_FILE" ]; then
echo "ERROR: $FILE_NAME points to an unreadable file." >&2
exit 1
fi
if IFS= read -r CREDENTIAL_FILE_CONTENT < "$CREDENTIAL_FILE"; then
:
else
CREDENTIAL_FILE_CONTENT=""
fi
if [ -z "$CREDENTIAL_FILE_CONTENT" ]; then
echo "ERROR: $FILE_NAME must not be empty." >&2
exit 1
fi
if [ "$CREDENTIAL_FILE_CONTENT" = "$DEFAULT_ROOT_CREDENTIAL" ]; then
echo "ERROR: $FILE_NAME must not contain the default $DEFAULT_ROOT_CREDENTIAL credential." >&2
exit 1
fi
;;
esac
}
if [ "$1" = "/usr/bin/rustfs" ]; then
ACCESS_SOURCE=$(resolve_credential_source "RUSTFS_ACCESS_KEY" "RUSTFS_ACCESS_KEY_FILE" "access-key" "access-key-file" "$@")
SECRET_SOURCE=$(resolve_credential_source "RUSTFS_SECRET_KEY" "RUSTFS_SECRET_KEY_FILE" "secret-key" "secret-key-file" "$@")
validate_credential_source "RUSTFS_ACCESS_KEY" "RUSTFS_ACCESS_KEY_FILE" "$ACCESS_SOURCE"
validate_credential_source "RUSTFS_SECRET_KEY" "RUSTFS_SECRET_KEY_FILE" "$SECRET_SOURCE"
fi
# 2) Process data volumes (separate from log directory)
DATA_VOLUMES=""
process_data_volumes() {
@@ -112,11 +257,6 @@ process_log_directory() {
process_data_volumes
process_log_directory
# 4) Default credentials warning
if [ "${RUSTFS_ACCESS_KEY:-}" = "rustfsadmin" ] || [ "${RUSTFS_SECRET_KEY:-}" = "rustfsadmin" ]; then
echo "!!!WARNING: Using default RUSTFS_ACCESS_KEY or RUSTFS_SECRET_KEY. Override them in production!"
fi
# 5) Append DATA_VOLUMES only if no data paths in arguments
# Check if any argument looks like a data path (starts with / and not an option)
HAS_DATA_PATH=false
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT
ENTRYPOINT="$ROOT_DIR/entrypoint.sh"
DOCKERFILE_GLIBC="$ROOT_DIR/Dockerfile.glibc"
if grep -Eq 'RUSTFS_(ACCESS|SECRET)_KEY=' "$DOCKERFILE_GLIBC"; then
echo "Dockerfile.glibc must not bake root credentials into image ENV" >&2
exit 1
fi
run_expect_failure() {
label="$1"
expected="$2"
shift 2
log_file="$TMP_DIR/$label.log"
if env -i PATH="$PATH" RUSTFS_VOLUMES="$TMP_DIR/data" RUSTFS_OBS_LOG_DIRECTORY= "$@" sh "$ENTRYPOINT" rustfs >"$log_file" 2>&1; then
echo "Expected $label to fail" >&2
exit 1
fi
if ! grep -q "$expected" "$log_file"; then
echo "Expected $label output to contain: $expected" >&2
cat "$log_file" >&2
exit 1
fi
}
missing_log="$TMP_DIR/missing.log"
if env -i PATH="$PATH" RUSTFS_VOLUMES="$TMP_DIR/data" RUSTFS_OBS_LOG_DIRECTORY= sh "$ENTRYPOINT" >"$missing_log" 2>&1; then
echo "Expected missing credentials to fail" >&2
exit 1
fi
grep -q "RUSTFS_ACCESS_KEY or RUSTFS_ACCESS_KEY_FILE must be set explicitly" "$missing_log"
run_expect_failure \
"missing-secret" \
"RUSTFS_SECRET_KEY or RUSTFS_SECRET_KEY_FILE must be set explicitly" \
RUSTFS_ACCESS_KEY=custom-access
run_expect_failure \
"default-access-env" \
"RUSTFS_ACCESS_KEY must not use the default rustfsadmin credential" \
RUSTFS_ACCESS_KEY=rustfsadmin \
RUSTFS_SECRET_KEY=custom-secret
default_access_cli_log="$TMP_DIR/default-access-cli.log"
if env -i PATH="$PATH" RUSTFS_VOLUMES="$TMP_DIR/data" RUSTFS_OBS_LOG_DIRECTORY= RUSTFS_SECRET_KEY=custom-secret sh "$ENTRYPOINT" rustfs --access-key rustfsadmin >"$default_access_cli_log" 2>&1; then
echo "Expected default-access-cli to fail" >&2
exit 1
fi
grep -q "RUSTFS_ACCESS_KEY must not use the default rustfsadmin credential" "$default_access_cli_log"
default_access_file="$TMP_DIR/default-access-key"
printf 'rustfsadmin\n' >"$default_access_file"
run_expect_failure \
"default-access-file" \
"RUSTFS_ACCESS_KEY_FILE must not contain the default rustfsadmin credential" \
RUSTFS_ACCESS_KEY_FILE="$default_access_file" \
RUSTFS_SECRET_KEY=custom-secret
cargo_log="$TMP_DIR/cargo.log"
if ! env -i PATH="$PATH" RUSTFS_VOLUMES="$TMP_DIR/data" RUSTFS_OBS_LOG_DIRECTORY= sh "$ENTRYPOINT" cargo --version >"$cargo_log" 2>&1; then
echo "Expected cargo passthrough to skip server credential checks" >&2
cat "$cargo_log" >&2
exit 1
fi
if grep -q "must be set explicitly" "$cargo_log"; then
echo "Cargo passthrough must not require server credentials" >&2
cat "$cargo_log" >&2
exit 1
fi