1
0
Fork 0
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:
catborise 2026-09-25 22:06:16 +03:00
parent b1a843e846
commit 7435d66492
5 changed files with 42 additions and 58 deletions

View file

@ -42,15 +42,11 @@ RUN python3 -m venv --system-site-packages venv && \
# Copy application source
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 && \
if [ ! -f webvirtcloud/settings.py ]; then \
cp webvirtcloud/settings.py.template webvirtcloud/settings.py && \
python3 -c 'import secrets; print(secrets.token_urlsafe(50))' > /tmp/secret_key && \
sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"$(cat /tmp/secret_key)\"|" webvirtcloud/settings.py && \
rm -f /tmp/secret_key; \
fi && \
python3 manage.py collectstatic --noinput && \
cp webvirtcloud/settings.py.template webvirtcloud/settings.py && \
SECRET_KEY="build-dummy-key-only-for-collectstatic" python3 manage.py collectstatic --noinput && \
rm -f webvirtcloud/settings.py && \
chown -R www-data:www-data /srv/webvirtcloud
# Setup Nginx

View file

@ -170,21 +170,17 @@ sudo systemctl restart nginx supervisord
# 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
# 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
sudo git clone https://github.com/retspen/webvirtcloud /srv/webvirtcloud
cd /srv/webvirtcloud
# 3. Configure settings
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
# 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
pip install -r conf/requirements.txt
@ -251,10 +247,9 @@ python manage.py runserver 0.0.0.0:8000
```bash
# 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 ln -sf /usr/bin/python3.11 /usr/bin/python3
# 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
# 3. Install Python dependencies
@ -263,7 +258,7 @@ pip install -r dev/requirements.txt
# 4. Initialize configuration and run local dev server
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 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
```
> **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

View file

@ -11,22 +11,13 @@ if [ ! -f "$APP_DIR/webvirtcloud/settings.py" ]; then
cp "$APP_DIR/webvirtcloud/settings.py.template" "$APP_DIR/webvirtcloud/settings.py"
fi
# Set SECRET_KEY if placeholder exists
if grep -q 'SECRET_KEY = ""' "$APP_DIR/webvirtcloud/settings.py" || grep -q "SECRET_KEY = ''" "$APP_DIR/webvirtcloud/settings.py"; then
KEY="${SECRET_KEY:-$("$APP_DIR/venv/bin/python3" -c 'import secrets; print(secrets.token_urlsafe(50))')}"
sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"${KEY}\"|" "$APP_DIR/webvirtcloud/settings.py"
fi
# Configure CSRF_TRUSTED_ORIGINS if environment variable is set
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"
# Ensure SECRET_KEY is persisted across container restarts if not supplied via environment
if [ -z "$SECRET_KEY" ]; then
if [ ! -s "$DATA_DIR/secret_key" ]; then
echo "* Generating fresh random SECRET_KEY..."
"$APP_DIR/venv/bin/python3" -c 'import secrets; print(secrets.token_urlsafe(50))' > "$DATA_DIR/secret_key"
chmod 600 "$DATA_DIR/secret_key"
fi
fi
# Persist SQLite database in DATA_DIR

View file

@ -71,7 +71,7 @@ readonly APP_REPO_URL="${APP_REPO_URL:-https://github.com/retspen/webvirtcloud.g
readonly APP_NAME="webvirtcloud"
readonly APP_PATH="/srv/$APP_NAME"
readonly PYTHON="python3"
PYTHON="python3"
progress () {
spin[0]="-"
@ -238,26 +238,26 @@ run_as_app_user () {
}
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.
if ! hash "$PYTHON" 2>/dev/null; then
echo "Python3 is not installed. Please install Python3 and try again."
exit 1
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
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 "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."
echo "Please install Python 3.10 or greater (such as python311) and try again."
exit 1
fi
}
@ -367,7 +367,9 @@ set_hosts () {
echo "* Setting up hosts file."
local hname
hname="$(hostname 2>/dev/null || uname -n)"
echo >> /etc/hosts "127.0.0.1 $hname $fqdn"
if ! grep -q "$fqdn" /etc/hosts 2>/dev/null; then
echo >> /etc/hosts "127.0.0.1 $hname $fqdn"
fi
}
restart_supervisor () {
@ -750,16 +752,6 @@ case $distro in
fi
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
# Supervisor on SUSE (available as python3-supervisor, supervisor, or via pip)

View file

@ -17,7 +17,14 @@ from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
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