Add comprehensive secrets management guide

Covers 6 options for storing passwords securely:
1. .env file (current, good for personal use)
2. Environment variables (better for production)
3. Separate secrets file
4. Docker secrets
5. HashiCorp Vault (enterprise)
6. Git secrets (CI/CD only)

Recommendation: Current .env setup is fine for personal/research use
Improvement: chmod 600 .env (done)

Includes security checklist, rotation procedures, and testing
This commit is contained in:
ilia 2025-12-15 15:47:12 -05:00
parent 5613d7f894
commit 0c183fb28c

View File

@ -0,0 +1,414 @@
# Secrets Management Guide
## Overview
POTE needs sensitive information like database passwords and SMTP credentials. This guide covers secure storage options.
---
## Option 1: `.env` File (Current Default)
**Good for:** Personal use, single server, local development
### Setup
```bash
# Create .env file
cp .env.example .env
nano .env # Add secrets
# Secure permissions
chmod 600 .env
chown poteapp:poteapp .env
```
### ✅ Pros
- Simple, works immediately
- No additional setup
- Standard practice for Python projects
### ⚠️ Cons
- Secrets stored in plain text on disk
- Risk if server is compromised
- No audit trail
### 🔒 Security Checklist
- [ ] `.env` in `.gitignore` (already done ✅)
- [ ] File permissions: `chmod 600 .env`
- [ ] Never commit to git
- [ ] Backup securely (encrypted)
- [ ] Rotate passwords regularly
---
## Option 2: Environment Variables (Better)
**Good for:** Systemd services, Docker, production
### Setup for Systemd Service
Create `/etc/systemd/system/pote.service`:
```ini
[Unit]
Description=POTE Daily Update
After=network.target postgresql.service
[Service]
Type=oneshot
User=poteapp
WorkingDirectory=/home/poteapp/pote
Environment="DATABASE_URL=postgresql://poteuser:PASSWORD@localhost:5432/potedb"
Environment="SMTP_HOST=mail.levkin.ca"
Environment="SMTP_PORT=587"
Environment="SMTP_USER=test@levkin.ca"
Environment="SMTP_PASSWORD=YOUR_PASSWORD"
Environment="FROM_EMAIL=test@levkin.ca"
ExecStart=/home/poteapp/pote/venv/bin/python scripts/automated_daily_run.sh
[Install]
WantedBy=multi-user.target
```
**Secure the service file:**
```bash
sudo chmod 600 /etc/systemd/system/pote.service
sudo systemctl daemon-reload
```
### ✅ Pros
- Secrets not in git or project directory
- Standard Linux practice
- Works with systemd timers
### ⚠️ Cons
- Still visible in `systemctl show`
- Requires root to edit
---
## Option 3: Separate Secrets File (Compromise)
**Good for:** Multiple environments, easier rotation
### Setup
Create `/etc/pote/secrets` (outside project):
```bash
sudo mkdir -p /etc/pote
sudo nano /etc/pote/secrets
```
Content:
```bash
export SMTP_PASSWORD="your_password_here"
export DATABASE_PASSWORD="your_db_password_here"
```
Secure it:
```bash
sudo chmod 600 /etc/pote/secrets
sudo chown poteapp:poteapp /etc/pote/secrets
```
Update scripts to source it:
```bash
#!/bin/bash
# Load secrets
if [ -f /etc/pote/secrets ]; then
source /etc/pote/secrets
fi
# Load .env (without passwords)
source .env
# Run POTE
python scripts/send_daily_report.py
```
### ✅ Pros
- Secrets separate from code
- Easy to rotate
- Can be backed up separately
### ⚠️ Cons
- Extra file to manage
- Still plain text
---
## Option 4: Docker Secrets (For Docker Deployments)
**Good for:** Docker Compose, Docker Swarm
### Setup
Create secret files:
```bash
echo "your_smtp_password" | docker secret create smtp_password -
echo "your_db_password" | docker secret create db_password -
```
Update `docker-compose.yml`:
```yaml
version: '3.8'
services:
pote:
image: pote:latest
secrets:
- smtp_password
- db_password
environment:
SMTP_HOST: mail.levkin.ca
SMTP_USER: test@levkin.ca
SMTP_PASSWORD_FILE: /run/secrets/smtp_password
DATABASE_PASSWORD_FILE: /run/secrets/db_password
secrets:
smtp_password:
external: true
db_password:
external: true
```
Update code to read from files:
```python
# In src/pote/config.py
def get_secret(key: str, default: str = "") -> str:
"""Read secret from file or environment."""
file_path = os.getenv(f"{key}_FILE")
if file_path and Path(file_path).exists():
return Path(file_path).read_text().strip()
return os.getenv(key, default)
class Settings(BaseSettings):
smtp_password: str = Field(default_factory=lambda: get_secret("SMTP_PASSWORD"))
```
### ✅ Pros
- Docker-native solution
- Encrypted in Swarm mode
- Never in logs
### ⚠️ Cons
- Requires Docker
- More complex setup
---
## Option 5: HashiCorp Vault (Enterprise)
**Good for:** Teams, multiple projects, compliance
### Setup
1. Install Vault server
2. Store secrets:
```bash
vault kv put secret/pote \
smtp_password="your_password" \
db_password="your_db_password"
```
3. Update POTE to fetch from Vault:
```python
import hvac
client = hvac.Client(url='http://vault:8200', token=os.getenv('VAULT_TOKEN'))
secrets = client.secrets.kv.v2.read_secret_version(path='pote')
smtp_password = secrets['data']['data']['smtp_password']
```
### ✅ Pros
- Centralized secrets management
- Audit logs
- Dynamic secrets
- Access control
### ⚠️ Cons
- Complex setup
- Requires Vault infrastructure
- Overkill for single user
---
## Option 6: Git Secrets (For CI/CD ONLY)
**Good for:** GitHub Actions, Gitea Actions
### Setup in Gitea/GitHub
1. Go to Repository Settings → Secrets
2. Add secrets:
- `SMTP_PASSWORD`
- `DB_PASSWORD`
3. Reference in `.github/workflows/ci.yml`:
```yaml
env:
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
DATABASE_URL: postgresql://user:${{ secrets.DB_PASSWORD }}@postgres/db
```
### ⚠️ Important
- **Only for CI/CD pipelines**
- **NOT for deployed servers**
- Secrets are injected during workflow runs
---
## 🎯 Recommendation for Your Setup
### Personal/Research Use (Current)
**Keep `.env` file with better security:**
```bash
# On Proxmox
ssh poteapp@your-proxmox-ip
cd ~/pote
# Secure .env
chmod 600 .env
chown poteapp:poteapp .env
# Verify
ls -la .env
# Should show: -rw------- 1 poteapp poteapp
```
**Backup strategy:**
```bash
# Encrypted backup of .env
gpg -c .env # Creates .env.gpg
# Store .env.gpg somewhere safe (encrypted USB, password manager)
```
### Production/Team Use
**Use environment variables + systemd:**
1. Remove passwords from `.env`
2. Create systemd service with `Environment=` directives
3. Secure service file: `chmod 600 /etc/systemd/system/pote.service`
---
## 🔒 General Security Best Practices
### ✅ DO
- Use strong, unique passwords
- Restrict file permissions (`chmod 600`)
- Keep `.env` in `.gitignore`
- Rotate passwords regularly (every 90 days)
- Use encrypted backups
- Audit who has server access
### ❌ DON'T
- Commit secrets to git (even private repos)
- Store passwords in code
- Share `.env` files via email/Slack
- Use the same password everywhere
- Leave default passwords
- Store secrets in public cloud storage
---
## 🧪 Test Your Security
### Check if `.env` is protected
```bash
# Should be in .gitignore
git check-ignore .env # Should output: .env
# Should have restricted permissions
ls -la .env # Should show: -rw------- (600)
# Should not be committed
git log --all --full-history --oneline -- .env # Should be empty
```
### Verify secrets aren't in git history
```bash
# Search for passwords in git history
git log --all --full-history --source --pickaxe-all -S 'smtp_password'
# Should find nothing
```
---
## 🔄 Password Rotation Procedure
### Every 90 days (or if compromised):
1. Generate new password in mailcow
2. Update `.env`:
```bash
nano .env # Change SMTP_PASSWORD
```
3. Test:
```bash
python scripts/send_daily_report.py --test-smtp
```
4. No restart needed (scripts read `.env` on each run)
---
## 📊 Security Level Comparison
| Level | Method | Effort | Protection |
|-------|--------|--------|------------|
| 🔓 Basic | `.env` (default perms) | None | Low |
| 🔒 Good | `.env` (chmod 600) | 1 min | Medium |
| 🔒 Better | Environment variables | 10 min | Good |
| 🔒 Better | Separate secrets file | 10 min | Good |
| 🔐 Best | Docker Secrets | 30 min | Very Good |
| 🔐 Best | Vault | 2+ hours | Excellent |
---
## 🎯 Your Current Status
✅ **Already secure enough for personal use:**
- `.env` in `.gitignore`
- Not committed to git ✅
- Local server only ✅
⚠️ **Recommended improvement (2 minutes):**
```bash
chmod 600 .env
```
🔐 **Optional (if paranoid):**
- Use separate secrets file in `/etc/pote/`
- Encrypt backups with GPG
- Set up password rotation schedule
---
## Summary
**For your levkin.ca setup:**
1. **Current approach (`.env` file) is fine**
2. **Add `chmod 600 .env`** for better security (2 minutes)
3. **Don't commit `.env` to git** (already protected ✅)
4. **Consider upgrading to environment variables** if you deploy to production
Your current setup is **appropriate for a personal research project**. Don't over-engineer it unless you have specific compliance requirements or a team.