Files
plane/deployments/aio/community/start.sh
Manish Gupta 1acc69e816 [WEB-7805] fix: remove hardcoded SECRET_KEY from community deployment manifests (#9291)
* fix: remove hardcoded SECRET_KEY from community deployment manifests (GHSA-cmwv-pjmw-8483)

Replace the publicly-known default SECRET_KEY and LIVE_SERVER_SECRET_KEY values
in AIO and CLI community deployment manifests with a safe placeholder.

- deployments/aio: variables.env now ships with placeholder values;
  start.sh auto-generates a random key on first boot (or on upgrade from the old
  insecure default) and persists it in plane.env across restarts
- deployments/cli: variables.env ships with placeholder; docker-compose.yml
  fallbacks that referenced the publicly-known default are removed
- apps/api/plane/settings/common.py: SECRET_KEY resolution now uses `or`
  so an empty env var falls back to get_random_secret_key() (not ""); adds a
  startup warning if the known insecure default or placeholder is detected

Closes WEB-7805

Co-authored-by: Plane AI <noreply@plane.so>

* fix: use logger.critical instead of print for insecure SECRET_KEY warning

Address code review feedback — replace module-level print() with _logger.critical()
and move _logger definition before the SECRET_KEY block to avoid duplicate assignment.
Also removes the now-unused `import sys`.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Plane AI <noreply@plane.so>
2026-06-23 17:59:19 +05:30

195 lines
6.6 KiB
Bash

#!/bin/bash -e
print_header(){
clear
echo "------------------------------------------------"
echo "Plane Community (All-In-One)"
echo "------------------------------------------------"
echo ""
echo "You are required to pass below environment variables to the script"
echo " DOMAIN_NAME, DATABASE_URL, REDIS_URL, AMQP_URL"
echo " AWS_REGION, AWS_ACCESS_KEY_ID"
echo " AWS_SECRET_ACCESS_KEY, AWS_S3_BUCKET_NAME"
echo ""
echo "Other optional environment variables: "
echo " SITE_ADDRESS (default: ':80')"
echo " FILE_SIZE_LIMIT (default: 5242880)"
echo " APP_PROTOCOL (http or https)"
echo " SECRET_KEY (auto-generated on first boot if not set)"
echo " LIVE_SERVER_SECRET_KEY (auto-generated on first boot if not set)"
echo ""
echo ""
}
check_required_env(){
echo "Checking required environment variables..."
local keys=("DOMAIN_NAME" "DATABASE_URL" "REDIS_URL" "AMQP_URL"
"AWS_REGION" "AWS_ACCESS_KEY_ID" "AWS_SECRET_ACCESS_KEY" "AWS_S3_BUCKET_NAME")
local missing_keys=()
# Check if the environment variable is set and not empty
for key in "${keys[@]}"; do
if [ -z "${!key}" ]; then
echo " ❌ '$key' is not set or is empty"
missing_keys+=("$key")
fi
done
if [ ${#missing_keys[@]} -gt 0 ]; then
echo ""
exit 1
fi
# add checkmark
echo "✅ Required environment variables are available"
echo ""
}
update_env_value(){
local key="$1"
local value="$2"
# check if the file exists
if [ ! -f "plane.env" ]; then
echo "plane.env file not found"
exit 1
fi
# check if the key exists and add it if it doesn't
if ! grep -q "^$key=.*" plane.env; then
echo "${key}=${value}" >> plane.env
return 0
fi
# if key and value are not empty, update the value
if [ -n "$key" ] && [ -n "$value" ]; then
sed -i "s|^$key=.*|$key=$value|" plane.env
return 0
fi
}
check_pre_requisites(){
check_required_env
# check if the file exists
if [ ! -f "plane.env" ]; then
echo "plane.env file not found"
exit 1
fi
# add a new line to the end of the file
echo "" >> plane.env
echo "" >> plane.env
echo "✅ Pre-requisites checked"
echo ""
}
validate_domain_name() {
local domain="$1"
# Check if it's an IP address first
if [[ "$domain" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "IP"
return 0
fi
# FQDN validation regex
local fqdn_regex='^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.?$'
if [[ "$domain" =~ $fqdn_regex ]]; then
# Additional checks
if [[ ${#domain} -le 253 ]] && [[ ! "$domain" =~ \.\. ]] && [[ ! "$domain" =~ ^- ]] && [[ ! "$domain" =~ -\. ]]; then
echo "FQDN"
return 0
fi
fi
echo "INVALID"
return 1
}
update_env_file(){
echo "Updating environment file..."
# check if DOMAIN_NAME is valid IP address
local domain_type=$(validate_domain_name "$DOMAIN_NAME")
if [ "$domain_type" == "INVALID" ]; then
echo "DOMAIN_NAME is not a valid FQDN or IP address"
exit 1
fi
local app_protocol=${APP_PROTOCOL:-http}
update_env_value "APP_PROTOCOL" "$app_protocol"
update_env_value "DOMAIN_NAME" "$DOMAIN_NAME"
update_env_value "APP_DOMAIN" "$DOMAIN_NAME"
if [ -n "$SITE_ADDRESS" ]; then
update_env_value "SITE_ADDRESS" "$SITE_ADDRESS"
else
update_env_value "SITE_ADDRESS" ":80"
fi
update_env_value "WEB_URL" "$app_protocol://$DOMAIN_NAME"
update_env_value "CORS_ALLOWED_ORIGINS" "http://$DOMAIN_NAME,https://$DOMAIN_NAME"
# update database url
update_env_value "DATABASE_URL" "$DATABASE_URL"
update_env_value "REDIS_URL" "$REDIS_URL"
update_env_value "AMQP_URL" "$AMQP_URL"
# update aws credentials
update_env_value "AWS_REGION" "$AWS_REGION"
update_env_value "AWS_ACCESS_KEY_ID" "$AWS_ACCESS_KEY_ID"
update_env_value "AWS_SECRET_ACCESS_KEY" "$AWS_SECRET_ACCESS_KEY"
update_env_value "AWS_S3_BUCKET_NAME" "$AWS_S3_BUCKET_NAME"
update_env_value "AWS_S3_ENDPOINT_URL" "${AWS_S3_ENDPOINT_URL:-https://s3.${AWS_REGION}.amazonaws.com}"
update_env_value "BUCKET_NAME" "$AWS_S3_BUCKET_NAME"
update_env_value "USE_MINIO" "0"
# Optional environment variables
# SECRET_KEY: if absent or set to a known placeholder/insecure value, preserve whatever
# is already stored in plane.env (survives restarts), or generate a fresh random value on
# first boot. Never write a publicly-known or placeholder value into plane.env.
local _insecure_sk="60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5"
local _placeholder_sk="change-this-key-on-deployment"
if [ -z "$SECRET_KEY" ] || [ "$SECRET_KEY" = "$_insecure_sk" ] || [ "$SECRET_KEY" = "$_placeholder_sk" ]; then
local _stored_sk
_stored_sk=$(grep "^SECRET_KEY=" plane.env 2>/dev/null | cut -d'=' -f2-)
if [ -n "$_stored_sk" ] && [ "$_stored_sk" != "$_insecure_sk" ] && [ "$_stored_sk" != "$_placeholder_sk" ]; then
SECRET_KEY="$_stored_sk"
else
SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c50)
fi
fi
update_env_value "SECRET_KEY" "$SECRET_KEY"
update_env_value "FILE_SIZE_LIMIT" "${FILE_SIZE_LIMIT:-5242880}"
# LIVE_SERVER_SECRET_KEY: same first-boot generation strategy.
local _insecure_lssk="htbqvBJAgpm9bzvf3r4urJer0ENReatceh"
local _placeholder_lssk="change-this-key-on-deployment"
if [ -z "$LIVE_SERVER_SECRET_KEY" ] || [ "$LIVE_SERVER_SECRET_KEY" = "$_insecure_lssk" ] || [ "$LIVE_SERVER_SECRET_KEY" = "$_placeholder_lssk" ]; then
local _stored_lssk
_stored_lssk=$(grep "^LIVE_SERVER_SECRET_KEY=" plane.env 2>/dev/null | cut -d'=' -f2-)
if [ -n "$_stored_lssk" ] && [ "$_stored_lssk" != "$_insecure_lssk" ] && [ "$_stored_lssk" != "$_placeholder_lssk" ]; then
LIVE_SERVER_SECRET_KEY="$_stored_lssk"
else
LIVE_SERVER_SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c50)
fi
fi
update_env_value "LIVE_SERVER_SECRET_KEY" "$LIVE_SERVER_SECRET_KEY"
update_env_value "API_KEY_RATE_LIMIT" "${API_KEY_RATE_LIMIT:-60/minute}"
echo "✅ Environment file updated"
echo ""
}
main(){
print_header
check_pre_requisites
update_env_file
# load plane.env as exported variables
export $(grep -v '^#' plane.env | xargs)
/usr/local/bin/supervisord -c /etc/supervisor/conf.d/supervisor.conf
}
main "$@"