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
415 lines
8.3 KiB
Markdown
415 lines
8.3 KiB
Markdown
# 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.
|
|
|