# 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