¿A quién no le ha pasado que debe acceder remotamente a un dispositivo Linux que está detrás de un firewall con NAT y la única opción posible es solicitar una VPN? ¿No sería ideal que exista algo así como un Teamviewer para CLI? Bueno, si existe, es gratis y se llama MySocket.io. En este ejemplo mostraré como configurar este servicio en una Raspberry Pi para acceder a la CLI desde cualquier lugar del mundo. Aunque no soy muy amigo de usar Raspberries en entornos de producción (ya que estos dispositivos tienden a fallar con una frecuencia increíble y si les entregamos responsabilidades de tareas críticas en un par de meses tendremos más problemas que soluciones), a veces hay que recurrir a las "raspis" ya que su pequeño tamaño es ideal para un sinfín de operaciones del día a día.
MySocket.io es un servicio que cuenta con su propia red CDN Anycast para facilitar el acceso desde todo el mundo a un dispositivo tipo Linux habilitando un puerto SSH en su red. Es muy simple y efectivo. Hay varias formas de instalar el cliente MySocket pero yo mostraré las 2 más comunes
1. Instalación del cliente
ALTERNATIVA 1: Descargar el cliente MySocket precompilado para ARM 64 bits directamente:
curl https://download.edge.mysocket.io/linux_arm64/mysocketctl -o mysocketctl
chmod +x ./mysocketctl
sudo mv ./mysocketctl /usr/local/bin/
mysocketctl -v
En mi caso, la Raspberry que estoy utilizando contiene un procesador ARMv7, que es de 32 bits, así que al momento de ejecutar el comando mysocketctl -v da un error de ejecución:
root@raspberrypi:/home/pi# mysocketctl -v
bash: /usr/local/bin/mysocketctl: cannot execute binary file: Exec format error
En este caso, la opción es descargar el código fuente y compilarlo localmente o bien usar el método Python:
ALTERNATIVA 2: Instalar mediante Python:
apt update
apt install python3-pip -y
pip3 install mysocketctl
2. Crear una cuenta en MySocket.io
mysocketctl account create \
--name "NOMBRE" \
--email "[email protected]" \
--password "MISUPERPASSWORD" \
--sshkey ~/.ssh/id_rsa.pub
Es posible que en este punto aparezca un error con el tipo de clave pública del servicio SSH local reclamando que no es de tipo RSA, ECDS o Ed25519
400 {"error": "Invalid SSH key: Key is not RSA, ECDSA or Ed25519"}
La solución al problema es generar nuevamente las claves SSH locales con el comando ssh-keygen -t rsa -C "[email protected]"). El correo debe ser el mismo que el anteriormente ingresado. Después repetir el paso anterior de creación de la cuenta. No es necesario ingresar una passphrase en el proceso.
root@raspberrypi:~# ssh-keygen -t rsa -C "[email protected]")
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:JqfUbBg68/gdbrgwddwsds4uYeAjj2CyNLZL5M4KhxZ1kcis [email protected]
The key's randomart image is:
+---[RSA 2048]----+
| |
| |
| . |
| . +. = |
| . *+o- S |
|+ E +* *
|*& .= o.. |
|#!O. *.o.. |
|=*ooo.ooo |
+----[SHA256]-----+
Luego de esto llegará un mail de confirmación para activar la cuenta y el siguiente paso es iniciar la sesión localmente en el servicio MySocket.
3. Login desde la CLI
mysocketctl login --email "[email protected]" --password "MISUPERPASSWORD"
Como uno a veces es un poco quisquilloso con dejar rastros de login en el historial de las CLIs, pueden usar el inicio interactivo simplemente con el comando
mysocketctl login
Email: [email protected]
Password:
Login successful
4. Crear un socket público
De acuerdo a la documentación de MySocket, un socket es una conexión que se abre en la red pública para que podamos acceder a nuestro servicio interno, el cual luego debe conectarse a un túnel para poder enlazar nuestro dispositivo contra ese socket y permitirnos el acceso desde fuera.
mysocketctl socket create --name "SERVICIO SSH" --type tcp
Y verificamos con
root@raspberrypi:~# mysocketctl socket ls
+--------------------------------------+--------------------------------------+---------+------+------------+----------+
| socket_id | dns_name | port(s) | type | cloud auth | name |
+--------------------------------------+--------------------------------------+---------+------+------------+----------+
| 5fce8f6e-b853-4e11-b240-f0364422978d | weathered-water-429.edge.mysocket.io | 26472 | tcp | False | SERVICIO SSH |
+--------------------------------------+--------------------------------------+---------+------+------------+----------+
Lo que hizo el servicio MySocket en este caso ha sido crear una redirección de sus puertos externos en el host weathered-water-429.edge.mysocket.io en el puerto 26482. Esto es algo así como un Port Forwarding de NAT .
5. Crear el túnel local
ya tenemos creado el socket público y ahora debemos crear un túnel que nos permitirá enlazar los servicios.
root@raspberrypi:~# mysocketctl tunnel create --socket_id 5fce8f6e-b853-4e11-b240-f0364422978d
+--------------------------------------+--------------------------------------+---------------+------------+
| socket_id | tunnel_id | tunnel_server | relay_port |
+--------------------------------------+--------------------------------------+---------------+------------+
| 5fce8f6e-b853-4e11-b240-f0364422978d | 73e89ffa-c397-4769-8bb8-deee0fc24abd | | 7756 |
+--------------------------------------+--------------------------------------+---------------+------------+```
6. Enlazar el socket con el túnel y conectarse a la red CDN
Finalmente, para poder acceder a nuestro servicio SSH en la Raspberry Pi desde Internet simplemente asociamos el socket_id, con el tunel_id y el puerto local 22:
root@raspberrypi:~# mysocketctl tunnel connect --socket_id 5fce8f6e-b853-4e11-b240-f0364422978d --tunnel_id 73e89ffa-c397-4769-8bb8-deee0fc24abd --port 22
Connecting to Server: ssh.mysocket.io
Welcome to Mysocket.io!
SERVICIO SSH - https://weathered-water-429.edge.mysocket.io
=======================================================
Logs
=======================================================
Ahora podemos conectarnos desde cualquier lugar del mundo a nuestra Raspberry:
[email protected]:~$ ssh [email protected] -p 26482
The authenticity of host '[weathered-water-429.edge.mysocket.io]:26482 ([75.2.104.207]:26482)' can't be established.
ECDSA key fingerprint is SHA256:h9ogh8RcrtjTm8lqKrL6YRLxB5q1UGb49xwyJ9JbPDk.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[weathered-water-429.edge.mysocket.io]:26482,[75.2.104.207]:26482' (ECDSA) to the list of known hosts.
[email protected]'s password:
Linux raspberrypi 5.4.83-v7l+ #1379 SMP Mon Dec 14 13:11:54 GMT 2020 armv7l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Feb 22 13:02:47 2021 from 192.168.1.98
Wi-Fi is currently blocked by rfkill.
Use raspi-config to set the country before use.
pi@raspberrypi:~
Más detalles en la documentación del proyecto: https://mysocket.readthedocs.io/en/latest/mysocketctl/mysocket.html
Happy tunneling!