# 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)
