|
| 1 | +# Security Guide |
| 2 | + |
| 3 | +This guide covers security considerations and best practices when deploying Torrust Tracker using the deployer. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +Security is a critical aspect of production deployments. The Torrust Tracker Deployer implements several security measures automatically during the deployment process, with additional considerations for production environments. |
| 8 | + |
| 9 | +## Firewall Configuration |
| 10 | + |
| 11 | +### Automatic Firewall Setup |
| 12 | + |
| 13 | +**CRITICAL**: The `configure` command automatically configures UFW (Uncomplicated Firewall) on virtual machines to protect internal services from unauthorized external access. |
| 14 | + |
| 15 | +During the `configure` step, the deployer: |
| 16 | + |
| 17 | +1. **Installs UFW** - Ensures the firewall is available |
| 18 | +2. **Sets restrictive policies** - Denies all incoming traffic by default |
| 19 | +3. **Allows SSH access** - Preserves SSH connectivity (configured port) |
| 20 | +4. **Allows tracker services** - Opens only necessary tracker ports: |
| 21 | + - UDP tracker ports (configured in environment) |
| 22 | + - HTTP tracker ports (configured in environment) |
| 23 | + - HTTP API port (configured in environment) |
| 24 | +5. **Enables the firewall** - Activates rules to protect the system |
| 25 | + |
| 26 | +### Why Firewall Configuration Matters |
| 27 | + |
| 28 | +The Docker Compose configuration (`templates/docker-compose/docker-compose.yml.tera`) exposes several service ports that should **NOT** be publicly accessible: |
| 29 | + |
| 30 | +**Exposed Ports in Docker Compose**: |
| 31 | + |
| 32 | +```yaml |
| 33 | +services: |
| 34 | + # Tracker - Public ports (UDP/HTTP tracker, HTTP API) |
| 35 | + tracker: |
| 36 | + ports: |
| 37 | + - "6969:6969/udp" # ✅ Public - UDP tracker |
| 38 | + - "7070:7070" # ✅ Public - HTTP tracker |
| 39 | + - "1212:1212" # ✅ Public - HTTP API |
| 40 | + |
| 41 | + # Prometheus - INTERNAL ONLY |
| 42 | + prometheus: |
| 43 | + ports: |
| 44 | + - "9090:9090" # ⚠️ INTERNAL - Metrics UI |
| 45 | + |
| 46 | + # MySQL - INTERNAL ONLY |
| 47 | + mysql: |
| 48 | + ports: |
| 49 | + - "3306:3306" # ⚠️ INTERNAL - Database |
| 50 | +``` |
| 51 | +
|
| 52 | +**Without firewall protection**, services like Prometheus (port 9090) and MySQL (port 3306) would be accessible from the internet, potentially exposing: |
| 53 | +
|
| 54 | +- **Prometheus** - Internal metrics, performance data, system topology |
| 55 | +- **MySQL** - Database access (even with authentication, this is a security risk) |
| 56 | +
|
| 57 | +**With firewall protection** (UFW configured by `configure` command): |
| 58 | + |
| 59 | +- ✅ **Tracker ports** - Accessible externally (UDP tracker, HTTP tracker, HTTP API) |
| 60 | +- 🔒 **Prometheus port** - Blocked from external access |
| 61 | +- 🔒 **MySQL port** - Blocked from external access |
| 62 | +- ✅ **SSH access** - Preserved for administration |
| 63 | + |
| 64 | +### E2E Testing vs Production |
| 65 | + |
| 66 | +**E2E Testing (Docker Containers)**: |
| 67 | + |
| 68 | +- Uses Docker containers instead of VMs for faster test execution |
| 69 | +- Firewall **NOT** configured inside containers (containers provide isolation) |
| 70 | +- Services exposed for testing purposes |
| 71 | +- ⚠️ **NOT suitable for production use** |
| 72 | + |
| 73 | +**Production Deployments (Virtual Machines)**: |
| 74 | + |
| 75 | +- Uses real VMs (LXD, cloud providers) |
| 76 | +- Firewall **automatically configured** by `configure` command |
| 77 | +- Only tracker services exposed externally |
| 78 | +- ✅ **Production-ready security posture** |
| 79 | + |
| 80 | +### Firewall Rules Applied |
| 81 | + |
| 82 | +The deployer configures these firewall rules during the `configure` step: |
| 83 | + |
| 84 | +```bash |
| 85 | +# SSH Access (required for management) |
| 86 | +ufw allow <ssh-port>/tcp |
| 87 | +
|
| 88 | +# UDP Tracker Ports (configured in environment) |
| 89 | +ufw allow <udp-port>/udp |
| 90 | +
|
| 91 | +# HTTP Tracker Ports (configured in environment) |
| 92 | +ufw allow <http-port>/tcp |
| 93 | +
|
| 94 | +# HTTP API Port (configured in environment) |
| 95 | +ufw allow <api-port>/tcp |
| 96 | +
|
| 97 | +# Default policies |
| 98 | +ufw default deny incoming # Block everything else |
| 99 | +ufw default allow outgoing # Allow outbound connections |
| 100 | +``` |
| 101 | + |
| 102 | +### Verifying Firewall Configuration |
| 103 | + |
| 104 | +After running the `configure` command, verify firewall rules: |
| 105 | + |
| 106 | +```bash |
| 107 | +# SSH into your VM |
| 108 | +INSTANCE_IP=$(cat data/<env-name>/environment.json | jq -r '.Configured.context.runtime_outputs.instance_ip') |
| 109 | +ssh -i <private-key> <username>@$INSTANCE_IP |
| 110 | +
|
| 111 | +# Check UFW status |
| 112 | +sudo ufw status numbered |
| 113 | +
|
| 114 | +# Expected output shows: |
| 115 | +# - SSH port allowed |
| 116 | +# - Tracker ports allowed (UDP/HTTP/API) |
| 117 | +# - Default deny incoming policy |
| 118 | +# - All other ports blocked |
| 119 | +``` |
| 120 | + |
| 121 | +**Example output**: |
| 122 | + |
| 123 | +```text |
| 124 | +Status: active |
| 125 | +
|
| 126 | + To Action From |
| 127 | + -- ------ ---- |
| 128 | +[ 1] 22/tcp ALLOW IN Anywhere |
| 129 | +[ 2] 6969/udp ALLOW IN Anywhere |
| 130 | +[ 3] 7070/tcp ALLOW IN Anywhere |
| 131 | +[ 4] 1212/tcp ALLOW IN Anywhere |
| 132 | +``` |
| 133 | + |
| 134 | +Note that ports 9090 (Prometheus) and 3306 (MySQL) are **not** in this list, meaning they are blocked from external access. |
| 135 | + |
| 136 | +## SSH Security |
| 137 | + |
| 138 | +### SSH Key Authentication |
| 139 | + |
| 140 | +The deployer requires SSH key-based authentication for VM access: |
| 141 | + |
| 142 | +**Best Practices**: |
| 143 | + |
| 144 | +1. **Use strong SSH keys** - Generate RSA keys with at least 4096 bits: |
| 145 | + |
| 146 | + ```bash |
| 147 | + ssh-keygen -t rsa -b 4096 -f ~/.ssh/torrust_deploy |
| 148 | + ``` |
| 149 | + |
| 150 | +2. **Protect private keys** - Set restrictive permissions: |
| 151 | + |
| 152 | + ```bash |
| 153 | + chmod 600 ~/.ssh/torrust_deploy |
| 154 | + ``` |
| 155 | + |
| 156 | +3. **Use dedicated keys** - Don't reuse personal SSH keys for deployments |
| 157 | + |
| 158 | +4. **Rotate keys regularly** - Update SSH keys periodically |
| 159 | + |
| 160 | +### SSH Port Configuration |
| 161 | + |
| 162 | +The default SSH port (22) is commonly targeted by automated attacks. Consider using a custom port: |
| 163 | + |
| 164 | +```json |
| 165 | +{ |
| 166 | + "ssh_credentials": { |
| 167 | + "port": 2222 // Custom SSH port |
| 168 | + } |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +**Trade-offs**: |
| 173 | + |
| 174 | +- ✅ Reduces automated attack attempts |
| 175 | +- ✅ Adds minimal security through obscurity |
| 176 | +- ⚠️ Must remember custom port for manual access |
| 177 | +- ⚠️ Not a substitute for strong authentication |
| 178 | + |
| 179 | +## Docker Security Considerations |
| 180 | + |
| 181 | +### Container Isolation |
| 182 | + |
| 183 | +Services run in isolated Docker containers with: |
| 184 | + |
| 185 | +- **Network isolation** - Backend network for inter-container communication |
| 186 | +- **Volume mounts** - Limited filesystem access with `:Z` SELinux labels |
| 187 | +- **Resource limits** - Logging limits prevent disk exhaustion |
| 188 | +- **Restart policies** - Automatic recovery from failures |
| 189 | + |
| 190 | +### Image Security |
| 191 | + |
| 192 | +**Current Images**: |
| 193 | + |
| 194 | +- `torrust/tracker:develop` - Torrust Tracker (development tag) |
| 195 | +- `prom/prometheus:v3.0.1` - Prometheus (pinned version) |
| 196 | +- `mysql:8.0` - MySQL (major version pinned) |
| 197 | + |
| 198 | +**Recommendations**: |
| 199 | + |
| 200 | +1. **Pin specific versions** - Use exact version tags in production |
| 201 | +2. **Scan images regularly** - Check for known vulnerabilities |
| 202 | +3. **Update periodically** - Apply security patches |
| 203 | +4. **Use official images** - Prefer official/verified images |
| 204 | + |
| 205 | +### Environment Variables |
| 206 | + |
| 207 | +Sensitive configuration is managed via `.env` files on the VM: |
| 208 | + |
| 209 | +**Best Practices**: |
| 210 | + |
| 211 | +1. **Strong passwords** - Use complex, randomly generated passwords |
| 212 | +2. **Unique credentials** - Different passwords per environment |
| 213 | +3. **Secure storage** - Never commit `.env` files to version control |
| 214 | +4. **Rotation policy** - Update passwords periodically |
| 215 | + |
| 216 | +**Example** (DO NOT use these values): |
| 217 | + |
| 218 | +```bash |
| 219 | +# Bad - Weak passwords |
| 220 | +MYSQL_ROOT_PASSWORD=password123 |
| 221 | +MYSQL_PASSWORD=tracker |
| 222 | +
|
| 223 | +# Good - Strong, unique passwords |
| 224 | +MYSQL_ROOT_PASSWORD=7k#mP9$vL2@qX5nR8jW |
| 225 | +MYSQL_PASSWORD=xF4!hT6@dN9$sK2mQ7wE |
| 226 | +``` |
| 227 | + |
| 228 | +## Network Security |
| 229 | + |
| 230 | +### Service Exposure |
| 231 | + |
| 232 | +The deployer follows the principle of least exposure: |
| 233 | + |
| 234 | +**Public Services** (accessible externally): |
| 235 | + |
| 236 | +- UDP Tracker - Required for BitTorrent protocol |
| 237 | +- HTTP Tracker - Required for HTTP-based tracker operations |
| 238 | +- HTTP API - Required for tracker management and metrics |
| 239 | + |
| 240 | +**Internal Services** (blocked by firewall): |
| 241 | + |
| 242 | +- Prometheus UI - Metrics collection (internal monitoring only) |
| 243 | +- MySQL Database - Data storage (internal access only) |
| 244 | + |
| 245 | +### Internal Communication |
| 246 | + |
| 247 | +Services communicate via Docker's `backend_network`: |
| 248 | + |
| 249 | +- Container-to-container communication allowed |
| 250 | +- Isolated from host network by default |
| 251 | +- DNS resolution via container names (e.g., `tracker`, `mysql`, `prometheus`) |
| 252 | + |
| 253 | +## Production Security Checklist |
| 254 | + |
| 255 | +Before deploying to production, verify: |
| 256 | + |
| 257 | +### Infrastructure Security |
| 258 | + |
| 259 | +- [ ] **Virtual machines used** (not Docker containers for testing) |
| 260 | +- [ ] **Firewall configured** (`configure` command completed successfully) |
| 261 | +- [ ] **SSH key authentication** (password authentication disabled) |
| 262 | +- [ ] **Custom SSH port** (optional but recommended) |
| 263 | +- [ ] **Firewall rules verified** (`ufw status` shows expected rules) |
| 264 | + |
| 265 | +### Credential Security |
| 266 | + |
| 267 | +- [ ] **Strong SSH keys** (4096-bit RSA minimum) |
| 268 | +- [ ] **Strong database passwords** (randomly generated, complex) |
| 269 | +- [ ] **Unique API tokens** (per environment, rotated regularly) |
| 270 | +- [ ] **No credentials in git** (`.env` files gitignored) |
| 271 | +- [ ] **Secure key storage** (restricted permissions on private keys) |
| 272 | + |
| 273 | +### Application Security |
| 274 | + |
| 275 | +- [ ] **Pinned image versions** (not using `latest` or `develop` tags) |
| 276 | +- [ ] **Image scanning enabled** (vulnerability checks in CI/CD) |
| 277 | +- [ ] **Logging configured** (audit trail and debugging) |
| 278 | +- [ ] **Resource limits set** (prevent resource exhaustion) |
| 279 | +- [ ] **Regular updates scheduled** (security patches applied) |
| 280 | + |
| 281 | +### Monitoring Security |
| 282 | + |
| 283 | +- [ ] **Prometheus UI not exposed** (firewall blocks port 9090) |
| 284 | +- [ ] **Database not exposed** (firewall blocks port 3306) |
| 285 | +- [ ] **Access logs reviewed** (regular security audits) |
| 286 | +- [ ] **Metrics monitored** (unusual patterns detected) |
| 287 | + |
| 288 | +## Security Incident Response |
| 289 | + |
| 290 | +If you suspect a security breach: |
| 291 | + |
| 292 | +1. **Isolate the system** - Disable network access if necessary |
| 293 | +2. **Check logs** - Review `data/logs/log.txt` and container logs |
| 294 | +3. **Review firewall rules** - Verify UFW configuration hasn't changed |
| 295 | +4. **Rotate credentials** - Update all passwords and keys immediately |
| 296 | +5. **Update software** - Apply latest security patches |
| 297 | +6. **Report vulnerabilities** - Contact maintainers for Torrust Tracker issues |
| 298 | + |
| 299 | +## Future Security Enhancements |
| 300 | + |
| 301 | +Planned improvements for future releases: |
| 302 | + |
| 303 | +- **TLS/SSL support** - HTTPS for HTTP tracker and API |
| 304 | +- **Certificate management** - Automated Let's Encrypt integration |
| 305 | +- **Rate limiting** - Protection against abuse |
| 306 | +- **Fail2ban integration** - Automated IP blocking for failed attempts |
| 307 | +- **Security scanning** - Automated vulnerability detection in CI/CD |
| 308 | +- **Audit logging** - Detailed access logs for compliance |
| 309 | + |
| 310 | +## Additional Resources |
| 311 | + |
| 312 | +### Related Documentation |
| 313 | + |
| 314 | +- **[User Guide](README.md)** - Main deployment guide |
| 315 | +- **[Configuration Guide](configuration/)** - Environment configuration details |
| 316 | +- **[Services Guide](services/)** - Service-specific security considerations |
| 317 | + |
| 318 | +### External Resources |
| 319 | + |
| 320 | +- **[UFW Documentation](https://help.ubuntu.com/community/UFW)** - Firewall configuration |
| 321 | +- **[Docker Security Best Practices](https://docs.docker.com/engine/security/)** - Container security |
| 322 | +- **[SSH Hardening Guide](https://www.ssh.com/academy/ssh/security)** - SSH security best practices |
| 323 | +- **[OWASP Top 10](https://owasp.org/www-project-top-ten/)** - Web application security risks |
| 324 | + |
| 325 | +## Questions or Concerns? |
| 326 | + |
| 327 | +Security is an ongoing process. If you have questions or discover security issues: |
| 328 | + |
| 329 | +- **Security Issues** - Report privately to maintainers (do not open public issues) |
| 330 | +- **General Questions** - [GitHub Discussions](https://github.com/torrust/torrust-tracker-deployer/discussions) |
| 331 | +- **Feature Requests** - [GitHub Issues](https://github.com/torrust/torrust-tracker-deployer/issues) |
| 332 | + |
| 333 | +Stay secure! 🔒 |
0 commit comments