A Docker-based simulation of an industrial control system featuring SCADA, PLC, and Remote I/O (RIO) devices with proper network isolation and security boundaries.
WaterTRAP simulates a realistic industrial network architecture commonly found in water treatment facilities and manufacturing plants. The system demonstrates:
- Network Segmentation: Isolated SCADA and RIO networks with PLC as the secure gateway
- Industrial Protocols: Modbus TCP communication between components
- Security by Design: SCADA cannot directly access field devices (RIO)
- Real-time Control: Automated control logic based on sensor readings
┌─────────────────┐ ┌─────────────────┐
│ SCADA │ │ RIO_SENSOR1 │
│ 192.168.1.20 │ │ 192.168.2.20 │
└────────┬────────┘ └────────┬────────┘
│ │
│ SCADA Network │ RIO Network
│ (192.168.1.0/24) │ (192.168.2.0/24)
│ │
┌────┴───────────────────────────┴────┐
│ PLC │
│ 192.168.1.10 | 192.168.2.10 │
│ (Dual Interface) │
└────┬───────────────────────────┬────┘
│ │
│ ┌──────┴──────┐ ┌─────────────────┐
│ │ RIO_SENSOR2 │ │ RIO_ACTUATOR │
│ │192.168.2.21 │ │ 192.168.2.30 │
│ └─────────────┘ └─────────────────┘
│
Proxy API (Port 8080)
- Monitors PLC registers via Modbus TCP
- Sends control commands to actuators
- Isolated from field devices for security
- Interactive command interface for operator control
- Dual network interfaces connecting both networks
- Runs control logic based on sensor inputs
- Modbus server on port 502
- HTTP proxy API on port 8080 for SCADA-RIO communication
- Implements safety logic: Actuator ON when sensor1 > 150 AND sensor2 < 20
- Sensor 1: Simulates water level readings (cycles: 100, 160, 140, 170)
- Sensor 2: Simulates pressure readings (cycles: 10, 25, 15, 30, 5)
- Actuator: Controls pump/valve (ON/OFF based on PLC commands)
- Docker Engine 20.10+
- Docker Compose V2
- Python 3.9+ (for testing scripts)
# Clone the repository
git clone https://github.com/yourusername/watertrap.git
cd watertrap
# Run the automated setup
chmod +x setup.sh
./setup.sh# Build and start all services
docker compose up -d
# View logs
docker compose logs -f
# Stop all services
docker compose down# View all container logs
docker compose logs -f
# View specific component
docker compose logs -f plcThe SCADA container provides an interactive interface:
- Enter
1 3to turn ON actuator for PLC1 - Enter
1 4to turn OFF actuator for PLC1
# From host machine
docker exec scada ping -c 1 192.168.2.20 # Should fail
docker exec plc ping -c 1 192.168.2.20 # Should succeedTest the proxy communication:
python3 test_proxy.pyAPI Endpoints (Port 8080):
- Get Status:
{"command": "status"} - Control Actuator:
{"command": "write", "device": "actuator", "value": 1}
- Network Isolation: SCADA and RIO devices on separate networks
- No Direct Access: SCADA cannot directly communicate with field devices
- Controlled Gateway: PLC acts as the only bridge between networks
- Proxy Authentication: Can be extended with authentication mechanisms
watertrap/
├── docker-compose.yml # Container orchestration
├── setup.sh # Automated setup script
├── test_proxy.py # Proxy API testing
├── scada/ # SCADA application
│ ├── Dockerfile
│ ├── scada.py
│ └── req.txt
├── plc/ # PLC controller
│ ├── Dockerfile
│ ├── plcServer.py
│ ├── plc_proxy.py
│ └── req.txt
├── rio-sensor/ # Sensor simulators
│ ├── sensor1/
│ └── sensor2/
└── rio-act/ # Actuator simulator
├── Dockerfile
├── actuator_server.py
└── req.txt
- Add More PLCs: Update
plcslist inscada/scada.py - Add More Sensors: Create new sensor directories and update docker-compose.yml
- Modify Control Logic: Edit PLC logic in
plc/plcServer.py - Add Authentication: Extend
plc/plc_proxy.pywith auth mechanisms
- Port Conflicts: Ensure ports 502, 8080, 5021-5030 are available
- Network Creation Failed: Remove existing networks with
docker network prune - Container Start Failed: Check logs with
docker compose logs [container_name]
# Check network configuration
docker network inspect watertrap_scada_net
docker network inspect watertrap_rio_net
# Enter container shell
docker exec -it plc /bin/bash
# Check Modbus communication
docker exec plc python -c "from pymodbus.client.sync import ModbusTcpClient; client = ModbusTcpClient('192.168.2.20', 5021); print(client.connect())"- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built using PyModbus for industrial protocol simulation
- Docker for containerization and network isolation
- Inspired by real-world SCADA architectures in critical infrastructure
This is a simulation tool for educational and testing purposes. Do not use in production environments without proper security hardening.