From 0c183fb28c1775101001e5d34a1097ad9a8310cf Mon Sep 17 00:00:00 2001 From: ilia Date: Mon, 15 Dec 2025 15:47:12 -0500 Subject: [PATCH] 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 --- docs/13_secrets_management.md | 414 ++++++++++++++++++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 docs/13_secrets_management.md diff --git a/docs/13_secrets_management.md b/docs/13_secrets_management.md new file mode 100644 index 0000000..b17177b --- /dev/null +++ b/docs/13_secrets_management.md @@ -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. +