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