mirror of
https://github.com/retspen/webvirtcloud
synced 2026-10-18 00:50:07 +00:00
fix(security): resolve reviewer findings on secret key baking, host symlinks, and injection safety
- Prevent baking SECRET_KEY into Docker image during collectstatic - Persist runtime SECRET_KEY in data/secret_key volume or read from environment - Remove sed-based injection of CSRF_TRUSTED_ORIGINS in favor of native os.getenv - Avoid overwriting system python3 symlink on SUSE; auto-detect python 3.10+ binaries - Make /etc/hosts entry in installer idempotent - Add security notice regarding compute node VNC/SPICE port firewall isolation
This commit is contained in:
parent
b1a843e846
commit
7435d66492
5 changed files with 42 additions and 58 deletions
10
Dockerfile
10
Dockerfile
|
|
@ -42,15 +42,11 @@ RUN python3 -m venv --system-site-packages venv && \
|
||||||
# Copy application source
|
# Copy application source
|
||||||
COPY . /srv/webvirtcloud
|
COPY . /srv/webvirtcloud
|
||||||
|
|
||||||
# Setup build-time settings, run collectstatic, and set permissions
|
# Run collectstatic with temporary dummy key, then remove temporary settings file
|
||||||
RUN . venv/bin/activate && \
|
RUN . venv/bin/activate && \
|
||||||
if [ ! -f webvirtcloud/settings.py ]; then \
|
|
||||||
cp webvirtcloud/settings.py.template webvirtcloud/settings.py && \
|
cp webvirtcloud/settings.py.template webvirtcloud/settings.py && \
|
||||||
python3 -c 'import secrets; print(secrets.token_urlsafe(50))' > /tmp/secret_key && \
|
SECRET_KEY="build-dummy-key-only-for-collectstatic" python3 manage.py collectstatic --noinput && \
|
||||||
sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"$(cat /tmp/secret_key)\"|" webvirtcloud/settings.py && \
|
rm -f webvirtcloud/settings.py && \
|
||||||
rm -f /tmp/secret_key; \
|
|
||||||
fi && \
|
|
||||||
python3 manage.py collectstatic --noinput && \
|
|
||||||
chown -R www-data:www-data /srv/webvirtcloud
|
chown -R www-data:www-data /srv/webvirtcloud
|
||||||
|
|
||||||
# Setup Nginx
|
# Setup Nginx
|
||||||
|
|
|
||||||
16
README.md
16
README.md
|
|
@ -170,21 +170,17 @@ sudo systemctl restart nginx supervisord
|
||||||
# 1. Install system prerequisites (Python 3.11 stack and C bindings)
|
# 1. Install system prerequisites (Python 3.11 stack and C bindings)
|
||||||
sudo zypper --non-interactive install -y git hostname python311 python311-base python311-devel python311-pip python311-libvirt-python python311-lxml python311-ldap libvirt-devel cyrus-sasl-devel libopenssl-devel gcc pkg-config nginx
|
sudo zypper --non-interactive install -y git hostname python311 python311-base python311-devel python311-pip python311-libvirt-python python311-lxml python311-ldap libvirt-devel cyrus-sasl-devel libopenssl-devel gcc pkg-config nginx
|
||||||
|
|
||||||
# Ensure python3 points to Python 3.11
|
|
||||||
sudo ln -sf /usr/bin/python3.11 /usr/bin/python3
|
|
||||||
sudo ln -sf /usr/bin/pip3.11 /usr/bin/pip3
|
|
||||||
|
|
||||||
# 2. Clone repository to /srv/webvirtcloud
|
# 2. Clone repository to /srv/webvirtcloud
|
||||||
sudo git clone https://github.com/retspen/webvirtcloud /srv/webvirtcloud
|
sudo git clone https://github.com/retspen/webvirtcloud /srv/webvirtcloud
|
||||||
cd /srv/webvirtcloud
|
cd /srv/webvirtcloud
|
||||||
|
|
||||||
# 3. Configure settings
|
# 3. Configure settings
|
||||||
cp webvirtcloud/settings.py.template webvirtcloud/settings.py
|
cp webvirtcloud/settings.py.template webvirtcloud/settings.py
|
||||||
SECRET_KEY=$(python3 conf/runit/secret_generator.py)
|
SECRET_KEY=$(python3.11 conf/runit/secret_generator.py)
|
||||||
sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"${SECRET_KEY}\"|" webvirtcloud/settings.py
|
sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"${SECRET_KEY}\"|" webvirtcloud/settings.py
|
||||||
|
|
||||||
# 4. Create virtual environment and install dependencies
|
# 4. Create virtual environment and install dependencies
|
||||||
python3 -m venv --system-site-packages venv
|
python3.11 -m venv --system-site-packages venv
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
pip install -r conf/requirements.txt
|
pip install -r conf/requirements.txt
|
||||||
|
|
||||||
|
|
@ -251,10 +247,9 @@ python manage.py runserver 0.0.0.0:8000
|
||||||
```bash
|
```bash
|
||||||
# 1. Install system prerequisites
|
# 1. Install system prerequisites
|
||||||
sudo zypper --non-interactive install -y git hostname python311 python311-base python311-devel python311-pip python311-libvirt-python python311-lxml python311-ldap libvirt-devel cyrus-sasl-devel libopenssl-devel gcc pkg-config
|
sudo zypper --non-interactive install -y git hostname python311 python311-base python311-devel python311-pip python311-libvirt-python python311-lxml python311-ldap libvirt-devel cyrus-sasl-devel libopenssl-devel gcc pkg-config
|
||||||
sudo ln -sf /usr/bin/python3.11 /usr/bin/python3
|
|
||||||
|
|
||||||
# 2. Create virtual environment with system site packages
|
# 2. Create virtual environment with system site packages
|
||||||
python3 -m venv --system-site-packages .venv
|
python3.11 -m venv --system-site-packages .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
|
|
||||||
# 3. Install Python dependencies
|
# 3. Install Python dependencies
|
||||||
|
|
@ -263,7 +258,7 @@ pip install -r dev/requirements.txt
|
||||||
|
|
||||||
# 4. Initialize configuration and run local dev server
|
# 4. Initialize configuration and run local dev server
|
||||||
cp webvirtcloud/settings.py.template webvirtcloud/settings.py
|
cp webvirtcloud/settings.py.template webvirtcloud/settings.py
|
||||||
sed -i -E 's/SECRET_KEY = .*/SECRET_KEY = "'$(python3 conf/runit/secret_generator.py)'"/' webvirtcloud/settings.py
|
sed -i -E 's/SECRET_KEY = .*/SECRET_KEY = "'$(python3.11 conf/runit/secret_generator.py)'"/' webvirtcloud/settings.py
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
python manage.py runserver 0.0.0.0:8000
|
python manage.py runserver 0.0.0.0:8000
|
||||||
```
|
```
|
||||||
|
|
@ -326,6 +321,9 @@ sudo dnf install -y dmidecode && sudo systemctl restart libvirtd
|
||||||
sudo zypper install -y dmidecode && sudo systemctl restart libvirtd
|
sudo zypper install -y dmidecode && sudo systemctl restart libvirtd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Security Notice (Compute Node Firewall):**
|
||||||
|
> Libvirt compute nodes listen on VNC/SPICE ports (`5900`–`65535`) to allow WebVirtCloud to proxy graphical consoles. Ensure your firewall (`ufw`, `firewalld`, or `iptables`) restricts these ports to accept connections **only** from the WebVirtCloud panel IP, and never exposes them directly to public networks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Configuration & Operational Notes
|
## Configuration & Operational Notes
|
||||||
|
|
|
||||||
|
|
@ -11,22 +11,13 @@ if [ ! -f "$APP_DIR/webvirtcloud/settings.py" ]; then
|
||||||
cp "$APP_DIR/webvirtcloud/settings.py.template" "$APP_DIR/webvirtcloud/settings.py"
|
cp "$APP_DIR/webvirtcloud/settings.py.template" "$APP_DIR/webvirtcloud/settings.py"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set SECRET_KEY if placeholder exists
|
# Ensure SECRET_KEY is persisted across container restarts if not supplied via environment
|
||||||
if grep -q 'SECRET_KEY = ""' "$APP_DIR/webvirtcloud/settings.py" || grep -q "SECRET_KEY = ''" "$APP_DIR/webvirtcloud/settings.py"; then
|
if [ -z "$SECRET_KEY" ]; then
|
||||||
KEY="${SECRET_KEY:-$("$APP_DIR/venv/bin/python3" -c 'import secrets; print(secrets.token_urlsafe(50))')}"
|
if [ ! -s "$DATA_DIR/secret_key" ]; then
|
||||||
sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"${KEY}\"|" "$APP_DIR/webvirtcloud/settings.py"
|
echo "* Generating fresh random SECRET_KEY..."
|
||||||
fi
|
"$APP_DIR/venv/bin/python3" -c 'import secrets; print(secrets.token_urlsafe(50))' > "$DATA_DIR/secret_key"
|
||||||
|
chmod 600 "$DATA_DIR/secret_key"
|
||||||
# Configure CSRF_TRUSTED_ORIGINS if environment variable is set
|
fi
|
||||||
if [ -n "$CSRF_TRUSTED_ORIGINS" ]; then
|
|
||||||
echo "* Setting CSRF_TRUSTED_ORIGINS from environment..."
|
|
||||||
origins=""
|
|
||||||
IFS=',' read -ra ADDR <<< "$CSRF_TRUSTED_ORIGINS"
|
|
||||||
for o in "${ADDR[@]}"; do
|
|
||||||
clean_o=$(echo "$o" | xargs)
|
|
||||||
[ -n "$clean_o" ] && origins="${origins}'${clean_o}', "
|
|
||||||
done
|
|
||||||
sed -i "s|^CSRF_TRUSTED_ORIGINS = .*|CSRF_TRUSTED_ORIGINS = [ ${origins} ]|" "$APP_DIR/webvirtcloud/settings.py"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Persist SQLite database in DATA_DIR
|
# Persist SQLite database in DATA_DIR
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ readonly APP_REPO_URL="${APP_REPO_URL:-https://github.com/retspen/webvirtcloud.g
|
||||||
readonly APP_NAME="webvirtcloud"
|
readonly APP_NAME="webvirtcloud"
|
||||||
readonly APP_PATH="/srv/$APP_NAME"
|
readonly APP_PATH="/srv/$APP_NAME"
|
||||||
|
|
||||||
readonly PYTHON="python3"
|
PYTHON="python3"
|
||||||
|
|
||||||
progress () {
|
progress () {
|
||||||
spin[0]="-"
|
spin[0]="-"
|
||||||
|
|
@ -238,26 +238,26 @@ run_as_app_user () {
|
||||||
}
|
}
|
||||||
|
|
||||||
check_python () {
|
check_python () {
|
||||||
|
# dynamically find python >= 3.10 if default python3 is older
|
||||||
|
for py_bin in python3.11 python3.12 python3.13 python3.10 python3; do
|
||||||
|
if command -v "$py_bin" >/dev/null 2>&1; then
|
||||||
|
if "$py_bin" -c 'import sys; sys.exit(0 if sys.version_info >= (3, 10) else 1)' >/dev/null 2>&1; then
|
||||||
|
PYTHON="$py_bin"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# check if python3 is installed.
|
# check if python3 is installed.
|
||||||
if ! hash "$PYTHON" 2>/dev/null; then
|
if ! hash "$PYTHON" 2>/dev/null; then
|
||||||
echo "Python3 is not installed. Please install Python3 and try again."
|
echo "Python3 is not installed. Please install Python3 and try again."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# check if python3 version is grater than 3.10 amd set it as default
|
# check if python3 version is greater than 3.10
|
||||||
if ! "$PYTHON" -c 'import sys; assert sys.version_info >= (3, 10)' >/dev/null 2>&1; then
|
if ! "$PYTHON" -c 'import sys; assert sys.version_info >= (3, 10)' >/dev/null 2>&1; then
|
||||||
echo "Your Python version is less than 3.10. This script requires Python 3.10 or greater."
|
echo "Your Python version is less than 3.10. This script requires Python 3.10 or greater."
|
||||||
echo "Please install Python 3.10 or greater and set it as the default version."
|
echo "Please install Python 3.10 or greater (such as python311) and try again."
|
||||||
echo "Use update-alternatives command to set default python version to latest."
|
|
||||||
echo "For example: sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 1"
|
|
||||||
echo "Then run this script again."
|
|
||||||
echo "Do not forget to install pip3 and python3-devel for python3.10 or later."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# check if pip3 is installed
|
|
||||||
if ! hash pip3 2>/dev/null; then
|
|
||||||
echo "pip3 is not installed. Please install pip3 and try again."
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -367,7 +367,9 @@ set_hosts () {
|
||||||
echo "* Setting up hosts file."
|
echo "* Setting up hosts file."
|
||||||
local hname
|
local hname
|
||||||
hname="$(hostname 2>/dev/null || uname -n)"
|
hname="$(hostname 2>/dev/null || uname -n)"
|
||||||
|
if ! grep -q "$fqdn" /etc/hosts 2>/dev/null; then
|
||||||
echo >> /etc/hosts "127.0.0.1 $hname $fqdn"
|
echo >> /etc/hosts "127.0.0.1 $hname $fqdn"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_supervisor () {
|
restart_supervisor () {
|
||||||
|
|
@ -750,16 +752,6 @@ case $distro in
|
||||||
fi
|
fi
|
||||||
install_packages
|
install_packages
|
||||||
|
|
||||||
# Ensure python3 and pip3 point to python 3.11+ if installed
|
|
||||||
if command -v python3.11 >/dev/null 2>&1; then
|
|
||||||
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1 2>/dev/null || true
|
|
||||||
ln -sf /usr/bin/python3.11 /usr/bin/python3
|
|
||||||
if command -v pip3.11 >/dev/null 2>&1; then
|
|
||||||
update-alternatives --install /usr/bin/pip3 pip3 /usr/bin/pip3.11 1 2>/dev/null || true
|
|
||||||
ln -sf /usr/bin/pip3.11 /usr/bin/pip3
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
set_hosts
|
set_hosts
|
||||||
|
|
||||||
# Supervisor on SUSE (available as python3-supervisor, supervisor, or via pip)
|
# Supervisor on SUSE (available as python3-supervisor, supervisor, or via pip)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,14 @@ from pathlib import Path
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
SECRET_KEY = ""
|
SECRET_KEY = os.getenv("SECRET_KEY", "")
|
||||||
|
if not SECRET_KEY:
|
||||||
|
secret_file = BASE_DIR / "data" / "secret_key"
|
||||||
|
if secret_file.exists():
|
||||||
|
try:
|
||||||
|
SECRET_KEY = secret_file.read_text().strip()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue