infra
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
# Security Checklist for Production Deployment
|
||||
|
||||
This checklist helps ensure your LinkForty deployment on Fly.io follows security best practices.
|
||||
|
||||
## ✅ Pre-Deployment Security Checklist
|
||||
|
||||
### Environment Variables & Secrets
|
||||
|
||||
- [ ] All sensitive values are set using `fly secrets set` (never in `fly.toml`)
|
||||
- [ ] `DATABASE_URL` includes `?sslmode=require` for PostgreSQL
|
||||
- [ ] `REDIS_URL` includes authentication credentials
|
||||
- [ ] `CORS_ORIGIN` is set to your actual frontend domain(s), not `*`
|
||||
- [ ] `NODE_ENV` is set to `"production"`
|
||||
- [ ] No secrets are committed to version control
|
||||
- [ ] `.env` files are in `.gitignore`
|
||||
|
||||
### Database Security
|
||||
|
||||
- [ ] PostgreSQL uses SSL/TLS connections (`sslmode=require`)
|
||||
- [ ] Database password is strong (20+ characters, random)
|
||||
- [ ] Database is not publicly accessible (Fly Postgres is private by default)
|
||||
- [ ] Connection pooling is configured (default: 2-10 connections)
|
||||
- [ ] Database backups are enabled (see [fly.postgres.md](./fly.postgres.md))
|
||||
- [ ] Backup retention policy is configured
|
||||
|
||||
### Redis Security
|
||||
|
||||
- [ ] Redis requires authentication (Upstash Redis includes this by default)
|
||||
- [ ] Redis connection uses TLS (`rediss://` protocol)
|
||||
- [ ] Redis is not publicly accessible
|
||||
- [ ] Connection timeout is configured
|
||||
|
||||
### Application Security
|
||||
|
||||
- [ ] CORS is properly configured (not set to `*` in production)
|
||||
- [ ] Rate limiting is enabled for link creation endpoints
|
||||
- [ ] Input validation is active (Zod schemas)
|
||||
- [ ] SQL injection protection via parameterized queries (pg library handles this)
|
||||
- [ ] Health check endpoint (`/health`) exposes no sensitive data
|
||||
- [ ] Error messages don't leak sensitive information
|
||||
- [ ] Logging doesn't include secrets or PII
|
||||
|
||||
### Network Security
|
||||
|
||||
- [ ] HTTPS is enforced (`force_https = true` in fly.toml)
|
||||
- [ ] HTTP is redirected to HTTPS
|
||||
- [ ] Health checks use HTTPS
|
||||
- [ ] No sensitive services are exposed publicly
|
||||
|
||||
### Access Control
|
||||
|
||||
- [ ] Fly.io account uses strong password + 2FA
|
||||
- [ ] Fly.io organization access is limited to required team members
|
||||
- [ ] Deploy tokens (if used in CI/CD) have minimum required permissions
|
||||
- [ ] Database credentials are rotated regularly (quarterly minimum)
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Configuration Details
|
||||
|
||||
### 1. Database URL Security
|
||||
|
||||
Your `DATABASE_URL` should look like:
|
||||
```
|
||||
postgresql://user:password@host:5432/dbname?sslmode=require
|
||||
```
|
||||
|
||||
Key requirements:
|
||||
- `sslmode=require` - Forces SSL/TLS encryption
|
||||
- Strong password (20+ characters)
|
||||
- Host should be internal Fly network (`.internal` domain) if using Fly Postgres
|
||||
|
||||
Set it securely:
|
||||
```bash
|
||||
fly secrets set DATABASE_URL="postgresql://user:password@host:5432/dbname?sslmode=require"
|
||||
```
|
||||
|
||||
### 2. Redis URL Security
|
||||
|
||||
Your `REDIS_URL` should look like:
|
||||
```
|
||||
rediss://default:password@host:6379
|
||||
```
|
||||
|
||||
Key requirements:
|
||||
- `rediss://` protocol (TLS encrypted)
|
||||
- Authentication password included
|
||||
- Upstash Redis (recommended) includes TLS by default
|
||||
|
||||
Set it securely:
|
||||
```bash
|
||||
fly secrets set REDIS_URL="rediss://default:password@host:6379"
|
||||
```
|
||||
|
||||
### 3. CORS Configuration
|
||||
|
||||
For production, set specific origins:
|
||||
|
||||
```bash
|
||||
# Single origin
|
||||
fly secrets set CORS_ORIGIN="https://yourdomain.com"
|
||||
|
||||
# Multiple origins (comma-separated)
|
||||
fly secrets set CORS_ORIGIN="https://yourdomain.com,https://app.yourdomain.com"
|
||||
```
|
||||
|
||||
Never use `*` in production - this allows any website to make requests to your API.
|
||||
|
||||
### 4. Rate Limiting
|
||||
|
||||
LinkForty includes built-in rate limiting. Verify it's enabled in your deployment:
|
||||
|
||||
- Link creation: Limited by IP address
|
||||
- Analytics queries: Limited by userId
|
||||
- Redirect endpoints: Unlimited (by design for fast redirects)
|
||||
|
||||
Monitor rate limit metrics:
|
||||
```bash
|
||||
fly logs | grep "rate limit"
|
||||
```
|
||||
|
||||
### 5. Input Validation
|
||||
|
||||
LinkForty uses Zod for input validation. Ensure validation errors are logged:
|
||||
|
||||
```bash
|
||||
fly logs | grep "validation"
|
||||
```
|
||||
|
||||
Common validation issues to monitor:
|
||||
- Invalid URLs
|
||||
- Malformed userId
|
||||
- Invalid UTM parameters
|
||||
- Expired links
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Secret Rotation Policy
|
||||
|
||||
Rotate secrets regularly to minimize compromise risk.
|
||||
|
||||
### Quarterly Rotation (Every 3 months)
|
||||
|
||||
1. **Database Password**
|
||||
```bash
|
||||
# On Fly Postgres
|
||||
fly postgres connect -a linkforty-db
|
||||
ALTER USER your_user WITH PASSWORD 'new-strong-password';
|
||||
\q
|
||||
|
||||
# Update secret
|
||||
fly secrets set DATABASE_URL="postgresql://user:new-password@host:5432/dbname?sslmode=require"
|
||||
```
|
||||
|
||||
2. **Redis Password**
|
||||
```bash
|
||||
# Generate new Upstash Redis credentials
|
||||
# In Upstash dashboard: Reset password
|
||||
|
||||
# Update secret
|
||||
fly secrets set REDIS_URL="rediss://default:new-password@host:6379"
|
||||
```
|
||||
|
||||
3. **API Keys** (if you add API authentication)
|
||||
```bash
|
||||
fly secrets set API_KEY="new-random-key"
|
||||
```
|
||||
|
||||
### After Security Incident
|
||||
|
||||
Rotate ALL secrets immediately:
|
||||
- Database credentials
|
||||
- Redis credentials
|
||||
- Any API keys
|
||||
- Fly.io deploy tokens (if compromised)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Security Monitoring
|
||||
|
||||
### Log Monitoring
|
||||
|
||||
Monitor these security-relevant events:
|
||||
|
||||
```bash
|
||||
# Failed database connections
|
||||
fly logs | grep "connection refused"
|
||||
|
||||
# Rate limit hits
|
||||
fly logs | grep "rate limit"
|
||||
|
||||
# Validation errors
|
||||
fly logs | grep "validation error"
|
||||
|
||||
# Suspicious activity patterns
|
||||
fly logs | grep "error"
|
||||
```
|
||||
|
||||
### Metrics to Watch
|
||||
|
||||
- **Unusual traffic spikes** - Potential DDoS or abuse
|
||||
- **High error rates** - Potential attack or misconfiguration
|
||||
- **Database connection errors** - Credential issues or network problems
|
||||
- **Redis connection failures** - Service degradation
|
||||
|
||||
Access metrics:
|
||||
```bash
|
||||
fly dashboard # Web UI with graphs
|
||||
fly status # Current health
|
||||
```
|
||||
|
||||
### Automated Alerts (Recommended)
|
||||
|
||||
Set up alerts for:
|
||||
- High error rates (>5% of requests)
|
||||
- Service downtime
|
||||
- Database connection failures
|
||||
- Unusual traffic patterns
|
||||
|
||||
Fly.io integrates with:
|
||||
- Sentry (error tracking)
|
||||
- Datadog (monitoring)
|
||||
- Prometheus (metrics)
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Incident Response Plan
|
||||
|
||||
### If Secrets Are Compromised
|
||||
|
||||
1. **Immediately rotate all secrets**
|
||||
```bash
|
||||
# See "Secret Rotation Policy" section above
|
||||
```
|
||||
|
||||
2. **Review access logs**
|
||||
```bash
|
||||
fly logs --all
|
||||
```
|
||||
|
||||
3. **Check for unauthorized database changes**
|
||||
```bash
|
||||
fly postgres connect -a linkforty-db
|
||||
SELECT * FROM users ORDER BY created_at DESC LIMIT 100;
|
||||
SELECT * FROM links ORDER BY created_at DESC LIMIT 100;
|
||||
```
|
||||
|
||||
4. **Review Fly.io access logs**
|
||||
- Check Fly.io dashboard for recent deploys
|
||||
- Review team member access
|
||||
- Check for unknown IP addresses
|
||||
|
||||
5. **Deploy with new secrets**
|
||||
```bash
|
||||
fly deploy
|
||||
```
|
||||
|
||||
6. **Document the incident**
|
||||
- What was compromised?
|
||||
- How was it discovered?
|
||||
- What actions were taken?
|
||||
- How to prevent in the future?
|
||||
|
||||
### If Database Is Compromised
|
||||
|
||||
1. **Restore from backup**
|
||||
```bash
|
||||
# See fly.postgres.md for backup/restore instructions
|
||||
```
|
||||
|
||||
2. **Analyze what data was accessed/modified**
|
||||
|
||||
3. **Notify affected users** (if PII was compromised)
|
||||
|
||||
4. **Review and strengthen security measures**
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Data Protection
|
||||
|
||||
### Personal Identifiable Information (PII)
|
||||
|
||||
LinkForty collects:
|
||||
- IP addresses (for geolocation)
|
||||
- User agent strings (for device detection)
|
||||
- Referrer URLs (for analytics)
|
||||
- User IDs (provided by you)
|
||||
|
||||
**Your responsibilities:**
|
||||
- Comply with GDPR, CCPA, or relevant privacy laws
|
||||
- Implement data retention policies
|
||||
- Provide user data deletion endpoints
|
||||
- Maintain privacy policy
|
||||
- Obtain user consent where required
|
||||
|
||||
### Data Retention
|
||||
|
||||
Consider implementing:
|
||||
- Automatic deletion of click events older than X days
|
||||
- User data export functionality
|
||||
- Data anonymization for old analytics
|
||||
|
||||
Example cleanup query:
|
||||
```sql
|
||||
DELETE FROM click_events WHERE created_at < NOW() - INTERVAL '90 days';
|
||||
```
|
||||
|
||||
Schedule via cron or Fly.io scheduled tasks.
|
||||
|
||||
### Encryption
|
||||
|
||||
- **In transit:** HTTPS/TLS for all connections (enforced by Fly.io)
|
||||
- **At rest:** Fly Postgres encrypts data at rest automatically
|
||||
- **Application level:** Consider encrypting sensitive user data in JSONB fields
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Security Vulnerabilities
|
||||
|
||||
### Reporting Security Issues
|
||||
|
||||
**DO NOT** open public GitHub issues for security vulnerabilities.
|
||||
|
||||
Instead:
|
||||
- Email security@yourdomain.com (set up a security contact)
|
||||
- Use GitHub Security Advisories (private disclosure)
|
||||
- Allow 90 days for responsible disclosure
|
||||
|
||||
### Keeping Dependencies Updated
|
||||
|
||||
```bash
|
||||
# Check for vulnerabilities
|
||||
npm audit
|
||||
|
||||
# Fix automatically where possible
|
||||
npm audit fix
|
||||
|
||||
# Review and update dependencies quarterly
|
||||
npm outdated
|
||||
npm update
|
||||
```
|
||||
|
||||
Subscribe to security advisories:
|
||||
- Node.js security releases
|
||||
- Fastify security updates
|
||||
- PostgreSQL security announcements
|
||||
|
||||
---
|
||||
|
||||
## ✅ Security Checklist Summary
|
||||
|
||||
Print and complete this checklist before every production deployment:
|
||||
|
||||
**Pre-Deploy:**
|
||||
- [ ] Secrets set via `fly secrets set` (not in code)
|
||||
- [ ] Database uses SSL (`sslmode=require`)
|
||||
- [ ] CORS configured for specific domains
|
||||
- [ ] HTTPS enforced in `fly.toml`
|
||||
- [ ] No secrets in version control
|
||||
|
||||
**Post-Deploy:**
|
||||
- [ ] Health check passes
|
||||
- [ ] HTTPS redirect works
|
||||
- [ ] CORS allows only intended domains
|
||||
- [ ] Database connection successful
|
||||
- [ ] Redis connection successful
|
||||
- [ ] Rate limiting active
|
||||
- [ ] Error logging working
|
||||
|
||||
**Ongoing:**
|
||||
- [ ] Secrets rotated quarterly
|
||||
- [ ] Dependencies updated monthly
|
||||
- [ ] Logs monitored weekly
|
||||
- [ ] Backups verified monthly
|
||||
- [ ] Access control reviewed quarterly
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [Fly.io Security Best Practices](https://fly.io/docs/reference/security/)
|
||||
- [PostgreSQL Security](https://www.postgresql.org/docs/current/runtime-config-connection.html#RUNTIME-CONFIG-CONNECTION-SSL)
|
||||
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Fastify Security](https://www.fastify.io/docs/latest/Guides/Security/)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-01-13
|
||||
|
||||
Review and update this checklist quarterly or after any security incident.
|
||||
Reference in New Issue
Block a user