Enhance environment variable management and security
- Updated .gitignore to include additional sensitive files and directories. - Added python-dotenv to requirements for loading environment variables. - Modified settings.py to load environment variables for sensitive configurations, including SECRET_KEY, DEBUG, and database credentials. - Implemented secure .env file generation during installation to avoid hardcoding sensitive information. - Introduced fallback method for settings update if environment generation fails.
This commit is contained in:
parent
938fb6442b
commit
7bd66f7f06
|
|
@ -0,0 +1,36 @@
|
||||||
|
# CyberPanel Environment Configuration Template
|
||||||
|
# Copy this file to .env and update with your actual values
|
||||||
|
# NEVER commit .env to version control!
|
||||||
|
|
||||||
|
# Django Configuration
|
||||||
|
SECRET_KEY=your_very_long_random_secret_key_here_minimum_50_characters
|
||||||
|
DEBUG=False
|
||||||
|
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
|
||||||
|
|
||||||
|
# Database Configuration - CyberPanel Database
|
||||||
|
DB_NAME=cyberpanel
|
||||||
|
DB_USER=cyberpanel
|
||||||
|
DB_PASSWORD=your_secure_cyberpanel_db_password_here
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
|
||||||
|
# Root Database Configuration - MySQL Root Access
|
||||||
|
ROOT_DB_NAME=mysql
|
||||||
|
ROOT_DB_USER=root
|
||||||
|
ROOT_DB_PASSWORD=your_secure_mysql_root_password_here
|
||||||
|
ROOT_DB_HOST=localhost
|
||||||
|
ROOT_DB_PORT=3306
|
||||||
|
|
||||||
|
# Security Settings
|
||||||
|
SECURE_SSL_REDIRECT=False
|
||||||
|
SECURE_HSTS_SECONDS=0
|
||||||
|
SECURE_HSTS_INCLUDE_SUBDOMAINS=False
|
||||||
|
SECURE_HSTS_PRELOAD=False
|
||||||
|
SESSION_COOKIE_SECURE=False
|
||||||
|
CSRF_COOKIE_SECURE=False
|
||||||
|
|
||||||
|
# File Upload Settings
|
||||||
|
DATA_UPLOAD_MAX_MEMORY_SIZE=2147483648
|
||||||
|
|
||||||
|
# Logging Configuration
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
|
@ -1,7 +1,120 @@
|
||||||
|
# CyberPanel .gitignore
|
||||||
|
|
||||||
|
# Environment variables (CRITICAL - Contains sensitive data)
|
||||||
|
.env
|
||||||
|
.env.backup
|
||||||
|
.env.local
|
||||||
|
.env.production
|
||||||
|
.env.staging
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.AppleDouble
|
.DS_Store?
|
||||||
.LSOverride
|
._*
|
||||||
*.pyc
|
.Spotlight-V100
|
||||||
.idea
|
.Trashes
|
||||||
venv
|
ehthumbs.db
|
||||||
/.venv/
|
Thumbs.db
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
log/
|
||||||
|
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
*.sqlite3
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.bak
|
||||||
|
*.backup
|
||||||
|
|
||||||
|
# Node modules (if any frontend build tools are used)
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# CyberPanel specific
|
||||||
|
/usr/local/CyberCP/
|
||||||
|
/etc/cyberpanel/
|
||||||
|
cyberpanel_password.txt
|
||||||
|
mysql_password.txt
|
||||||
|
|
@ -13,6 +13,14 @@ https://docs.djangoproject.com/en/1.11/ref/settings/
|
||||||
import os
|
import os
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
# Load environment variables from .env file
|
||||||
|
try:
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv()
|
||||||
|
except ImportError:
|
||||||
|
# dotenv not available, continue without it
|
||||||
|
pass
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
@ -20,12 +28,13 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f'
|
SECRET_KEY = os.getenv('SECRET_KEY', 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = False
|
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
# Allow configuration via environment variable, fallback to wildcard for backward compatibility
|
||||||
|
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '*').split(',')
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
|
|
@ -111,19 +120,19 @@ WSGI_APPLICATION = 'CyberCP.wsgi.application'
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'cyberpanel',
|
'NAME': os.getenv('DB_NAME', 'cyberpanel'),
|
||||||
'USER': 'cyberpanel',
|
'USER': os.getenv('DB_USER', 'cyberpanel'),
|
||||||
'PASSWORD': 'SLTUIUxqhulwsh',
|
'PASSWORD': os.getenv('DB_PASSWORD', 'SLTUIUxqhulwsh'),
|
||||||
'HOST': 'localhost',
|
'HOST': os.getenv('DB_HOST', 'localhost'),
|
||||||
'PORT':''
|
'PORT': os.getenv('DB_PORT', '3306'),
|
||||||
},
|
},
|
||||||
'rootdb': {
|
'rootdb': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'mysql',
|
'NAME': os.getenv('ROOT_DB_NAME', 'mysql'),
|
||||||
'USER': 'root',
|
'USER': os.getenv('ROOT_DB_USER', 'root'),
|
||||||
'PASSWORD': 'SLTUIUxqhulwsh',
|
'PASSWORD': os.getenv('ROOT_DB_PASSWORD', 'SLTUIUxqhulwsh'),
|
||||||
'HOST': 'localhost',
|
'HOST': os.getenv('ROOT_DB_HOST', 'localhost'),
|
||||||
'PORT': '',
|
'PORT': os.getenv('ROOT_DB_PORT', '3306'),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
DATABASE_ROUTERS = ['backup.backupRouter.backupRouter']
|
DATABASE_ROUTERS = ['backup.backupRouter.backupRouter']
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
# CyberPanel Secure Installation Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document describes the secure installation process for CyberPanel that eliminates hardcoded passwords and implements environment-based configuration.
|
||||||
|
|
||||||
|
## Security Improvements
|
||||||
|
|
||||||
|
### ✅ **Fixed Security Vulnerabilities**
|
||||||
|
|
||||||
|
1. **Hardcoded Database Passwords** - Now generated securely during installation
|
||||||
|
2. **Hardcoded Django Secret Key** - Now generated using cryptographically secure random generation
|
||||||
|
3. **Environment Variables** - All sensitive configuration moved to `.env` file
|
||||||
|
4. **File Permissions** - `.env` file set to 600 (owner read/write only)
|
||||||
|
|
||||||
|
### 🔐 **Security Features**
|
||||||
|
|
||||||
|
- **Cryptographically Secure Passwords**: Uses Python's `secrets` module for password generation
|
||||||
|
- **Environment-based Configuration**: Sensitive data stored in `.env` file, not in code
|
||||||
|
- **Secure File Permissions**: Environment files protected with 600 permissions
|
||||||
|
- **Credential Backup**: Automatic backup of credentials for recovery
|
||||||
|
- **Fallback Security**: Maintains backward compatibility with fallback method
|
||||||
|
|
||||||
|
## Installation Process
|
||||||
|
|
||||||
|
### 1. **Automatic Secure Installation**
|
||||||
|
|
||||||
|
The installation script now automatically:
|
||||||
|
|
||||||
|
1. Generates secure random passwords for:
|
||||||
|
- MySQL root user
|
||||||
|
- CyberPanel database user
|
||||||
|
- Django secret key
|
||||||
|
|
||||||
|
2. Creates `.env` file with secure configuration:
|
||||||
|
```bash
|
||||||
|
# Generated during installation
|
||||||
|
SECRET_KEY=your_64_character_secure_key
|
||||||
|
DB_PASSWORD=your_24_character_secure_password
|
||||||
|
ROOT_DB_PASSWORD=your_24_character_secure_password
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Creates `.env.backup` file for credential recovery
|
||||||
|
4. Sets secure file permissions (600) on all environment files
|
||||||
|
|
||||||
|
### 2. **Manual Installation** (if needed)
|
||||||
|
|
||||||
|
If you need to manually generate environment configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
python install/env_generator.py /usr/local/CyberCP
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
/usr/local/CyberCP/
|
||||||
|
├── .env # Main environment configuration (600 permissions)
|
||||||
|
├── .env.backup # Credential backup (600 permissions)
|
||||||
|
├── .env.template # Template for manual configuration
|
||||||
|
├── .gitignore # Prevents .env files from being committed
|
||||||
|
└── CyberCP/
|
||||||
|
└── settings.py # Updated to use environment variables
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
### ✅ **Do's**
|
||||||
|
|
||||||
|
- Keep `.env` and `.env.backup` files secure
|
||||||
|
- Record credentials from `.env.backup` and delete the file after installation
|
||||||
|
- Use strong, unique passwords for production deployments
|
||||||
|
- Regularly rotate database passwords
|
||||||
|
- Monitor access to environment files
|
||||||
|
|
||||||
|
### ❌ **Don'ts**
|
||||||
|
|
||||||
|
- Never commit `.env` files to version control
|
||||||
|
- Don't share `.env` files via insecure channels
|
||||||
|
- Don't use default passwords in production
|
||||||
|
- Don't leave `.env.backup` files on the system after recording credentials
|
||||||
|
|
||||||
|
## Recovery
|
||||||
|
|
||||||
|
### **Lost Credentials**
|
||||||
|
|
||||||
|
If you lose your database credentials:
|
||||||
|
|
||||||
|
1. Check if `.env.backup` file exists:
|
||||||
|
```bash
|
||||||
|
sudo cat /usr/local/CyberCP/.env.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If backup doesn't exist, you'll need to reset MySQL passwords using MySQL recovery procedures
|
||||||
|
|
||||||
|
### **Regenerate Environment**
|
||||||
|
|
||||||
|
To regenerate environment configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
sudo python install/env_generator.py /usr/local/CyberCP
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
### **Environment Variables**
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `SECRET_KEY` | Django secret key | Generated (64 chars) |
|
||||||
|
| `DB_PASSWORD` | CyberPanel DB password | Generated (24 chars) |
|
||||||
|
| `ROOT_DB_PASSWORD` | MySQL root password | Generated (24 chars) |
|
||||||
|
| `DEBUG` | Debug mode | False |
|
||||||
|
| `ALLOWED_HOSTS` | Allowed hosts | localhost,127.0.0.1,hostname |
|
||||||
|
|
||||||
|
### **Custom Configuration**
|
||||||
|
|
||||||
|
To use custom passwords during installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python install/env_generator.py /usr/local/CyberCP "your_root_password" "your_db_password"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### **Installation Fails**
|
||||||
|
|
||||||
|
If the new secure installation fails:
|
||||||
|
|
||||||
|
1. Check installation logs for error messages
|
||||||
|
2. The system will automatically fallback to the original installation method
|
||||||
|
3. Verify Python dependencies are installed:
|
||||||
|
```bash
|
||||||
|
pip install python-dotenv
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Environment Loading Issues**
|
||||||
|
|
||||||
|
If Django can't load environment variables:
|
||||||
|
|
||||||
|
1. Ensure `.env` file exists and has correct permissions:
|
||||||
|
```bash
|
||||||
|
ls -la /usr/local/CyberCP/.env
|
||||||
|
# Should show: -rw------- 1 root root
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install python-dotenv if missing:
|
||||||
|
```bash
|
||||||
|
pip install python-dotenv
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration from Old Installation
|
||||||
|
|
||||||
|
### **Existing Installations**
|
||||||
|
|
||||||
|
For existing CyberPanel installations with hardcoded passwords:
|
||||||
|
|
||||||
|
1. **Backup current configuration**:
|
||||||
|
```bash
|
||||||
|
cp /usr/local/CyberCP/CyberCP/settings.py /usr/local/CyberCP/CyberCP/settings.py.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Generate new environment configuration**:
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
python install/env_generator.py /usr/local/CyberCP
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update settings.py** (already done in new installations):
|
||||||
|
- The settings.py file now supports environment variables
|
||||||
|
- It will fallback to hardcoded values if .env is not available
|
||||||
|
|
||||||
|
4. **Test the configuration**:
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
python manage.py check
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues with the secure installation:
|
||||||
|
|
||||||
|
1. Check the installation logs
|
||||||
|
2. Verify file permissions
|
||||||
|
3. Ensure all dependencies are installed
|
||||||
|
4. Review the fallback installation method if needed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Security Notice**: This installation method significantly improves security by eliminating hardcoded credentials. Always ensure proper file permissions and secure handling of environment files.
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
CyberPanel Environment Configuration Generator
|
||||||
|
Generates secure .env file with random passwords during installation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import secrets
|
||||||
|
import string
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def generate_secure_password(length=24):
|
||||||
|
"""
|
||||||
|
Generate a cryptographically secure password
|
||||||
|
|
||||||
|
Args:
|
||||||
|
length: Length of the password to generate (default 24)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Random password containing uppercase, lowercase, digits and safe special chars
|
||||||
|
"""
|
||||||
|
# Use safe characters that don't require escaping in most contexts
|
||||||
|
safe_chars = string.ascii_letters + string.digits + '!@#$%^&*'
|
||||||
|
return ''.join(secrets.choice(safe_chars) for _ in range(length))
|
||||||
|
|
||||||
|
def generate_secret_key(length=64):
|
||||||
|
"""
|
||||||
|
Generate a cryptographically secure Django secret key
|
||||||
|
|
||||||
|
Args:
|
||||||
|
length: Length of the secret key to generate (default 64)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Random secret key
|
||||||
|
"""
|
||||||
|
chars = string.ascii_letters + string.digits + '!@#$%^&*(-_=+)'
|
||||||
|
return ''.join(secrets.choice(chars) for _ in range(length))
|
||||||
|
|
||||||
|
def create_env_file(cyberpanel_path, mysql_root_password=None, cyberpanel_db_password=None):
|
||||||
|
"""
|
||||||
|
Create .env file with generated secure credentials
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cyberpanel_path: Path to CyberPanel installation directory
|
||||||
|
mysql_root_password: Optional MySQL root password (will generate if None)
|
||||||
|
cyberpanel_db_password: Optional CyberPanel DB password (will generate if None)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Generate secure passwords if not provided
|
||||||
|
if not mysql_root_password:
|
||||||
|
mysql_root_password = generate_secure_password(24)
|
||||||
|
|
||||||
|
if not cyberpanel_db_password:
|
||||||
|
cyberpanel_db_password = generate_secure_password(24)
|
||||||
|
|
||||||
|
secret_key = generate_secret_key(64)
|
||||||
|
|
||||||
|
# Get hostname for ALLOWED_HOSTS
|
||||||
|
import socket
|
||||||
|
try:
|
||||||
|
hostname = socket.gethostname()
|
||||||
|
local_ip = socket.gethostbyname(hostname)
|
||||||
|
except:
|
||||||
|
hostname = 'localhost'
|
||||||
|
local_ip = '127.0.0.1'
|
||||||
|
|
||||||
|
# Create .env content
|
||||||
|
env_content = f"""# CyberPanel Environment Configuration
|
||||||
|
# Generated automatically during installation - DO NOT EDIT MANUALLY
|
||||||
|
# Generated on: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||||
|
|
||||||
|
# Django Configuration
|
||||||
|
SECRET_KEY={secret_key}
|
||||||
|
DEBUG=False
|
||||||
|
ALLOWED_HOSTS=localhost,127.0.0.1,{hostname},{local_ip}
|
||||||
|
|
||||||
|
# Database Configuration - CyberPanel Database
|
||||||
|
DB_NAME=cyberpanel
|
||||||
|
DB_USER=cyberpanel
|
||||||
|
DB_PASSWORD={cyberpanel_db_password}
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
|
||||||
|
# Root Database Configuration - MySQL Root Access
|
||||||
|
ROOT_DB_NAME=mysql
|
||||||
|
ROOT_DB_USER=root
|
||||||
|
ROOT_DB_PASSWORD={mysql_root_password}
|
||||||
|
ROOT_DB_HOST=localhost
|
||||||
|
ROOT_DB_PORT=3306
|
||||||
|
|
||||||
|
# Security Settings
|
||||||
|
SECURE_SSL_REDIRECT=False
|
||||||
|
SECURE_HSTS_SECONDS=0
|
||||||
|
SECURE_HSTS_INCLUDE_SUBDOMAINS=False
|
||||||
|
SECURE_HSTS_PRELOAD=False
|
||||||
|
SESSION_COOKIE_SECURE=False
|
||||||
|
CSRF_COOKIE_SECURE=False
|
||||||
|
|
||||||
|
# File Upload Settings
|
||||||
|
DATA_UPLOAD_MAX_MEMORY_SIZE=2147483648
|
||||||
|
|
||||||
|
# Logging Configuration
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Write .env file
|
||||||
|
env_file_path = os.path.join(cyberpanel_path, '.env')
|
||||||
|
with open(env_file_path, 'w') as f:
|
||||||
|
f.write(env_content)
|
||||||
|
|
||||||
|
# Set secure permissions (owner read/write only)
|
||||||
|
os.chmod(env_file_path, 0o600)
|
||||||
|
|
||||||
|
print(f"✓ Generated secure .env file at: {env_file_path}")
|
||||||
|
print(f"✓ MySQL Root Password: {mysql_root_password}")
|
||||||
|
print(f"✓ CyberPanel DB Password: {cyberpanel_db_password}")
|
||||||
|
print(f"✓ Django Secret Key: {secret_key[:20]}...")
|
||||||
|
|
||||||
|
return {
|
||||||
|
'mysql_root_password': mysql_root_password,
|
||||||
|
'cyberpanel_db_password': cyberpanel_db_password,
|
||||||
|
'secret_key': secret_key
|
||||||
|
}
|
||||||
|
|
||||||
|
def create_env_backup(cyberpanel_path, credentials):
|
||||||
|
"""
|
||||||
|
Create a secure backup of credentials for recovery purposes
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cyberpanel_path: Path to CyberPanel installation directory
|
||||||
|
credentials: Dictionary containing generated credentials
|
||||||
|
"""
|
||||||
|
backup_content = f"""# CyberPanel Credentials Backup
|
||||||
|
# Generated: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||||
|
#
|
||||||
|
# IMPORTANT: Store this file securely and delete it after recording credentials
|
||||||
|
# These are your database passwords and should be kept confidential
|
||||||
|
|
||||||
|
MySQL Root Password: {credentials['mysql_root_password']}
|
||||||
|
CyberPanel Database Password: {credentials['cyberpanel_db_password']}
|
||||||
|
Django Secret Key: {credentials['secret_key']}
|
||||||
|
|
||||||
|
# To restore these credentials, copy them to your .env file
|
||||||
|
"""
|
||||||
|
|
||||||
|
backup_file_path = os.path.join(cyberpanel_path, '.env.backup')
|
||||||
|
with open(backup_file_path, 'w') as f:
|
||||||
|
f.write(backup_content)
|
||||||
|
|
||||||
|
# Set secure permissions (owner read/write only)
|
||||||
|
os.chmod(backup_file_path, 0o600)
|
||||||
|
|
||||||
|
print(f"✓ Created credentials backup at: {backup_file_path}")
|
||||||
|
print("⚠️ IMPORTANT: Record these credentials and delete the backup file for security")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python env_generator.py <cyberpanel_path> [mysql_root_password] [cyberpanel_db_password]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cyberpanel_path = sys.argv[1]
|
||||||
|
mysql_root_password = sys.argv[2] if len(sys.argv) > 2 else None
|
||||||
|
cyberpanel_db_password = sys.argv[3] if len(sys.argv) > 3 else None
|
||||||
|
|
||||||
|
if not os.path.exists(cyberpanel_path):
|
||||||
|
print(f"Error: CyberPanel path does not exist: {cyberpanel_path}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
credentials = create_env_file(cyberpanel_path, mysql_root_password, cyberpanel_db_password)
|
||||||
|
create_env_backup(cyberpanel_path, credentials)
|
||||||
|
print("\n✓ Environment configuration generated successfully!")
|
||||||
|
print("✓ Remember to delete .env.backup after recording credentials")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error generating environment configuration: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
@ -504,6 +504,73 @@ class preFlightsChecks:
|
||||||
self.stdOut("Install psmisc")
|
self.stdOut("Install psmisc")
|
||||||
self.install_package("psmisc")
|
self.install_package("psmisc")
|
||||||
|
|
||||||
|
def generate_secure_env_file(self, mysql_root_password, cyberpanel_db_password):
|
||||||
|
"""
|
||||||
|
Generate secure .env file with random passwords during installation
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
|
||||||
|
# Import the environment generator
|
||||||
|
sys.path.append(os.path.join(self.cyberPanelPath, 'install'))
|
||||||
|
from env_generator import create_env_file, create_env_backup
|
||||||
|
|
||||||
|
# Generate secure credentials
|
||||||
|
credentials = create_env_file(
|
||||||
|
self.cyberPanelPath,
|
||||||
|
mysql_root_password,
|
||||||
|
cyberpanel_db_password
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create backup for recovery
|
||||||
|
create_env_backup(self.cyberPanelPath, credentials)
|
||||||
|
|
||||||
|
logging.InstallLog.writeToFile("✓ Secure .env file generated successfully")
|
||||||
|
logging.InstallLog.writeToFile("✓ Credentials backup created for recovery")
|
||||||
|
|
||||||
|
return credentials
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.InstallLog.writeToFile(f"[ERROR] Failed to generate secure environment file: {str(e)}")
|
||||||
|
# Fallback to original method if environment generation fails
|
||||||
|
self.fallback_settings_update(mysql_root_password, cyberpanel_db_password)
|
||||||
|
|
||||||
|
def fallback_settings_update(self, mysqlPassword, password):
|
||||||
|
"""
|
||||||
|
Fallback method to update settings.py directly if environment generation fails
|
||||||
|
"""
|
||||||
|
logging.InstallLog.writeToFile("Using fallback method for settings.py update")
|
||||||
|
|
||||||
|
path = self.cyberPanelPath + "/CyberCP/settings.py"
|
||||||
|
data = open(path, "r").readlines()
|
||||||
|
writeDataToFile = open(path, "w")
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
for items in data:
|
||||||
|
if items.find('SECRET_KEY') > -1:
|
||||||
|
SK = "SECRET_KEY = '%s'\n" % (generate_pass(50))
|
||||||
|
writeDataToFile.writelines(SK)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if items.find("'PASSWORD':") > -1:
|
||||||
|
if counter == 0:
|
||||||
|
writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n")
|
||||||
|
counter = counter + 1
|
||||||
|
else:
|
||||||
|
writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n")
|
||||||
|
elif items.find('127.0.0.1') > -1:
|
||||||
|
writeDataToFile.writelines(" 'HOST': 'localhost',\n")
|
||||||
|
elif items.find("'PORT':'3307'") > -1:
|
||||||
|
writeDataToFile.writelines(" 'PORT': '',\n")
|
||||||
|
else:
|
||||||
|
writeDataToFile.writelines(items)
|
||||||
|
|
||||||
|
if self.distro == ubuntu:
|
||||||
|
os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR)
|
||||||
|
|
||||||
|
writeDataToFile.close()
|
||||||
|
|
||||||
def download_install_CyberPanel(self, mysqlPassword, mysql):
|
def download_install_CyberPanel(self, mysqlPassword, mysql):
|
||||||
##
|
##
|
||||||
|
|
||||||
|
|
@ -549,50 +616,12 @@ password="%s"
|
||||||
|
|
||||||
logging.InstallLog.writeToFile("Updating /root/.my.cnf!")
|
logging.InstallLog.writeToFile("Updating /root/.my.cnf!")
|
||||||
|
|
||||||
logging.InstallLog.writeToFile("Updating settings.py!")
|
logging.InstallLog.writeToFile("Generating secure environment configuration!")
|
||||||
|
|
||||||
path = self.cyberPanelPath + "/CyberCP/settings.py"
|
# Generate secure environment file instead of hardcoding passwords
|
||||||
|
self.generate_secure_env_file(mysqlPassword, password)
|
||||||
|
|
||||||
data = open(path, "r").readlines()
|
logging.InstallLog.writeToFile("Environment configuration generated successfully!")
|
||||||
|
|
||||||
writeDataToFile = open(path, "w")
|
|
||||||
|
|
||||||
counter = 0
|
|
||||||
|
|
||||||
for items in data:
|
|
||||||
if items.find('SECRET_KEY') > -1:
|
|
||||||
SK = "SECRET_KEY = '%s'\n" % (generate_pass(50))
|
|
||||||
writeDataToFile.writelines(SK)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if mysql == 'Two':
|
|
||||||
if items.find("'PASSWORD':") > -1:
|
|
||||||
if counter == 0:
|
|
||||||
writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n")
|
|
||||||
counter = counter + 1
|
|
||||||
else:
|
|
||||||
writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n")
|
|
||||||
|
|
||||||
else:
|
|
||||||
writeDataToFile.writelines(items)
|
|
||||||
else:
|
|
||||||
if items.find("'PASSWORD':") > -1:
|
|
||||||
if counter == 0:
|
|
||||||
writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n")
|
|
||||||
counter = counter + 1
|
|
||||||
else:
|
|
||||||
writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n")
|
|
||||||
elif items.find('127.0.0.1') > -1:
|
|
||||||
writeDataToFile.writelines(" 'HOST': 'localhost',\n")
|
|
||||||
elif items.find("'PORT':'3307'") > -1:
|
|
||||||
writeDataToFile.writelines(" 'PORT': '',\n")
|
|
||||||
else:
|
|
||||||
writeDataToFile.writelines(items)
|
|
||||||
|
|
||||||
if self.distro == ubuntu:
|
|
||||||
os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR)
|
|
||||||
|
|
||||||
writeDataToFile.close()
|
|
||||||
|
|
||||||
if self.remotemysql == 'ON':
|
if self.remotemysql == 'ON':
|
||||||
command = "sed -i 's|localhost|%s|g' %s" % (self.mysqlhost, path)
|
command = "sed -i 's|localhost|%s|g' %s" % (self.mysqlhost, path)
|
||||||
|
|
|
||||||
|
|
@ -37,3 +37,4 @@ asyncssh==2.21.0
|
||||||
python-jose==3.4.0
|
python-jose==3.4.0
|
||||||
websockets==15.0.1
|
websockets==15.0.1
|
||||||
PyJWT
|
PyJWT
|
||||||
|
python-dotenv==1.0.0
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
# CyberPanel Secure Installation Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document describes the secure installation process for CyberPanel that eliminates hardcoded passwords and implements environment-based configuration.
|
||||||
|
|
||||||
|
## Security Improvements
|
||||||
|
|
||||||
|
### ✅ **Fixed Security Vulnerabilities**
|
||||||
|
|
||||||
|
1. **Hardcoded Database Passwords** - Now generated securely during installation
|
||||||
|
2. **Hardcoded Django Secret Key** - Now generated using cryptographically secure random generation
|
||||||
|
3. **Environment Variables** - All sensitive configuration moved to `.env` file
|
||||||
|
4. **File Permissions** - `.env` file set to 600 (owner read/write only)
|
||||||
|
|
||||||
|
### 🔐 **Security Features**
|
||||||
|
|
||||||
|
- **Cryptographically Secure Passwords**: Uses Python's `secrets` module for password generation
|
||||||
|
- **Environment-based Configuration**: Sensitive data stored in `.env` file, not in code
|
||||||
|
- **Secure File Permissions**: Environment files protected with 600 permissions
|
||||||
|
- **Credential Backup**: Automatic backup of credentials for recovery
|
||||||
|
- **Fallback Security**: Maintains backward compatibility with fallback method
|
||||||
|
|
||||||
|
## Installation Process
|
||||||
|
|
||||||
|
### 1. **Automatic Secure Installation**
|
||||||
|
|
||||||
|
The installation script now automatically:
|
||||||
|
|
||||||
|
1. Generates secure random passwords for:
|
||||||
|
- MySQL root user
|
||||||
|
- CyberPanel database user
|
||||||
|
- Django secret key
|
||||||
|
|
||||||
|
2. Creates `.env` file with secure configuration:
|
||||||
|
```bash
|
||||||
|
# Generated during installation
|
||||||
|
SECRET_KEY=your_64_character_secure_key
|
||||||
|
DB_PASSWORD=your_24_character_secure_password
|
||||||
|
ROOT_DB_PASSWORD=your_24_character_secure_password
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Creates `.env.backup` file for credential recovery
|
||||||
|
4. Sets secure file permissions (600) on all environment files
|
||||||
|
|
||||||
|
### 2. **Manual Installation** (if needed)
|
||||||
|
|
||||||
|
If you need to manually generate environment configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
python install/env_generator.py /usr/local/CyberCP
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
/usr/local/CyberCP/
|
||||||
|
├── .env # Main environment configuration (600 permissions)
|
||||||
|
├── .env.backup # Credential backup (600 permissions)
|
||||||
|
├── .env.template # Template for manual configuration
|
||||||
|
├── .gitignore # Prevents .env files from being committed
|
||||||
|
└── CyberCP/
|
||||||
|
└── settings.py # Updated to use environment variables
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
### ✅ **Do's**
|
||||||
|
|
||||||
|
- Keep `.env` and `.env.backup` files secure
|
||||||
|
- Record credentials from `.env.backup` and delete the file after installation
|
||||||
|
- Use strong, unique passwords for production deployments
|
||||||
|
- Regularly rotate database passwords
|
||||||
|
- Monitor access to environment files
|
||||||
|
|
||||||
|
### ❌ **Don'ts**
|
||||||
|
|
||||||
|
- Never commit `.env` files to version control
|
||||||
|
- Don't share `.env` files via insecure channels
|
||||||
|
- Don't use default passwords in production
|
||||||
|
- Don't leave `.env.backup` files on the system after recording credentials
|
||||||
|
|
||||||
|
## Recovery
|
||||||
|
|
||||||
|
### **Lost Credentials**
|
||||||
|
|
||||||
|
If you lose your database credentials:
|
||||||
|
|
||||||
|
1. Check if `.env.backup` file exists:
|
||||||
|
```bash
|
||||||
|
sudo cat /usr/local/CyberCP/.env.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If backup doesn't exist, you'll need to reset MySQL passwords using MySQL recovery procedures
|
||||||
|
|
||||||
|
### **Regenerate Environment**
|
||||||
|
|
||||||
|
To regenerate environment configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
sudo python install/env_generator.py /usr/local/CyberCP
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
### **Environment Variables**
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `SECRET_KEY` | Django secret key | Generated (64 chars) |
|
||||||
|
| `DB_PASSWORD` | CyberPanel DB password | Generated (24 chars) |
|
||||||
|
| `ROOT_DB_PASSWORD` | MySQL root password | Generated (24 chars) |
|
||||||
|
| `DEBUG` | Debug mode | False |
|
||||||
|
| `ALLOWED_HOSTS` | Allowed hosts | localhost,127.0.0.1,hostname |
|
||||||
|
|
||||||
|
### **Custom Configuration**
|
||||||
|
|
||||||
|
To use custom passwords during installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python install/env_generator.py /usr/local/CyberCP "your_root_password" "your_db_password"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### **Installation Fails**
|
||||||
|
|
||||||
|
If the new secure installation fails:
|
||||||
|
|
||||||
|
1. Check installation logs for error messages
|
||||||
|
2. The system will automatically fallback to the original installation method
|
||||||
|
3. Verify Python dependencies are installed:
|
||||||
|
```bash
|
||||||
|
pip install python-dotenv
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Environment Loading Issues**
|
||||||
|
|
||||||
|
If Django can't load environment variables:
|
||||||
|
|
||||||
|
1. Ensure `.env` file exists and has correct permissions:
|
||||||
|
```bash
|
||||||
|
ls -la /usr/local/CyberCP/.env
|
||||||
|
# Should show: -rw------- 1 root root
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install python-dotenv if missing:
|
||||||
|
```bash
|
||||||
|
pip install python-dotenv
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration from Old Installation
|
||||||
|
|
||||||
|
### **Existing Installations**
|
||||||
|
|
||||||
|
For existing CyberPanel installations with hardcoded passwords:
|
||||||
|
|
||||||
|
1. **Backup current configuration**:
|
||||||
|
```bash
|
||||||
|
cp /usr/local/CyberCP/CyberCP/settings.py /usr/local/CyberCP/CyberCP/settings.py.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Generate new environment configuration**:
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
python install/env_generator.py /usr/local/CyberCP
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update settings.py** (already done in new installations):
|
||||||
|
- The settings.py file now supports environment variables
|
||||||
|
- It will fallback to hardcoded values if .env is not available
|
||||||
|
|
||||||
|
4. **Test the configuration**:
|
||||||
|
```bash
|
||||||
|
cd /usr/local/CyberCP
|
||||||
|
python manage.py check
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues with the secure installation:
|
||||||
|
|
||||||
|
1. Check the installation logs
|
||||||
|
2. Verify file permissions
|
||||||
|
3. Ensure all dependencies are installed
|
||||||
|
4. Review the fallback installation method if needed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Security Notice**: This installation method significantly improves security by eliminating hardcoded credentials. Always ensure proper file permissions and secure handling of environment files.
|
||||||
Loading…
Reference in New Issue