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
40 changes: 37 additions & 3 deletions build/scripts/orchestrated/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,40 @@ else
REDIS_CLUSTER=''
fi

# --------------------------------------------------------------------
# Fail closed on insecure default secrets.
#
# The standalone image generates and persists random secrets, but cluster
# pods are ephemeral and run as multiple replicas behind a shared proxy: a
# per-pod generated secret would differ across replicas and break JWT /
# secure-link verification. Secrets must therefore be supplied explicitly
# (e.g. via a Kubernetes Secret). Refuse to start with the known upstream
# placeholder values ("secret" / "verysecretstring") when the corresponding
# feature is enabled, rather than silently accepting forgeable tokens.
# --------------------------------------------------------------------
JWT_ENABLED_EFF="${JWT_ENABLED:-true}"
JWT_ENABLED_INBOX_EFF="${JWT_ENABLED_INBOX:-$JWT_ENABLED_EFF}"
JWT_ENABLED_OUTBOX_EFF="${JWT_ENABLED_OUTBOX:-$JWT_ENABLED_EFF}"

# browser/session verify with JWT_SECRET directly; inbox/outbox fall back to it.
if [ "$JWT_ENABLED_EFF" = "true" ] && [ -z "${JWT_SECRET:-}" ]; then
echo "ERROR: JWT browser verification is enabled (JWT_ENABLED=true) but JWT_SECRET is not set. Provide a strong JWT_SECRET (e.g. via a Kubernetes Secret) or set JWT_ENABLED=false. Refusing to start with an insecure default." >&2
exit 1
fi
if [ "$JWT_ENABLED_INBOX_EFF" = "true" ] && [ -z "${JWT_SECRET_INBOX:-}" ] && [ -z "${JWT_SECRET:-}" ]; then
echo "ERROR: inbox JWT is enabled but neither JWT_SECRET_INBOX nor JWT_SECRET is set. Refusing to start with an insecure default." >&2
exit 1
fi
if [ "$JWT_ENABLED_OUTBOX_EFF" = "true" ] && [ -z "${JWT_SECRET_OUTBOX:-}" ] && [ -z "${JWT_SECRET:-}" ]; then
echo "ERROR: outbox JWT is enabled but neither JWT_SECRET_OUTBOX nor JWT_SECRET is set. Refusing to start with an insecure default." >&2
exit 1
fi

if [ -z "${SECURE_LINK_SECRET:-}" ]; then
echo "ERROR: SECURE_LINK_SECRET is not set. It signs internal cache/file URLs and must be identical across all Docs and proxy replicas. Provide a strong shared value (e.g. via a Kubernetes Secret). Refusing to start with an insecure default." >&2
exit 1
fi

# --------------------------------------------------------------------
# NODE_CONFIG (exported for Docs services)
# --------------------------------------------------------------------
Expand Down Expand Up @@ -135,7 +169,7 @@ export NODE_CONFIG='{
},
"secret": {
"inbox": {
"string": "'${JWT_SECRET_INBOX:-${JWT_SECRET:=secret}}'"
"string": "'${JWT_SECRET_INBOX:-${JWT_SECRET}}'"
},
"outbox": {
"string": "'${JWT_SECRET_OUTBOX:-${JWT_SECRET}}'"
Expand Down Expand Up @@ -190,14 +224,14 @@ export NODE_CONFIG='{
"storage": {
"fs": {
"folderPath": "/var/lib/'${COMPANY_NAME}'/documentserver/App_Data/cache/files/'${STORAGE_SUBDIRECTORY_NAME:-latest}'",
"secretString": "'${SECURE_LINK_SECRET:-verysecretstring}'"
"secretString": "'${SECURE_LINK_SECRET}'"
},
"storageFolderName": "files/'${STORAGE_SUBDIRECTORY_NAME:-latest}'"
},
"persistentStorage": {
"fs": {
"folderPath": "/var/lib/'${COMPANY_NAME}'/documentserver/App_Data/cache/files",
"secretString": "'${SECURE_LINK_SECRET:-verysecretstring}'"
"secretString": "'${SECURE_LINK_SECRET}'"
},
"storageFolderName": "files"
}
Expand Down
18 changes: 16 additions & 2 deletions build/scripts/orchestrated/proxy-docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
#!/usr/bin/env bash
set -e

# Fail closed on an insecure default secure-link secret. This value signs the
# internal cache/file URLs and MUST be identical to the one the Docs replicas
# use (see docker-entrypoint.sh), so it cannot be generated per-pod — it has to
# be supplied explicitly (e.g. via a Kubernetes Secret). Refuse to start with
# the known upstream placeholder rather than serve forgeable signed URLs.
if [ -z "${SECURE_LINK_SECRET:-}" ]; then
echo "ERROR: SECURE_LINK_SECRET is not set. Provide a strong shared value matching the Docs replicas (e.g. via a Kubernetes Secret). Refusing to start with an insecure default." >&2
exit 1
fi

if ! [ -d /tmp/proxy_nginx ]; then
mkdir /tmp/proxy_nginx
fi
Expand All @@ -19,7 +29,7 @@ fi

envsubst < /tmp/proxy_nginx/includes/http-upstream.conf > /tmp/http-upstream.conf
envsubst < /etc/nginx/includes/ds-common.conf | tee /tmp/proxy_nginx/includes/ds-common.conf > /dev/null
sed "s,\(set \+\$secure_link_secret\).*,\1 "${SECURE_LINK_SECRET:-verysecretstring}";," -i /tmp/proxy_nginx/conf.d/ds.conf
sed "s,\(set \+\$secure_link_secret\).*,\1 "${SECURE_LINK_SECRET}";," -i /tmp/proxy_nginx/conf.d/ds.conf
sed "s/\(client_max_body_size\).*/\1 $NGINX_CLIENT_MAX_BODY_SIZE;/" -i /tmp/proxy_nginx/includes/ds-common.conf

if [[ ! -f "/proc/net/if_inet6" ]]; then
Expand Down Expand Up @@ -53,7 +63,11 @@ if [[ -n "$INFO_ALLOWED_IP" ]]; then
fi

if [[ -n "$INFO_ALLOWED_USER" ]]; then
htpasswd -c -b /tmp/auth "${INFO_ALLOWED_USER}" "${INFO_ALLOWED_PASSWORD:-password}"
if [[ -z "${INFO_ALLOWED_PASSWORD:-}" ]]; then
echo "ERROR: INFO_ALLOWED_USER is set but INFO_ALLOWED_PASSWORD is empty. Refusing to expose /info behind a default password." >&2
exit 1
fi
htpasswd -c -b /tmp/auth "${INFO_ALLOWED_USER}" "${INFO_ALLOWED_PASSWORD}"
sed -i '/(info)/a\ auth_basic \"Authentication Required\"\;' /tmp/proxy_nginx/includes/ds-docservice.conf
sed -i '/auth_basic/a\ auth_basic_user_file \/tmp\/auth\;' /tmp/proxy_nginx/includes/ds-docservice.conf
fi
Expand Down