Reenvío de puerto: Tunelizando conexiones por SSH

Publicado por Diego Córdoba en

En esta oportunidad vamos a aprender a hacer reenvío de puerto y conectarnos a un servidor remoto (particularmente MySQL) utilizando un túnel SSH para maximizar la seguridad del acceso.


Motivaciones

¿Cuántas veces necesitamos utilizar algún cliente de conexión a MySQL como el mysql-client o MySQL Workbench, para poder administrar un servidor Mysql?

Claro, para ello «necesitamos» abrir el puerto tcp 3306 en el servidor, lo que a simple vista no parece una muy buena idea.

Ya se, se preguntarán ¿Por qué no utilizar phpmyadmin y utilizar el web server?

Particularmente prefiero no utilizarlo por una cuestión de seguridad en mis servidores, pero eso es otro tema.

Entonces… ¿cuál podría ser la solución?

Y la respuesta a esta pregunta viene, como muchas veces, de la mano de SSH, en este caso, a través del reenvío de puerto 🙂

Cabe aclarar que lo que explicaré en este artículo es válido para cualquier servicio TCP que esté atendiendo remotamente. Si se desea tunelizar un protocolo que corra sobre UDP debe usarse otro mecanismo 🙂

Túnel SSHssh mysql

SSH es un súper protocolo, un protocolo extremadamente versátil y útil para un montón de aplicaciones.

Ya hemos escrito largo y tendido sobre SSH en este blog, algunas de las entradas que pueden ser de interés son:

A grandes rasgos, SSH permite establecer una conexión de contenido cifrado de alta seguridad entre nuestro ordenador y un servidor en la red.

SSH, además de permitirnos armar túneles para proxificar una conexión web, o realizar conexiones invertidas, o montar un sistema de archivos en red, o incluso levantar una VPN, también permite, como es la intención explicar aquí, tunelizar otros protocolos de aplicación sobre SSH… en este caso, MySQL.

Esquema de la comunicación

En la siguiente figura se puede analizar brevemente el esquema de la comunicación a realizar.

mysql tunnel ssh security privacy hack hacking reenvío de peurto

La idea es dejar oculto el puerto tcp3306 en el servidor (mysql), y solo permitirnos conexión por SSH (¿quien no tiene ya un SSH en el server? :D).

El cliente al establecer la conexión SSH contra el servidor, va a abrir automáticamente en el host local (Cliente) el puerto 3306 para el mysql, pero de una forma en la que el cliente Mysql local, como mysql-client por línea de comandos, o MySQL Workbench, o cualquier otro, se conecten al server remoto apuntándole a la dirección ip local 127.0.0.1.

Todo el tráfico Mysql dirigido a la ip local de localhost será dirigido automáticamente, a través del reenvío de puerto de SSH, al servidor remoto, por medio del túnel cifrado.

El tráfico mysql en sí, será cifrado en el cliente, enviado por dentro del túnel de red de SSH, descifrado en el servidor y entregado localmente al server en su puerto tcp 3306 local.

¿Interesante no? Vamos con la práctica.

Configuración del reenvío de puerto

Suponiendo que nuestro servidor SSH/mysql está en la dirección ip 11.22.33.44, y queremos abrir un puerto en el cliente (IP 127.0.0.1) por donde reenviar tráfico MySQL, como explicamos en el esquema anterior, solo debemos ejecutar el siguiente comando (previo, por supuesto, ya disponer de cliente y serveridor SSH configurado).

ssh -L 12345:127.0.0.1:3306 usuario_ssh@11.22.33.44

Aquí,

  • -L permite especificar un puerto local que será reenviado al servidor SSH remoto hacia un puerto remoto.
  • 12345: es el puerto local que reenviaremos al servidor remoto.
  • 127.0.0.1 es la dirección ip local en el equipo remoto en la que atiende el servicio. En este caso es la de localhost.
  • :3306 es el puerto remoto que será mapeado y asociado a esta conexión en el puerto local.
  • usuario_ssh es el usuario con el que vamos a conectarnos al SSH remoto.
  • 11.22.33.44 es el servidor remoto que atiende en el puerto de SSH hacia Internet, y que localmente tiene un servidor Mysql escuchando en una ip privada.

Luego de ejecutar este comando, podremos ver el puerto 12345 en nuestra ip local esperando conexiones, y por supuesto, podremos utilizar cualquier cliente de Mysql para conectarnos al servidor «127.0.0.1» o «localhost». Todas las consultas que realicemos hacia el puerto local 12345 serán reenviadas al servidor Mysql remoto, puerto 3306.

No necesariamente tienen que ser estos puertos, podemos abrir cualquier puerto en el cliente, y que este puerto mapee contra el servidor en el 3306, simplemente reemplazando el primer «12345» en el comando anterior, por cualquier otro.

Además, suponiendo que en nuestra LAN tengamos mas de un equipo que quiera conectarse al mismo servidor, no es necesario que conecte SSH también, podemos especificar la ip de nuestra LAN antes del puerto local (192.168.x.y idealmente), o incluso * para permitir conectar a cualquier ip local de la LAN.

El comando quedaría así:

ssh -L *:12345:127.0.0.1:3306 usuario_ssh@11.22.33.44

Como nota adicional cabe aclarar que MySQL Workbench ya dispone de la lógica para permitir conexión a un server Mysql remoto por medio de un túnel SSH… pero en mi caso necesitaba, además, abrir el puerto para permitir conexiones de otros equipos virtualizados locales 🙂

Ejemplo

Si en nuestro cliente ejecutamos:

ssh -L 12345:127.0.0.1:3306 usuario_ssh@11.22.33.44

Y nos autenticamos contra el servidor, luego podremos conectar, por ejemplo, nuestro cliente Mysql por línea de comandos de esta forma:

mysql -h 127.0.0.1 -P 12345 -u usuario_mysql -p

Reenvío de puerto en un cliente Windows (Putty)

Si el equipo cliente es Window$, podemos simplemente instalar Putty, el genial cliente SSH para sistemas EXE, y ejecutarlo.

En los datos de conexión debemos colocar el usuario y host del equipo servidor remoto:

putty reenvio de puerto win

Luego, ir a la sección Connection -> SSH -> Tunnels, y crear un túnel local automático con un puerto origen determinado, 3306 en este caso, y socket destino ip:port del servidor remoto de mysql:

putty reenvio de puerto win

Al dar clic en Add / Agregar, veremos lo siguiente:

putty reenvio de puerto win

Esto indica que se ha configurado correctamente… solo debemos dar clic en «Open/Abrir» y typear nuestra contraseña SSH contra el servicio remoto, que si loguea, ya tendremos en la ip 127.0.0.1:3306 el servicio Mysql remoto corriendo y atendiendo en forma local 🙂

Evitando el reenvío o.0

Respondiendo a una duda que me hicieron en el curso de SSH sobre cómo evitar que alguien que tenga acceso a nuestro servidor SSH pueda realizar este tipo de túneles, tanto locales como el explicado en este artículo (-L) como remotos (-R).

Se puede configurar en el servidor de ssh, tanto de manera global, como mediante un bloque match para usuarios o clientes particulares.

La opción involucrada es: AllowTcpForwarding

Esta opción debe estar habilitada para que el servidor permita el reenvío de puertos TCP, tanto locales como remotos. Esta opción puede tomar los siguientes valores:

  • yes o all: permite todo tipo de reenvíos TCP, es el valor predeterminado.
  • no: bloquea todo tipo de reenvíos TCP.
  • local: permite solamente los reenvíos locales de TCP (-L)
  • remote: permite solamente los reenvíos remotos de TCP (-R)

Si queremos bloquear, por ejemplo, el reenvío local que estamos explicando en este artículo, podemos usar las opciones «no«, como «remote«, ya que esta última habilitará únicamente los reenvíos remotos, bloqueando los locales.

Por ejemplo, se podría añadir la siguiente línea al archivo de configuración del servidor SSH, /etc/ssh/sshd_config:

AllowTcpForwarding no

Y reiniciar el servicio sshd para cargar los cambios.


¡Espero que les sea de utilidad!


Video complementario: Reenvío de puerto

En nuestro canal de youtube hemos publicado un video con la explicación de este artículo, esperamos sea interesante y ameno!


¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!


Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador

6 comentarios

kabeza · 6 enero, 2017 a las 17:52

Buenisimo el dato. Consulta: en este caso tanto cliente como servidor tienen *nix como S.O., pero el cliente podria ser bien un Windows o cualquier cosa, no?

    Diego Cordoba - @d1cor · 6 enero, 2017 a las 19:30

    Hola! Si, si se puede configurando el túnel en Putty (el cliente SSH para Windows).
    Ahí actualicé el artículo y agregué esta info, es simplemente configurar un túnel SSH local automático contra el servcio remoto para que levante el puerto local.
    Espero te sirva!

Oscar Gallench · 20 noviembre, 2017 a las 19:09

me estoy volviendo loco, el putty parece que si accede al servidor, ya que me accepta el pass, pero luego intento acceder al phpmyadmin pero no abre…

    Diego Cordoba - @d1cor · 20 noviembre, 2017 a las 23:33

    Hola Oscar! Hay una confusión ahí. El artículo habla sobre cómo tunelizar conexiones de MYSQL sobre SSH, no http/https. Si el Putty te aceptó la password, significa que en tu ordenador vas a tener el puerto 3306 abierto para establecer conexiones contra el mysql remoto, por lo que con un cliente mysql deberías poder conectarte, como mysql desde línea de comandos, o mysql workbench apuntándole al localhost:3306 para acceder al servidor remoto.
    PHPmyadmin es un cliente web de mysql, que corre en un servidor web y atiende en el puerto 80/443, y el phpmyadmin internamente accede a los datos del mysql utilizando la conexión al puerto 3306.
    Esto significa que, si tenés el phpmyadmin instalado en tu máquina, éste debería acceder al server mysql remoto apuntándo a 127.0.0.1:3306.
    Si tenés el phpmyadmin en la máquina remota que hostea al mysql, y tenés acceso web a esa máquina, entonces deberías entrar con un navegador a la ip/nombre de la máquina remota, puerto 80/443.

    Conclusión, con el tunel ssh estás «trayendo» el puerto 3306 de la máquina remota a la tuya, de modo que puedas acceder al mysql remoto apuntándo a tu ip local, puerto 3306.
    Si de la misma forma querés acceder al phpmyadmin remoto, deberías hacer un trabajo similar para «traerte» el puerto 80/443 de la máquina remota a la tuya, y poder acceder al phpmyadmin apuntándo a tu dirección local.

    Espero que se haya entendido (algo, está rebuscado jaja).

    Cualquier duda quedo a disposición! Escribime que no es molestia.

    Saludos!! Diego

      Oscar Gallench · 21 noviembre, 2017 a las 07:49

      Buf…te cuento mi caso por si me puedes/quieres ayudar.
      Mi hermano me ha cedido una base de datos alojada en 1and1.com
      Lo que queremos conseguir es que yo pueda acceder mediante phpmyadmin sin usar el portal 1and1 y asi no usar sus credenciales.
      He seguido varios tutoriales, y mas o menos todos llegan al mismo sitio, pero en mi caso, no puedo entrar entrando en 127.0.0.1:3306/phpmyadmin, me aparece “Got packets out of order”, pero el caso es que en mi pc tengo tambien una base de datos montada con appache en red local que es donde hago las pruevas antes de subirlo al servidor online. Tambien acabo de provar de entrar con mysql worckbench configurando la conexion como tcp/ip over ssh pero parece que tampoco responde…sale un error que dice “lost connection to mysql server at ‘reading initial communication packet’, system error:0
      Podrias guiarme un poco?? Muchas gracias!

        Diego Cordoba - @d1cor · 22 noviembre, 2017 a las 04:21

        Oscar! Algunos datos a tener en cuenta:
        Si vas a usar mysqlworkbench, como bien decís, tiene la opción de conectarse via «tcp/ip over ssh»… si usás esa configuración, NO es necesario tunelizar la conexión mysql por ssh como describo en mi artículo, puesto que el workbench en este caso hace el mismo trabajo… deberías poder conectarte usando la ip/puerto/user/password del SSH remoto, y en la configuración del mysql apuntarle a 127.0.0.1:3306, debería salir andando solo.

        Por otro lado, si estás tunelizando como describo en mi artículo, y querés usar mysqlworkbench, deberías conectarte usando la conexión «standard tcp/ip», no la que va sobre SSH, ya que la parte del ssh ya la resolviste… ahí deberías poner el server 127.0.0.1:3306 como base de datos, con user/pass de acceso que tenés configurado en el mysql remoto.

        Finalmente, como te dije en el otro comentario, no vas a poder entrar al phpmyadmin usando 127.0.0.1:3306/phpmyadmin, el puerto 3306 es de protocolo mysql, NO web, por lo que el navegador no puede interpretarlo.
        Si tenés acceso web a la máquina del mysql, simplemente deberías entrar al phpmyadmin usando http://ip_del_server_mysql/phpmyadmin.

        Si NO tenés acceso web y solo tenés acceso ssh, deberías «traerte» el puerto 80 del server mysql a tu equipo local, un trabajo similar al que hago en el artícuo, pero utilizando el puerto 80 en vez del 3306… el artículo explica cómo «traerse» el puerto 3306 de mysql desde un server remoto a tu equipo local para conectarte localmente, pero el mecanismo es perfectamente válido para cualquier puerto.

        Así, si querés traerte el puerto 80 del server mysql al equipo local, podrés hacer algo similar a esto:

        ssh -L 11111:127.0.0.1:80 usuario_ssh@11.22.33.4

        Y luego conectar al phpmyadmin desde un browser usando http://127.0.0.1:11111/phpmyadmin

        Es «parecido» al que no te funcionó a vos, con la diferencia de que el puerto 11111 en este caso está enlazado al puerto 80 remoto, no al 3306.

        Espero te aclare un poco los tantos! Escribime cualquier duda!

Los comentarios están cerrados.