mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
fix(docker): require explicit root credentials (#4278)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Executable
+77
@@ -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
|
||||
Reference in New Issue
Block a user