9.8 KiB
Sistema NAT Industrial para Acceso a PLCs/SCADA
Este proyecto crea un sistema NAT dinámico en WSL2 que permite a PC2 acceder a dispositivos PLC/SCADA en la red corporativa de PC1 a través de un servidor Linux intermediario (PC3). Soluciona las limitaciones de red de WSL2 y VPNs corporativas.
🎯 Arquitectura de Red Industrial
PC2 (Remoto) → PC3 (91.99.210.72) → PC1 (WSL2+VPN) → PLCs/SCADA (10.1.33.x)
↑ ↑ ↑ ↑
ZeroTier/Internet SSH Tunnel Túnel Reverso Red Corporativa
Intermediario desde WSL2 (GlobalConnect VPN)
Problema resuelto: PC1 está en una VPN corporativa con acceso a PLCs pero no puede abrir puertos. PC2 necesita acceder a esos PLCs remotamente.
🏭 Casos de Uso Industriales
- VNC a PLCs - Acceso gráfico remoto a pantallas HMI
- Interfaces Web - Configuración de dispositivos industriales
- Modbus TCP - Comunicación con controladores
- SSH/Telnet - Acceso terminal a equipos industriales
- Bases de datos - Historiadores y sistemas SCADA
- OPC/SCADA - Protocolos industriales
✨ Características del Sistema
- ✅ NAT Dinámico - Conecta a cualquier IP:puerto sin configuración previa
- ✅ Solo clave SSH privada - No necesita certificados SSL complejos
- ✅ Servicios industriales predefinidos - VNC, Modbus, HTTP, SSH automáticos
- ✅ Gestión desde PC2 - Control remoto completo via API REST
- ✅ Sistema permanente - Se ejecuta como servicio, auto-reinicio
- ✅ Múltiples PLCs simultáneos - Gestiona toda la planta industrial
📁 Estructura del Proyecto
proxytcp/
├── Dockerfile # Imagen del contenedor industrial
├── docker-compose.yml # Configuración de servicios
├── requirements.txt # Dependencias Python
├── src/
│ └── industrial_nat_manager.py # Sistema NAT principal
├── config/
│ └── nat_config.yaml # Configuración industrial
├── certs/ # Clave SSH privada
│ └── ssh_private_key # Tu clave SSH generada
├── scripts/
│ ├── nat_client.py # Cliente para PC2
│ ├── industrial_manager.sh # Gestión automatizada
│ └── generate_ssh_key.sh # Generador de claves
├── setup_permanent.sh # Configuración como servicio
└── logs/ # Logs del sistema
🚀 Instalación Completa
Paso 1: Generar Clave SSH (PC1)
# Generar nueva clave SSH específica
./scripts/generate_ssh_key.sh
Paso 2: Configurar PC3 (Servidor Intermediario)
## 🚨 **Resolución de Problemas**
### **Problemas Comunes**
#### **1. Error de conexión SSH a PC3**
```bash
# Verificar clave SSH
ls -la certs/ssh_private_key
chmod 600 certs/ssh_private_key
# Probar conexión manual
ssh -i certs/ssh_private_key miguefin@91.99.210.72
2. PLC no accesible desde PC2
# Verificar túnel SSH activo
docker exec proxytcp_proxy_1 ps aux | grep ssh
# Verificar configuración PC3
ssh -i certs/ssh_private_key miguefin@91.99.210.72 "sudo netstat -tlnp | grep :9"
3. Servicio no inicia automáticamente
# Verificar servicio systemd
sudo systemctl status industrial-nat-manager
# Ver logs del servicio
sudo journalctl -u industrial-nat-manager -f
# Reiniciar servicio
sudo systemctl restart industrial-nat-manager
4. Puertos ocupados
# Verificar puertos en uso
docker exec proxytcp_proxy_1 netstat -tlnp
# Limpiar conexiones
docker restart proxytcp_proxy_1
Información de Red
Flujo de Datos:
PC2 (Remoto) → PC3 (91.99.210.72) → PC1 (WSL2+VPN) → PLCs/SCADA (10.1.33.x)
Puertos Dinámicos: 9000-9999 en PC3
API de Control: Puerto 8080 en PC1
📚 Documentación Adicional
- PC3_SETUP.md - Configuración detallada del servidor intermediario
- INDUSTRIAL_README.md - Guía específica para uso industrial
- config/nat_config.yaml - Referencia de configuración completa
🤝 Soporte
Este sistema está diseñado para entornos industriales que requieren acceso remoto a PLCs y sistemas SCADA a través de limitaciones de red corporativa.
Casos de uso típicos:
- Monitoreo remoto de plantas industriales
- Mantenimiento de equipos desde ubicaciones remotas
- Acceso a HMI/SCADA sin VPN corporativa
- Gestión de múltiples PLCs simultáneamente
🏭 Sistema NAT Industrial para Acceso Remoto a PLCs/SCADA 🏭
### **Paso 3: Configurar Sistema Permanente (PC1)**
```bash
# Instalar como servicio permanente
./setup_permanent.sh
# ¡El sistema queda funcionando automáticamente!
<EFBFBD> Uso del Sistema
Desde PC2 (Remoto) - Acceso Industrial
# Copiar el cliente a PC2
scp nat_client.py pc2@ip.del.pc2:/ruta/destino/
# En PC2, conectar a PLCs usando servicios predefinidos:
# 1. Conectar a PLC via VNC (visualización)
python nat_client.py plc 10.1.33.11 vnc
# 2. Conectar a PLC via Modbus TCP (datos)
python nat_client.py plc 10.1.33.11 modbus
# 3. Conectar a interfaz web del PLC
python nat_client.py plc 10.1.33.11 http
# 4. Acceso SSH a dispositivo industrial
python nat_client.py plc 10.1.33.15 ssh
# 5. Conexión personalizada
python nat_client.py connect 10.1.33.20 8080 --name "Servidor_SCADA"
Gestión Avanzada (PC1)
# Ver estado del sistema
docker exec proxytcp_proxy_1 python -c "
import aiohttp, asyncio
async def status():
async with aiohttp.ClientSession() as session:
async with session.get('http://localhost:8080/status') as resp:
print(await resp.json())
asyncio.run(status())
"
# Gestión interactiva
./scripts/industrial_manager.sh
# Ver logs del sistema
docker logs proxytcp_proxy_1 -f
🔧 Configuración Industrial
Archivo de Configuración (config/nat_config.yaml
)
# Configuración del servidor PC3
ssh_server:
host: "91.99.210.72"
port: 22
user: "miguefin"
key_file: "/app/certs/ssh_private_key"
# Servicios industriales predefinidos
services:
vnc:
port: 5900
description: "Acceso remoto a pantallas HMI"
modbus:
port: 502
description: "Protocolo Modbus TCP"
http:
port: 80
description: "Interfaces web de dispositivos"
ssh:
port: 22
description: "Acceso SSH a dispositivos"
# Configuración de puertos dinámicos
nat:
port_range: [9000, 9999]
bind_host: "0.0.0.0"
🔧 Tipos de Servicios Disponibles
1. Servicio HTTP
Responde con JSON y información de la conexión:
# En el contenedor Docker expone puerto 3000
# En el servidor Linux se accede por puerto 3000
curl http://91.99.210.72:3000
2. Servicio Echo
Útil para pruebas de conectividad:
# Usando telnet o netcat
echo "Hello World" | nc 91.99.210.72 7000
3. Servicios Personalizados
Puedes crear tus propios servicios modificando ssh_proxy_manager.py
💡 Casos de Uso Comunes
1. API de Desarrollo
# Exponer API del contenedor al mundo
./scripts/manage_proxy.sh add 8000 8000
# Acceso: http://91.99.210.72:8000
2. Servicio de Pruebas
# Servicio echo para verificar conectividad
./scripts/manage_proxy.sh add 9999 9999
# Prueba: echo "test" | nc 91.99.210.72 9999
3. Múltiples Servicios
# Web frontend
./scripts/manage_proxy.sh add 3000 3000
# API backend
./scripts/manage_proxy.sh add 8000 8000
# WebSocket
./scripts/manage_proxy.sh add 9000 9000
🐛 Resolución de Problemas
El contenedor no inicia
# Verificar logs
docker logs tcp-proxy-container
# Verificar certificados
ls -la certs/
Error de conexión SSL
- Verifica que los certificados son válidos
- Confirma que el servidor remoto acepta tu certificado
- Revisa los logs para detalles del error
Puerto ya en uso
# Ver qué proceso usa el puerto
sudo netstat -tulpn | grep :PUERTO
# Eliminar proxy existente
./scripts/manage_proxy.sh remove PUERTO
Proxy no funciona
# Verificar estado
./scripts/manage_proxy.sh status
# Probar conexión manual
telnet localhost PUERTO_LOCAL
🔐 Seguridad
- Los certificados se montan como solo lectura
- El contenedor ejecuta con usuario no-root
- Las conexiones usan SSL/TLS end-to-end
- Los logs no registran datos sensibles
📊 Monitoreo
Verificar Conexiones Activas
# Estado general
./scripts/manage_proxy.sh status
# Conexiones detalladas
docker exec tcp-proxy-container netstat -an
Métricas de Uso
import requests
status = requests.get('http://localhost:8080/status').json()
print(f"Total conexiones: {status['total_connections']}")
for proxy in status['proxies']:
print(f"Puerto {proxy['local_port']}: {proxy['connections']} conexiones activas")
🚦 Scripts de Automatización
Script de Backup de Configuración
#!/bin/bash
# backup_config.sh
tar -czf "backup_$(date +%Y%m%d_%H%M%S).tar.gz" config/ certs/
Script de Monitoreo
#!/usr/bin/env python3
# monitor.py
import time
import requests
from datetime import datetime
while True:
try:
status = requests.get('http://localhost:8080/status', timeout=5).json()
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"[{timestamp}] Proxies: {len(status['proxies'])}, Conexiones: {status['total_connections']}")
except Exception as e:
print(f"Error: {e}")
time.sleep(30)
📝 Licencia
Este proyecto es de uso libre para fines personales y educativos.
🤝 Contribuciones
Para reportar problemas o sugerir mejoras, crea un issue en el repositorio del proyecto.
¡Listo para usar! El sistema está configurado para conectar automáticamente con tu servidor Linux usando los certificados proporcionados.