auto-claude: 4.3 - Create security documentation explaining credential management
Created comprehensive docs/SECURITY.md with: - Database credentials management guide (CWE-798 security) - Complete environment variables reference - Development and production setup instructions - Shell script configuration (.pgpass, PGPASSWORD) - Security best practices (never hardcode credentials) - Verification and testing procedures - Troubleshooting guide for common issues - Incident response procedures for compromised credentials - Links to official documentation and security standards This completes Phase 4 (Documentation) of the credential security cleanup task.
This commit is contained in:
parent
1a2edef536
commit
f85b3261ab
636
docs/SECURITY.md
Normal file
636
docs/SECURITY.md
Normal file
@ -0,0 +1,636 @@
|
|||||||
|
# Security Guide - Norda Biznes Hub
|
||||||
|
|
||||||
|
**Last Updated:** 2026-01-10
|
||||||
|
**Status:** Active
|
||||||
|
**Severity:** CRITICAL - Follow all guidelines
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Overview](#overview)
|
||||||
|
2. [Database Credentials Management](#database-credentials-management)
|
||||||
|
3. [Environment Variables Reference](#environment-variables-reference)
|
||||||
|
4. [Development Environment Setup](#development-environment-setup)
|
||||||
|
5. [Production Environment Setup](#production-environment-setup)
|
||||||
|
6. [Shell Script Configuration](#shell-script-configuration)
|
||||||
|
7. [Security Best Practices](#security-best-practices)
|
||||||
|
8. [Verification and Testing](#verification-and-testing)
|
||||||
|
9. [Troubleshooting](#troubleshooting)
|
||||||
|
10. [Incident Response](#incident-response)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document provides comprehensive guidance on securely configuring database credentials and API keys for the Norda Biznes Hub platform. Following these guidelines is **mandatory** to prevent security vulnerabilities and protect sensitive data.
|
||||||
|
|
||||||
|
### Security Vulnerability: CWE-798
|
||||||
|
|
||||||
|
**CWE-798: Use of Hard-coded Credentials** is a critical security vulnerability that occurs when passwords, API keys, or other sensitive credentials are embedded directly in source code. This practice:
|
||||||
|
|
||||||
|
- ❌ Exposes credentials if repository becomes public
|
||||||
|
- ❌ Makes credential rotation extremely difficult
|
||||||
|
- ❌ Violates compliance frameworks (OWASP, PCI-DSS, SOC 2)
|
||||||
|
- ❌ Creates audit trail of credentials in Git history
|
||||||
|
- ❌ Allows unauthorized access if code is compromised
|
||||||
|
|
||||||
|
**ALL credentials MUST be stored in environment variables, NEVER in source code.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database Credentials Management
|
||||||
|
|
||||||
|
### Principles
|
||||||
|
|
||||||
|
1. **Never commit credentials to Git** - Use `.env` files (already in `.gitignore`)
|
||||||
|
2. **Use environment variables** - All scripts read from `DATABASE_URL` or `PGPASSWORD`
|
||||||
|
3. **Safe fallback values** - Default values use `CHANGE_ME` placeholder (will fail fast)
|
||||||
|
4. **Fail fast** - Scripts exit with clear error if credentials missing
|
||||||
|
5. **Separate dev/prod** - Different credentials for each environment
|
||||||
|
|
||||||
|
### Credential Storage Locations
|
||||||
|
|
||||||
|
| Environment | Location | User | Access |
|
||||||
|
|-------------|----------|------|--------|
|
||||||
|
| **Development** | `.env` in project root | Developer | Local only |
|
||||||
|
| **Production** | `/var/www/nordabiznes/.env` | www-data | Server only |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables Reference
|
||||||
|
|
||||||
|
### Required Variables
|
||||||
|
|
||||||
|
| Variable | Purpose | Used By | Example |
|
||||||
|
|----------|---------|---------|---------|
|
||||||
|
| `DATABASE_URL` | PostgreSQL connection string | Python scripts | `postgresql://user:pass@host:port/db` |
|
||||||
|
| `PGPASSWORD` | PostgreSQL password | Shell scripts (psql, pg_dump) | `your_secure_password` |
|
||||||
|
| `SECRET_KEY` | Flask session encryption | Flask app | Random string (64+ chars) |
|
||||||
|
| `GOOGLE_GEMINI_API_KEY` | Gemini AI chat | AI features | `AIzaSy...` |
|
||||||
|
| `GOOGLE_PAGESPEED_API_KEY` | SEO audits | Admin panel | `AIzaSy...` |
|
||||||
|
| `GOOGLE_PLACES_API_KEY` | Google Business Profile | GBP audits | `AIzaSy...` |
|
||||||
|
| `BRAVE_SEARCH_API_KEY` | News monitoring | News search | `BSA...` |
|
||||||
|
|
||||||
|
### Optional Variables
|
||||||
|
|
||||||
|
| Variable | Purpose | Default | Example |
|
||||||
|
|----------|---------|---------|---------|
|
||||||
|
| `FLASK_ENV` | Flask environment mode | `production` | `development` |
|
||||||
|
| `PORT` | Flask server port | `5000` | `5001` |
|
||||||
|
| `HOST` | Flask server host | `0.0.0.0` | `127.0.0.1` |
|
||||||
|
| `MAIL_SERVER` | Email SMTP server | None | `smtp.gmail.com` |
|
||||||
|
| `MAIL_USERNAME` | Email account | None | `noreply@example.com` |
|
||||||
|
| `MAIL_PASSWORD` | Email password/app password | None | `your_app_password` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development Environment Setup
|
||||||
|
|
||||||
|
### Step 1: Create `.env` File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In project root directory
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Configure Database Credentials
|
||||||
|
|
||||||
|
Edit `.env` and set your local database credentials:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development PostgreSQL (Docker)
|
||||||
|
DATABASE_URL=postgresql://nordabiz_user:nordabiz_password@localhost:5433/nordabiz
|
||||||
|
|
||||||
|
# Flask Configuration
|
||||||
|
SECRET_KEY=your-randomly-generated-secret-key-change-this
|
||||||
|
FLASK_ENV=development
|
||||||
|
PORT=5000
|
||||||
|
|
||||||
|
# API Keys (get from Google Cloud Console)
|
||||||
|
GOOGLE_GEMINI_API_KEY=your_gemini_key_here
|
||||||
|
GOOGLE_PAGESPEED_API_KEY=your_pagespeed_key_here
|
||||||
|
GOOGLE_PLACES_API_KEY=your_places_key_here
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Start Local Database
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start PostgreSQL in Docker
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# Verify database is running
|
||||||
|
docker ps | grep postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Verify Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test Python scripts can read DATABASE_URL
|
||||||
|
python3 -c "import os; print('DATABASE_URL:', os.getenv('DATABASE_URL', 'NOT SET'))"
|
||||||
|
|
||||||
|
# Expected output:
|
||||||
|
# DATABASE_URL: postgresql://nordabiz_user:nordabiz_password@localhost:5433/nordabiz
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Run Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Activate virtual environment
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# Run Flask application
|
||||||
|
python3 app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Production Environment Setup
|
||||||
|
|
||||||
|
### Step 1: SSH to Production Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh maciejpi@10.22.68.249
|
||||||
|
```
|
||||||
|
|
||||||
|
**IMPORTANT:** Always SSH as `maciejpi`, NEVER as root!
|
||||||
|
|
||||||
|
### Step 2: Configure Production `.env`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to application directory
|
||||||
|
cd /var/www/nordabiznes
|
||||||
|
|
||||||
|
# Edit .env file (use sudo if needed)
|
||||||
|
sudo -u www-data nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Set Production Credentials
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Production PostgreSQL (same server)
|
||||||
|
DATABASE_URL=postgresql://nordabiz_app:YOUR_PRODUCTION_PASSWORD@127.0.0.1:5432/nordabiz
|
||||||
|
|
||||||
|
# Flask Configuration
|
||||||
|
SECRET_KEY=your-production-secret-key-64-random-characters-minimum
|
||||||
|
FLASK_ENV=production
|
||||||
|
PORT=5000
|
||||||
|
HOST=0.0.0.0
|
||||||
|
|
||||||
|
# API Keys (production keys from Google Cloud)
|
||||||
|
GOOGLE_GEMINI_API_KEY=your_production_gemini_key
|
||||||
|
GOOGLE_PAGESPEED_API_KEY=your_production_pagespeed_key
|
||||||
|
GOOGLE_PLACES_API_KEY=your_production_places_key
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Set File Permissions
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ensure .env is readable only by www-data
|
||||||
|
sudo chown www-data:www-data /var/www/nordabiznes/.env
|
||||||
|
sudo chmod 600 /var/www/nordabiznes/.env
|
||||||
|
|
||||||
|
# Verify permissions
|
||||||
|
ls -la /var/www/nordabiznes/.env
|
||||||
|
# Expected: -rw------- 1 www-data www-data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Restart Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl restart nordabiznes
|
||||||
|
sudo systemctl status nordabiznes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Shell Script Configuration
|
||||||
|
|
||||||
|
### Problem: Shell Scripts Cannot Read `.env` Files
|
||||||
|
|
||||||
|
Shell scripts (like `view_maturity_results.sh`) **cannot automatically read** `.env` files. You must set `PGPASSWORD` manually in your shell session.
|
||||||
|
|
||||||
|
### Solution 1: Export in Shell Session (Temporary)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set PGPASSWORD for current shell session
|
||||||
|
export PGPASSWORD='your_database_password'
|
||||||
|
|
||||||
|
# Run script
|
||||||
|
./view_maturity_results.sh
|
||||||
|
|
||||||
|
# Unset after use (optional, for security)
|
||||||
|
unset PGPASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
### Solution 2: Inline Environment Variable (One-time)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set PGPASSWORD only for this command
|
||||||
|
PGPASSWORD='your_database_password' ./view_maturity_results.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Solution 3: Use `.pgpass` File (Recommended for Production)
|
||||||
|
|
||||||
|
The `.pgpass` file allows PostgreSQL tools to authenticate without environment variables.
|
||||||
|
|
||||||
|
**Step 1: Create `.pgpass` file**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create file in home directory
|
||||||
|
nano ~/.pgpass
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Add credentials (one line per database)**
|
||||||
|
|
||||||
|
```
|
||||||
|
# Format: hostname:port:database:username:password
|
||||||
|
10.22.68.249:5432:nordabiz:nordabiz_app:your_production_password
|
||||||
|
localhost:5433:nordabiz:nordabiz_user:nordabiz_password
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Set correct permissions (REQUIRED)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod 600 ~/.pgpass
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
ls -la ~/.pgpass
|
||||||
|
# Expected: -rw------- 1 your_user your_group
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4: Run script (no PGPASSWORD needed)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./view_maturity_results.sh
|
||||||
|
# PostgreSQL will automatically read credentials from .pgpass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Script Validation
|
||||||
|
|
||||||
|
All shell scripts now validate that `PGPASSWORD` is set before execution:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Scripts check for PGPASSWORD at start
|
||||||
|
if [ -z "$PGPASSWORD" ]; then
|
||||||
|
echo "ERROR: PGPASSWORD environment variable is not set"
|
||||||
|
echo "Usage: PGPASSWORD='your_password' $0"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**If you see this error**, set PGPASSWORD using one of the methods above.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
### 1. Never Hardcode Credentials
|
||||||
|
|
||||||
|
**❌ WRONG - Hardcoded password in Python:**
|
||||||
|
|
||||||
|
```python
|
||||||
|
# NEVER DO THIS
|
||||||
|
DATABASE_URL = 'postgresql://user:MyPassword123@localhost/db'
|
||||||
|
```
|
||||||
|
|
||||||
|
**✅ CORRECT - Environment variable with safe fallback:**
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Always use environment variables
|
||||||
|
DATABASE_URL = os.getenv('DATABASE_URL', 'postgresql://user:CHANGE_ME@localhost/db')
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Never Hardcode Credentials in Shell Scripts
|
||||||
|
|
||||||
|
**❌ WRONG - Hardcoded PGPASSWORD:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# NEVER DO THIS
|
||||||
|
PGPASSWORD='MyPassword123' psql -h localhost -U myuser -d mydb
|
||||||
|
```
|
||||||
|
|
||||||
|
**✅ CORRECT - Use environment variable:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Validate variable is set
|
||||||
|
if [ -z "$PGPASSWORD" ]; then
|
||||||
|
echo "ERROR: PGPASSWORD not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use variable
|
||||||
|
psql -h localhost -U myuser -d mydb
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Keep `.env` Out of Version Control
|
||||||
|
|
||||||
|
The `.env` file is already in `.gitignore`. **NEVER remove it from `.gitignore`.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verify .env is ignored
|
||||||
|
git status | grep .env
|
||||||
|
# Should show nothing (file is ignored)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Use `.env.example` as Template
|
||||||
|
|
||||||
|
The `.env.example` file is committed to Git and serves as a template. It contains:
|
||||||
|
|
||||||
|
- ✅ Variable names and structure
|
||||||
|
- ✅ Comments explaining each variable
|
||||||
|
- ✅ Example/placeholder values (not real credentials)
|
||||||
|
- ❌ NO real passwords or API keys
|
||||||
|
|
||||||
|
### 5. Rotate Credentials if Compromised
|
||||||
|
|
||||||
|
If credentials are accidentally committed to Git:
|
||||||
|
|
||||||
|
1. **Immediately change the password/API key** in database/service
|
||||||
|
2. Update `.env` files in all environments
|
||||||
|
3. Restart applications
|
||||||
|
4. Consider the old credential compromised (attackers may have Git history)
|
||||||
|
|
||||||
|
**Git history cleanup (advanced, use with caution):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Option 1: BFG Repo-Cleaner (recommended)
|
||||||
|
# https://rtyley.github.io/bfg-repo-cleaner/
|
||||||
|
|
||||||
|
# Option 2: git filter-branch (complex)
|
||||||
|
# Not recommended unless you know what you're doing
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Use Strong Credentials
|
||||||
|
|
||||||
|
- **Database passwords:** Minimum 16 characters, mix of letters/numbers/symbols
|
||||||
|
- **Flask SECRET_KEY:** Minimum 64 random characters
|
||||||
|
- **API Keys:** Use keys from official provider (Google Cloud Console)
|
||||||
|
|
||||||
|
**Generate random SECRET_KEY:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -c "import secrets; print(secrets.token_hex(32))"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Principle of Least Privilege
|
||||||
|
|
||||||
|
- **Development:** Use separate database user with limited permissions
|
||||||
|
- **Production:** Use `nordabiz_app` user (not postgres superuser)
|
||||||
|
- **API Keys:** Enable only required APIs in Google Cloud Console
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification and Testing
|
||||||
|
|
||||||
|
### Pre-Deployment Checklist
|
||||||
|
|
||||||
|
Before deploying any code, run these verification commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Check for hardcoded passwords in Python files
|
||||||
|
grep -r "NordaBiz2025Secure" --include="*.py" .
|
||||||
|
# Expected: No results (or only in docs/)
|
||||||
|
|
||||||
|
# 2. Check for hardcoded PGPASSWORD in shell scripts
|
||||||
|
grep -r "PGPASSWORD=" --include="*.sh" .
|
||||||
|
# Expected: No results (or only validation checks)
|
||||||
|
|
||||||
|
# 3. Check for hardcoded DATABASE_URL with passwords
|
||||||
|
grep -r "postgresql://.*:.*@" --include="*.py" . | grep -v "CHANGE_ME" | grep -v ".example"
|
||||||
|
# Expected: No results (or only safe placeholders)
|
||||||
|
|
||||||
|
# 4. Verify .env is in .gitignore
|
||||||
|
git check-ignore .env
|
||||||
|
# Expected: .env (file is ignored)
|
||||||
|
|
||||||
|
# 5. Check what would be committed
|
||||||
|
git status
|
||||||
|
# Expected: .env should NOT appear in list
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Environment Variable Loading
|
||||||
|
|
||||||
|
**Test Python scripts:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Unset DATABASE_URL to test fallback
|
||||||
|
unset DATABASE_URL
|
||||||
|
python3 -c "from database import get_database_url; print(get_database_url())"
|
||||||
|
# Expected: postgresql://user:CHANGE_ME@127.0.0.1:5432/nordabiz (safe fallback)
|
||||||
|
|
||||||
|
# Set DATABASE_URL to test loading
|
||||||
|
export DATABASE_URL='postgresql://test:test@localhost:5432/testdb'
|
||||||
|
python3 -c "from database import get_database_url; print(get_database_url())"
|
||||||
|
# Expected: postgresql://test:test@localhost:5432/testdb (from environment)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test shell scripts:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Unset PGPASSWORD to test validation
|
||||||
|
unset PGPASSWORD
|
||||||
|
./view_maturity_results.sh
|
||||||
|
# Expected: ERROR message about PGPASSWORD not set
|
||||||
|
|
||||||
|
# Set PGPASSWORD to test execution
|
||||||
|
export PGPASSWORD='test_password'
|
||||||
|
./view_maturity_results.sh
|
||||||
|
# Expected: Script runs (may fail if credentials wrong, but validation passed)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Continuous Monitoring
|
||||||
|
|
||||||
|
Add these checks to your deployment pipeline:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In CI/CD or pre-commit hook
|
||||||
|
if grep -r "NordaBiz2025Secure" --include="*.py" --include="*.sh" .; then
|
||||||
|
echo "ERROR: Found hardcoded credentials in code"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Issue: "PGPASSWORD not set" error in shell script
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
ERROR: PGPASSWORD environment variable is not set
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
# Set PGPASSWORD before running script
|
||||||
|
export PGPASSWORD='your_database_password'
|
||||||
|
./your_script.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: "Password authentication failed" in Python script
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL: password authentication failed
|
||||||
|
```
|
||||||
|
|
||||||
|
**Diagnosis:**
|
||||||
|
```bash
|
||||||
|
# Check if DATABASE_URL is set
|
||||||
|
echo $DATABASE_URL
|
||||||
|
|
||||||
|
# Check if DATABASE_URL in .env is correct
|
||||||
|
cat .env | grep DATABASE_URL
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Verify password is correct in `.env`
|
||||||
|
2. Ensure `.env` file exists and is readable
|
||||||
|
3. Check database user exists: `psql -U postgres -c "\du"`
|
||||||
|
|
||||||
|
### Issue: Script uses 'CHANGE_ME' placeholder password
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
sqlalchemy.exc.OperationalError: FATAL: password authentication failed for user "nordabiz_app"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause:** DATABASE_URL environment variable is not set, script is using safe fallback.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
# Check if .env file exists
|
||||||
|
ls -la .env
|
||||||
|
|
||||||
|
# Check if DATABASE_URL is in .env
|
||||||
|
grep DATABASE_URL .env
|
||||||
|
|
||||||
|
# Ensure you're loading .env (Flask should do this automatically)
|
||||||
|
# For standalone scripts, may need to load manually:
|
||||||
|
python3 -c "from dotenv import load_dotenv; load_dotenv(); import os; print(os.getenv('DATABASE_URL'))"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: ".env file not found" on production
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
Application can't find credentials, using fallback values.
|
||||||
|
|
||||||
|
**Diagnosis:**
|
||||||
|
```bash
|
||||||
|
# Check if .env exists in application directory
|
||||||
|
ls -la /var/www/nordabiznes/.env
|
||||||
|
|
||||||
|
# Check file ownership and permissions
|
||||||
|
ls -la /var/www/nordabiznes/.env
|
||||||
|
# Expected: -rw------- 1 www-data www-data
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
# Create .env from template
|
||||||
|
cd /var/www/nordabiznes
|
||||||
|
sudo -u www-data cp .env.example .env
|
||||||
|
sudo -u www-data nano .env # Edit with production credentials
|
||||||
|
|
||||||
|
# Set correct permissions
|
||||||
|
sudo chown www-data:www-data .env
|
||||||
|
sudo chmod 600 .env
|
||||||
|
|
||||||
|
# Restart application
|
||||||
|
sudo systemctl restart nordabiznes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Incident Response
|
||||||
|
|
||||||
|
### If Credentials Are Committed to Git
|
||||||
|
|
||||||
|
**CRITICAL: Follow these steps immediately**
|
||||||
|
|
||||||
|
1. **Change the compromised credential**
|
||||||
|
```bash
|
||||||
|
# For database password
|
||||||
|
psql -U postgres -d nordabiz -c "ALTER USER nordabiz_app WITH PASSWORD 'new_secure_password';"
|
||||||
|
|
||||||
|
# For API keys
|
||||||
|
# Disable old key in Google Cloud Console and create new one
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Update `.env` files in all environments**
|
||||||
|
```bash
|
||||||
|
# Development
|
||||||
|
nano .env # Update DATABASE_URL with new password
|
||||||
|
|
||||||
|
# Production
|
||||||
|
ssh maciejpi@10.22.68.249
|
||||||
|
cd /var/www/nordabiznes
|
||||||
|
sudo -u www-data nano .env # Update DATABASE_URL with new password
|
||||||
|
sudo systemctl restart nordabiznes
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Remove credential from Git history (optional, advanced)**
|
||||||
|
```bash
|
||||||
|
# WARNING: This rewrites Git history and requires force push
|
||||||
|
# Coordinate with team before doing this
|
||||||
|
|
||||||
|
# Using BFG Repo-Cleaner (recommended)
|
||||||
|
java -jar bfg.jar --replace-text passwords.txt nordabiz.git
|
||||||
|
git reflog expire --expire=now --all
|
||||||
|
git gc --prune=now --aggressive
|
||||||
|
git push --force
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Document the incident**
|
||||||
|
- Create incident report in `docs/INCIDENT_REPORT_YYYYMMDD.md`
|
||||||
|
- Document what was exposed, when, and remediation steps
|
||||||
|
- Review with team to prevent future incidents
|
||||||
|
|
||||||
|
5. **Review access logs**
|
||||||
|
```bash
|
||||||
|
# Check PostgreSQL logs for unauthorized access
|
||||||
|
sudo tail -100 /var/log/postgresql/postgresql-14-main.log
|
||||||
|
|
||||||
|
# Check Flask application logs
|
||||||
|
sudo journalctl -u nordabiznes -n 100
|
||||||
|
```
|
||||||
|
|
||||||
|
### Emergency Contacts
|
||||||
|
|
||||||
|
| Role | Contact | Responsibility |
|
||||||
|
|------|---------|----------------|
|
||||||
|
| System Administrator | maciejpi@inpi.local | Infrastructure, database |
|
||||||
|
| Lead Developer | [Your contact] | Application code |
|
||||||
|
| Security Officer | [Contact if applicable] | Security incidents |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
### Official Documentation
|
||||||
|
|
||||||
|
- PostgreSQL Authentication: https://www.postgresql.org/docs/current/auth-methods.html
|
||||||
|
- PostgreSQL .pgpass file: https://www.postgresql.org/docs/current/libpq-pgpass.html
|
||||||
|
- Flask Configuration: https://flask.palletsprojects.com/en/2.3.x/config/
|
||||||
|
- python-dotenv: https://github.com/theskumar/python-dotenv
|
||||||
|
|
||||||
|
### Security Standards
|
||||||
|
|
||||||
|
- CWE-798: Use of Hard-coded Credentials: https://cwe.mitre.org/data/definitions/798.html
|
||||||
|
- OWASP Top 10: https://owasp.org/www-project-top-ten/
|
||||||
|
- OWASP Secrets Management Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
|
||||||
|
|
||||||
|
### Internal Documentation
|
||||||
|
|
||||||
|
- Project README: `README.md`
|
||||||
|
- Developer Guide: `CLAUDE.md`
|
||||||
|
- Environment Configuration: `.env.example`
|
||||||
|
- Architecture Documentation: `docs/architecture/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document Version:** 1.0
|
||||||
|
**Last Reviewed:** 2026-01-10
|
||||||
|
**Next Review:** 2026-04-10 (quarterly)
|
||||||
Loading…
Reference in New Issue
Block a user