# Security & Best Practices ## Credential Management ### ⚠️ Critical Security Rules 1. **Never commit `.env.local`** to Git - It contains passwords and API keys - Use `.env.example` for template only - Add to `.gitignore` (already configured) 2. **Rotate credentials regularly** - Change Synology password every 90 days - Rotate UniFi credentials quarterly - Update Grafana API keys if compromised 3. **Use strong passwords** - Minimum 16 characters - Mix of uppercase, lowercase, numbers, special characters - Unique per service ### Credential Storage **Best Practice:** Use a secrets manager #### Option 1: HashiCorp Vault ```bash # Store credentials in Vault vault kv put secret/dashboard/atlas \ unifi_password="..." \ synology_password="..." # Load in container startup script export UNIFI_PASSWORD=$(vault kv get -field=unifi_password secret/dashboard/atlas) ``` #### Option 2: AWS Secrets Manager ```bash # Store and retrieve aws secretsmanager get-secret-value --secret-id dashboard/credentials ``` #### Option 3: GitHub Actions Secrets (for automation) ```yaml env: UNIFI_PASSWORD: ${{ secrets.UNIFI_PASSWORD }} ``` ## Network Security ### Docker API Security ⚠️ **Current Setup**: Docker API exposed to internal network only ```bash # Verify Docker API is not publicly exposed curl http://100.104.196.38:2375/containers/json # Should NOT be accessible from external networks # If it is, restrict with firewall: sudo ufw allow from 100.104.196.0/24 to any port 2375 sudo ufw deny from any to any port 2375 ``` ### HTTPS/SSL Configuration **Recommended:** Use reverse proxy with SSL ```nginx # Nginx example server { listen 443 ssl http2; server_name dashboard.yourdomain.com; ssl_certificate /etc/ssl/certs/your_cert.crt; ssl_certificate_key /etc/ssl/private/your_key.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://localhost:3001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` ### VPN/Network Access **Recommended Setup:** 1. Dashboard accessible only via VPN 2. Or restrict to specific IP ranges: ```bash # UFW firewall rules sudo ufw allow from 100.104.196.0/24 to any port 3001 sudo ufw deny from any to any port 3001 ``` ## Authentication & Authorization ### Basic Auth (Simple) Add basic authentication with Nginx/Traefik: ```yaml # Traefik example labels: - "traefik.http.middlewares.auth.basicauth.users=admin:your_hashed_password" - "traefik.http.routers.dashboard.middlewares=auth" ``` Generate hashed password: ```bash echo $(htpasswd -nB admin) | sed -r 's/:.*//' # Use output in Traefik config ``` ### OAuth2 (Advanced) Using Oauth2-proxy: ```docker # docker-compose.yml addition oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:v7.4.0 environment: OAUTH2_PROXY_PROVIDER: github OAUTH2_PROXY_CLIENT_ID: your_client_id OAUTH2_PROXY_CLIENT_SECRET: your_client_secret OAUTH2_PROXY_COOKIE_SECRET: your_secret ports: - "4180:4180" ``` ## API Security ### Rate Limiting Add rate limiting to API endpoints: ```typescript // src/app/api/containers/route.ts import rateLimit from 'express-rate-limit'; const limiter = rateLimit({ windowMs: 1 * 60 * 1000, // 1 minute max: 100, // 100 requests per minute }); export const GET = limiter(async (req) => { // ... existing code }); ``` ### Input Validation Always validate external inputs: ```typescript // Validate environment variables function validateEnv() { const required = ['DOCKER_HOST', 'UNIFI_HOST', 'SYNOLOGY_HOST']; const missing = required.filter(key => !process.env[key]); if (missing.length > 0) { throw new Error(`Missing env vars: ${missing.join(', ')}`); } } ``` ### API Key Rotation For Grafana API key: ```bash # Generate new key in Grafana UI # Update in .env.local # Revoke old key in Grafana # Script to automate #!/bin/bash NEW_KEY=$(curl -X POST https://grafana/api/auth/keys \ -H "Authorization: Bearer $OLD_KEY" \ -d '{"name": "dashboard", "role": "Viewer"}') # Update .env.local sed -i "s/GRAFANA_API_KEY=.*/GRAFANA_API_KEY=$NEW_KEY/" /opt/dashboard/.env.local ``` ## Logging & Monitoring ### Enable Audit Logging ```bash # Docker daemon audit log echo '{"log-driver": "json-file"}' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker ``` ### Monitor Access Logs ```bash # View nginx/reverse proxy logs tail -f /var/log/nginx/access.log | grep dashboard # Monitor failed authentication attempts grep "401\|403" /var/log/nginx/access.log ``` ### Alert on Anomalies ```bash # Example: Alert on excessive API errors docker logs atlas-dashboard | grep -c "error" | awk '{if ($1 > 10) print "ALERT: High error rate"}' ``` ## Vulnerability Management ### Scan for CVEs ```bash # Scan Docker image trivy image atlas-dashboard:latest # Scan dependencies npm audit # Fix vulnerabilities npm audit fix ``` ### Keep Images Updated ```bash # Update base image docker-compose build --pull # Update Node.js version regularly # Edit Dockerfile to latest LTS version ``` ### Monitor for Vulnerabilities ```bash # GitHub Dependabot - enabled by default # Review and merge dependabot PRs regularly # Manual check npm outdated ``` ## Data Privacy ### GDPR/Data Protection The dashboard: - ✅ Does NOT store personal data - ✅ Does NOT use cookies or tracking - ✅ Does NOT collect user information - ⚠️ Logs contain IP addresses To anonymize logs: ```bash # Redact IPs from logs docker logs atlas-dashboard | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/[REDACTED]/g' ``` ## Compliance Checklist - [ ] All credentials use strong passwords - [ ] .env.local is NOT committed to Git - [ ] Docker API is not publicly exposed - [ ] HTTPS/SSL configured for production - [ ] Authentication layer in place - [ ] Audit logs are enabled - [ ] Dependencies are up-to-date - [ ] Security scanning (trivy) runs regularly - [ ] Access is restricted by firewall/VPN - [ ] Backup strategy is documented - [ ] Incident response plan is prepared - [ ] Regular security reviews scheduled ## Incident Response ### If Credentials Are Compromised 1. **Immediately change passwords:** ```bash # Synology # UniFi # Any API keys ``` 2. **Update in .env.local:** ```bash ssh soadmin@100.104.196.38 nano /opt/dashboard/.env.local ``` 3. **Restart container:** ```bash docker-compose restart dashboard ``` 4. **Check logs for unauthorized access:** ```bash docker logs atlas-dashboard | grep error ``` 5. **Review API call history** in Synology/UniFi ### If Container Is Compromised 1. **Isolate the container:** ```bash docker-compose down ``` 2. **Rebuild from source:** ```bash cd /opt/dashboard git fetch origin git reset --hard origin/main docker-compose build --no-cache ``` 3. **Verify integrity:** ```bash git log -1 docker images atlas-dashboard ``` 4. **Redeploy:** ```bash docker-compose up -d ``` ### If Server Is Compromised 1. **Migrate to new server** (see MONITORING.md - Disaster Recovery) 2. **Rotate ALL credentials** 3. **Conduct security audit** of infrastructure 4. **Review access logs** from before incident ## Additional Resources - [OWASP Top 10](https://owasp.org/www-project-top-ten/) - [Docker Security Best Practices](https://docs.docker.com/engine/security/) - [Next.js Security](https://nextjs.org/docs/advanced-features/security-headers) - [Node.js Security Checklist](https://nodejs.org/en/docs/guides/security/)