Skip to content

Commit 91d2be5

Browse files
committed
docs: [#277] add issue specification for MySQL port security fix
- Create issue #277 for MySQL port 3306 public exposure security issue - Add detailed specification document with implementation plan - Add healthchecks to project dictionary
1 parent 29c1e23 commit 91d2be5

2 files changed

Lines changed: 187 additions & 66 deletions

File tree

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Security: MySQL port 3306 is publicly exposed in Docker Compose configuration
2+
3+
**Issue**: #277
4+
**Parent Epic**: None (standalone security fix)
5+
**Related**: [docs/decisions/docker-ufw-firewall-security-strategy.md](../decisions/docker-ufw-firewall-security-strategy.md)
6+
7+
## Overview
8+
9+
The MySQL service in the Docker Compose template exposes port 3306 publicly to all network interfaces, allowing external connections to the database. This is a security risk as it enables potential brute-force attacks on MySQL credentials and exposes the database to unauthorized access.
10+
11+
## Goals
12+
13+
- [ ] Remove public exposure of MySQL port 3306
14+
- [ ] Maintain MySQL healthcheck functionality
15+
- [ ] Ensure tracker can still connect to MySQL via internal Docker network
16+
17+
## 🏗️ Architecture Requirements
18+
19+
**DDD Layer**: Infrastructure (templates)
20+
**Module Path**: `templates/docker-compose/`
21+
**Pattern**: Template modification
22+
23+
### Module Structure Requirements
24+
25+
- [ ] Follow DDD layer separation (see [docs/codebase-architecture.md](../codebase-architecture.md))
26+
- [ ] Respect dependency flow rules (dependencies flow toward domain)
27+
- [ ] Use appropriate module organization (see [docs/contributing/module-organization.md](../contributing/module-organization.md))
28+
29+
### Architectural Constraints
30+
31+
- [ ] Template changes only - no Rust code changes required
32+
- [ ] Must maintain compatibility with existing environment configurations
33+
34+
### Anti-Patterns to Avoid
35+
36+
- ❌ Exposing internal services to public network
37+
- ❌ Breaking healthcheck functionality
38+
- ❌ Breaking inter-container communication
39+
40+
## Specifications
41+
42+
### Current State (Problematic)
43+
44+
The MySQL service in `templates/docker-compose/docker-compose.yml.tera` has:
45+
46+
```yaml
47+
mysql:
48+
# ...
49+
ports:
50+
- "3306:3306"
51+
```
52+
53+
This exposes MySQL to the entire network. Anyone with network access to the VM can connect to the database using the credentials.
54+
55+
### Verified Issue
56+
57+
The issue was verified by:
58+
59+
1. Creating a test environment with MySQL configuration (`envs/manual-mysql-test.json`)
60+
2. Deploying the environment
61+
3. Successfully connecting to MySQL from outside the VM:
62+
63+
```bash
64+
mysql -h 10.140.190.23 -P 3306 -u tracker_user -p tracker_password -e "SELECT 1;"
65+
+-----------------+
66+
| connection_test |
67+
+-----------------+
68+
| 1 |
69+
+-----------------+
70+
```
71+
72+
### Desired State (Secure)
73+
74+
Remove the `ports` section entirely. The MySQL healthcheck uses `mysqladmin ping -h localhost` which works without port exposure because it runs inside the container.
75+
76+
Unlike Prometheus (which binds to localhost for host validation via `curl http://localhost:9090`), MySQL only needs to be accessible by the tracker container via Docker's internal `database_network`, not from the host.
77+
78+
## Implementation Plan
79+
80+
### Phase 1: Fix Template (5 minutes)
81+
82+
- [ ] Task 1.1: Remove `ports: - "3306:3306"` from MySQL service in `docker-compose.yml.tera`
83+
- [ ] Task 1.2: Add security comment explaining why port is not exposed
84+
85+
### Phase 2: Verification (15 minutes)
86+
87+
- [ ] Task 2.1: Deploy test environment with MySQL
88+
- [ ] Task 2.2: Verify MySQL is NOT accessible from outside the VM (`nc -zv <ip> 3306` should fail)
89+
- [ ] Task 2.3: Verify healthcheck still works (container becomes healthy)
90+
- [ ] Task 2.4: Verify tracker can still connect to MySQL via internal network
91+
92+
## Acceptance Criteria
93+
94+
> **Note for Contributors**: These criteria define what the PR reviewer will check. Use this as your pre-review checklist before submitting the PR to minimize back-and-forth iterations.
95+
96+
**Quality Checks**:
97+
98+
- [ ] Pre-commit checks pass: `./scripts/pre-commit.sh`
99+
100+
**Security Criteria**:
101+
102+
- [ ] MySQL port 3306 is not accessible from outside the VM
103+
- [ ] MySQL healthcheck still passes (container reaches healthy state)
104+
- [ ] Tracker can still connect to MySQL via Docker internal network
105+
- [ ] E2E tests pass
106+
107+
## Related Documentation
108+
109+
- [Docker UFW Firewall Security Strategy](../decisions/docker-ufw-firewall-security-strategy.md)
110+
- [Docker Network Segmentation Analysis](../analysis/security/docker-network-segmentation-analysis.md)
111+
- [User Guide: Security](../user-guide/security.md)
112+
113+
## Notes
114+
115+
The fix is straightforward - simply remove the `ports` section from MySQL service. The healthcheck will continue to work because:
116+
117+
1. Docker healthchecks run inside the container
118+
2. `mysqladmin ping -h localhost` connects to MySQL within the container's network namespace
119+
3. No external port binding is required for container-internal commands

0 commit comments

Comments
 (0)