288 lines
7.5 KiB
Markdown
288 lines
7.5 KiB
Markdown
# Security Notes
|
|
|
|
## Network Security Architecture
|
|
|
|
### Internal-Only Services
|
|
|
|
The following services are configured to be **internal-only** and are not exposed to the host machine or external network:
|
|
|
|
- **Ollama** - AI service (port 11434 internal only)
|
|
- **MongoDB** - Database (port 27017 internal only)
|
|
- **Crawler** - News crawler (no ports)
|
|
- **Sender** - Newsletter sender (no ports)
|
|
|
|
Only the **Backend API** is exposed to the host on port 5001.
|
|
|
|
This provides several security benefits:
|
|
|
|
### Ollama Service Security
|
|
|
|
**Configuration:**
|
|
```yaml
|
|
# Ollama service has NO ports exposed
|
|
ollama:
|
|
image: ollama/ollama:latest
|
|
# No ports section - internal only
|
|
networks:
|
|
- munich-news-network
|
|
```
|
|
|
|
**Benefits:**
|
|
1. **No External Access**: Ollama API cannot be accessed from outside Docker network
|
|
2. **Reduced Attack Surface**: Service is not exposed to potential external threats
|
|
3. **Network Isolation**: Only authorized Docker Compose services can communicate with Ollama
|
|
4. **No Port Conflicts**: Port 11434 is not bound to host machine
|
|
|
|
### Accessing Ollama
|
|
|
|
**From Docker Compose Services (✓ Allowed):**
|
|
```bash
|
|
# Services use internal Docker network
|
|
OLLAMA_BASE_URL=http://ollama:11434
|
|
```
|
|
|
|
**From Host Machine (✗ Not Allowed):**
|
|
```bash
|
|
# This will NOT work - port not exposed
|
|
curl http://localhost:11434/api/tags
|
|
# Connection refused
|
|
```
|
|
|
|
**From Inside Containers (✓ Allowed):**
|
|
```bash
|
|
# Access from another container
|
|
docker-compose exec crawler curl http://ollama:11434/api/tags
|
|
```
|
|
|
|
### Why This Matters
|
|
|
|
**Security Risks of Exposed Ollama:**
|
|
- Unauthorized access to AI models
|
|
- Potential for abuse (resource consumption)
|
|
- Information disclosure through prompts
|
|
- No authentication by default
|
|
- Could be used for unintended purposes
|
|
|
|
**With Internal-Only Configuration:**
|
|
- Only your trusted services can access Ollama
|
|
- No external attack vector
|
|
- Controlled usage within your application
|
|
- Better resource management
|
|
|
|
### Testing Ollama
|
|
|
|
Since Ollama is internal-only, you must test from inside the Docker network:
|
|
|
|
```bash
|
|
# ✓ Correct way - from inside a container
|
|
docker-compose exec crawler curl -s http://ollama:11434/api/tags
|
|
|
|
# ✓ Test translation
|
|
docker-compose exec crawler python crawler_service.py 1
|
|
|
|
# ✓ Check logs
|
|
docker-compose logs ollama
|
|
```
|
|
|
|
### If You Need External Access
|
|
|
|
If you have a specific need to access Ollama from the host machine (e.g., development, debugging), you can temporarily expose it:
|
|
|
|
**Option 1: Temporary Port Forward**
|
|
```bash
|
|
# Forward port temporarily (stops when you press Ctrl+C)
|
|
docker exec -it munich-news-ollama socat TCP-LISTEN:11434,fork TCP:localhost:11434 &
|
|
```
|
|
|
|
**Option 2: Add Ports to docker-compose.yml (Not Recommended)**
|
|
```yaml
|
|
ollama:
|
|
ports:
|
|
- "127.0.0.1:11434:11434" # Only bind to localhost, not 0.0.0.0
|
|
```
|
|
|
|
**⚠️ Warning:** Only expose Ollama if absolutely necessary, and always bind to `127.0.0.1` (localhost only), never `0.0.0.0` (all interfaces).
|
|
|
|
### Other Security Considerations
|
|
|
|
**MongoDB:**
|
|
- ✅ **Internal-only** (not exposed to host)
|
|
- Uses authentication (username/password)
|
|
- Only accessible via Docker network
|
|
- Cannot be accessed from host machine or external network
|
|
|
|
**Backend API:**
|
|
- Exposed on port 5001 for tracking and admin functions
|
|
- Should be behind reverse proxy in production
|
|
- Consider adding authentication for admin endpoints
|
|
- In production, bind to localhost only: `127.0.0.1:5001:5001`
|
|
|
|
**Email Credentials:**
|
|
- Stored in `.env` file
|
|
- Never commit `.env` to version control
|
|
- Use environment variables in production
|
|
|
|
### Production Recommendations
|
|
|
|
1. **Use Docker Secrets** for sensitive data:
|
|
```yaml
|
|
secrets:
|
|
mongo_password:
|
|
external: true
|
|
```
|
|
|
|
2. **Restrict Backend to Localhost** (if not using reverse proxy):
|
|
```yaml
|
|
backend:
|
|
ports:
|
|
- "127.0.0.1:5001:5001" # Only accessible from localhost
|
|
```
|
|
|
|
3. **Use Reverse Proxy** (nginx, Traefik) - Recommended:
|
|
```yaml
|
|
backend:
|
|
# Remove ports section - only accessible via reverse proxy
|
|
expose:
|
|
- "5001"
|
|
```
|
|
|
|
Benefits:
|
|
- SSL/TLS termination
|
|
- Rate limiting
|
|
- Authentication
|
|
- Access logs
|
|
- DDoS protection
|
|
|
|
4. **Regular Updates**:
|
|
```bash
|
|
docker-compose pull
|
|
docker-compose up -d
|
|
```
|
|
|
|
5. **Monitor Logs**:
|
|
```bash
|
|
docker-compose logs -f
|
|
```
|
|
|
|
6. **Network Isolation**:
|
|
- ✅ Already configured: MongoDB, Ollama, Crawler, Sender are internal-only
|
|
- Only Backend API is exposed
|
|
- All services communicate via internal Docker network
|
|
|
|
### Security Checklist
|
|
|
|
- [x] Ollama is internal-only (no exposed ports)
|
|
- [x] MongoDB is internal-only (no exposed ports)
|
|
- [x] MongoDB uses authentication
|
|
- [x] Crawler is internal-only (no exposed ports)
|
|
- [x] Sender is internal-only (no exposed ports)
|
|
- [x] Only Backend API is exposed (port 5001)
|
|
- [x] `.env` file is in `.gitignore`
|
|
- [ ] Backend API has authentication (if needed)
|
|
- [ ] Using HTTPS in production (reverse proxy)
|
|
- [ ] Regular security updates
|
|
- [ ] Monitoring and logging enabled
|
|
- [ ] Backup strategy in place
|
|
|
|
## Reporting Security Issues
|
|
|
|
If you discover a security vulnerability, please email security@example.com (replace with your contact).
|
|
|
|
Do not open public issues for security vulnerabilities.
|
|
|
|
|
|
---
|
|
|
|
## Network Isolation Summary
|
|
|
|
### Current Port Exposure
|
|
|
|
| Service | Port | Exposed to Host | Security Status |
|
|
|---------|------|-----------------|-----------------|
|
|
| Backend API | 5001 | ✅ Yes | Only exposed service |
|
|
| MongoDB | 27017 | ❌ No | Internal only |
|
|
| Ollama | 11434 | ❌ No | Internal only |
|
|
| Crawler | - | ❌ No | Internal only |
|
|
| Sender | - | ❌ No | Internal only |
|
|
|
|
### Security Improvements Applied
|
|
|
|
**Ollama Service:**
|
|
- Changed from exposed (port 11434) to internal-only
|
|
- Only accessible via Docker network
|
|
- Prevents unauthorized AI model usage
|
|
|
|
**MongoDB Service:**
|
|
- Changed from exposed (port 27017) to internal-only
|
|
- Only accessible via Docker network
|
|
- Prevents unauthorized database access
|
|
|
|
**Result:**
|
|
- 66% reduction in attack surface (3 services → 1 service exposed)
|
|
- Better defense in depth
|
|
- Production-ready security configuration
|
|
|
|
### Verification Commands
|
|
|
|
```bash
|
|
# Check what's exposed
|
|
docker ps --format "table {{.Names}}\t{{.Ports}}"
|
|
|
|
# Expected output:
|
|
# Backend: 0.0.0.0:5001->5001/tcp ← Only this exposed
|
|
# MongoDB: 27017/tcp ← Internal only
|
|
# Ollama: 11434/tcp ← Internal only
|
|
|
|
# Test MongoDB not accessible from host
|
|
nc -z -w 2 localhost 27017 # Should fail
|
|
|
|
# Test Ollama not accessible from host
|
|
nc -z -w 2 localhost 11434 # Should fail
|
|
|
|
# Test Backend accessible from host
|
|
curl http://localhost:5001/health # Should work
|
|
```
|
|
|
|
---
|
|
|
|
## MongoDB Connection Security
|
|
|
|
### Configuration
|
|
|
|
**Inside Docker Network:**
|
|
```env
|
|
MONGODB_URI=mongodb://admin:changeme@mongodb:27017/
|
|
```
|
|
- Uses `mongodb` (Docker service name)
|
|
- Only works inside Docker network
|
|
- Cannot be accessed from host
|
|
|
|
**Connection Flow:**
|
|
1. Service reads `MONGODB_URI` from environment
|
|
2. Docker DNS resolves `mongodb` to container IP
|
|
3. Connection established via internal network
|
|
4. No external exposure
|
|
|
|
### Why This Is Secure
|
|
|
|
- MongoDB port (27017) not exposed to host
|
|
- Only Docker Compose services can connect
|
|
- Uses authentication (username/password)
|
|
- Network isolation prevents external access
|
|
|
|
---
|
|
|
|
## Testing Security Configuration
|
|
|
|
Run the connectivity test:
|
|
```bash
|
|
./test-mongodb-connectivity.sh
|
|
```
|
|
|
|
Expected results:
|
|
- ✅ MongoDB NOT accessible from host
|
|
- ✅ Backend CAN connect to MongoDB
|
|
- ✅ Crawler CAN connect to MongoDB
|
|
- ✅ Sender CAN connect to MongoDB
|
|
- ✅ Backend API accessible from host
|