Saltar al contenido
Páginas de la documentación

Documentación

Bastión

Llega a un escritorio de IsardVDI sin VPN — el bastión, isard ssh y cómo publicar un servicio en él.

Parte de CLI, Ssh.

Introducción

La VPN de Red llega a tu máquina, y llega bien.

Pero tiene una característica que descarta la mitad de lo que quieres hacer con un servidor: la otra persona también tiene que estar conectada.

¿Quieres enseñar tu aplicación web a un compañero? Necesita el túnel. ¿Quieres pasarle una URL a un profesor? Necesita el túnel. ¿Quieres que un servicio externo envíe un webhook a tu máquina? Has perdido antes de empezar, porque un webhook no puede instalar WireGuard.

El bastión es la otra puerta.

El propio servidor web de Isard — ese en el que inicias sesión, en internet, con un nombre real y un certificado real — reenviará las conexiones hasta tu escritorio.

No hay que instalar nada en el otro extremo. Ni túnel, ni configuración, ni cliente.

architecture-beta
     service bastion(internet)[Bastion]
     service server(server)[VM]

     bastion:R -- L:server

El precio es que no llegan todos los puertos, como ocurre con la VPN.

Hay tres expuestos, y son los tres que importan:

22/TCP SSH
80/TCP HTTP
443/TCP HTTPS

Esos son los puertos de dentro de tu escritorio, y solo son los valores por defecto: el formulario del bastión te deja cambiarlos, si tu servidor escucha en otro.

Desde fuera, todo llega al servidor de Isard. Más abajo verás que el SSH entra por el 443.

Cómo activarlo

El bastión va por escritorio y está desactivado por defecto.

Abre el formulario de edición del escritorio y busca la sección bastión:

Ahí haces dos cosas: lo activas y registras la clave pública con la que te vas a conectar.

Obtén la tuya como te enseñaba SSH:

> gc .\.ssh\id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFJgYeQKuRlSp6BOSaVriPqJ5IKakDpHLfP4csIN8Ft/ david@elite

Pégala, guarda, y obtendrás un UUID:

e6a0307a-f48f-46e2-9fed-87e34a2d4f61

Y aquí viene la pregunta obvia: ¿qué se supone que hay que hacer con eso?

El UUID es la dirección

El escritorio no tiene ningún nombre público, así que el bastión le da uno — y es el UUID.

Pulsa el botón del bastión en la vista Escritorios:

Te muestra el UUID junto con una URL para cada protocolo activado:

La forma es siempre la misma:

e6a0307a-f48f-46e2-9fed-87e34a2d4f61.bastion.elmeuescriptori.cat

Ese nombre se resuelve en internet, desde cualquier sitio, sin VPN.

http:// y https:// llegan a los puertos 80 y 443 del escritorio.

El SSH es la excepción, y merece la pena leerlo dos veces: va al servidor de Isard, puerto 443, y el UUID hace de nombre de usuario SSH.

No es un error de la interfaz. Hay un solo puerto abierto para los escritorios de toda una plataforma, así que lo que identifica tu máquina tiene que viajar dentro de la conexión y no en la dirección — y el campo del nombre de usuario es donde cabe.

isard ssh

Todo lo anterior es un solo comando:

$ isard ssh box-1
✓ Resolved desktop: box-1 (state: Stopped)
✓ Start request sent for box-1
✓ box-1 is now Started
✓ SSH bastion ready for box-1
Connecting: ssh -o StrictHostKeyChecking=no ... -p 443 -i /Users/david/.ssh/id_ed25519
isard@box-1:~$

No has escrito ningún UUID, no has abierto el formulario de edición, no has pegado ninguna clave.

Esto es lo que ha hecho, en orden:

  1. Ha resuelto el nombre — box-1, o una grafía lo bastante parecida.
  2. Ha encontrado tu clave privada — --identity si le has pasado una, luego ~/.ssh/id_ed25519 y luego ~/.ssh/id_rsa. Si no tienes ninguna, genera una ed25519 en lugar de fallar.
  3. Ha arrancado el escritorio si estaba detenido, y ha esperado.
  4. Ha registrado la clave pública correspondiente en el bastión del escritorio, lo que además lo activa. Hacerlo dos veces no hace daño — lo comprueba antes de escribir.
  5. Se ha conectado al servidor de Isard por el puerto 443, con el UUID del bastión como nombre de usuario.

El paso 2 es el que conviene saber: no te hace falta ninguna clave para empezar.

$ isard ssh box-1
✓ Resolved desktop: box-1 (state: Stopped)
No SSH key found — generating /Users/david/.ssh/id_ed25519...
Generating public/private ed25519 key pair.
...
Generated SSH key: /Users/david/.ssh/id_ed25519
✓ Start request sent for box-1
✓ box-1 is now Started
✓ SSH bastion ready for box-1
Connecting: ssh -o StrictHostKeyChecking=no ... -p 443 -i /Users/david/.ssh/id_ed25519
isard@box-1:~$

La máquina tiene que estar escuchando

El bastión reenvía una conexión al puerto 22 de tu máquina — o al puerto SSH que hayas puesto en el formulario.

Si no hay nada escuchando ahí, esto es lo que obtienes:

$ isard ssh box-1
✓ Resolved desktop: box-1 (state: Started)
✓ SSH bastion ready for box-1
Connecting: ssh -o StrictHostKeyChecking=no ... -p 443 -i /Users/david/.ssh/id_ed25519
Error connecting to target host: dial tcp 192.168.122.214:22: connect: connection refused
ssh exited 255 (auth/connection failed). Cached confirmation for 'box-1' cleared.
If ssh reported 'Connection refused', the desktop has no SSH server yet. Open it in the viewer (isard view box-1) and, in the guest:
...

Léelo con atención, porque es lo que falla con más frecuencia y parece un problema de permisos.

connection refused significa que el bastión ha llegado. Ha llegado a tu máquina y no ha encontrado a nadie en el puerto 22.

Una plantilla Server lleva un servidor SSH. Una plantilla Desktop normalmente no, y una máquina que has instalado tú solo lo lleva si marcaste la casilla durante la instalación.

En un escritorio Linux, desde el visor:

$ sudo apt install -y openssh-server
$ sudo systemctl enable ssh --now

Esa es la lección de SSH, y esta página no la repite.

Una máquina desnuda, en una línea

A un escritorio que has instalado tú le falta algo más que sshd.

No hay servidor SSH, puede que no haya ninguna cuenta que coincida con la que usa el bastión para entrar, y no hay agente SPICE — así que el portapapeles tampoco funciona, y eso es lo que duele, porque no puedes pegar el comando que lo arreglaría.

Por eso hay un comando lo bastante corto para escribirlo a mano. En el visor del propio escritorio:

$ curl -fsSL https://isard.xtec.dev/guest.sh | sudo sh -s isard mypassword
==> installing openssh-server
==> creating user 'isard'
==> installing spice-vdagent
==> done

Instala y activa el servidor SSH, crea la cuenta con sudo sin contraseña, e instala spice-vdagent y qemu-guest-agent.

Funciona tanto con apt como con dnf, y ejecutarlo dos veces es seguro — se salta lo que ya está.

En un escritorio Windows el mismo trabajo es una línea de PowerShell, en una ventana de administrador:

> iex (irm https://isard.xtec.dev/guest.ps1)

Eso instala el servidor OpenSSH, abre el puerto 22 en el cortafuegos, pone PowerShell como shell del SSH e instala las spice-guest-tools.

Reinicia después, porque el portapapeles no funciona hasta que reinicias:

> Restart-Computer

Las credenciales que te muestra una sola vez

La primera vez que haces isard ssh a un escritorio concreto, se detiene y te muestra algo:

$ isard ssh box-1
✓ Resolved desktop: box-1 (state: Stopped)
Guest credentials for 'box-1':
  user:     isard
  password: pi****us
Use these credentials? [Y/n]

La mitad de la contraseña, y una pregunta.

No es la clave con la que te conectas — es la cuenta con la que el bastión entra en la máquina, y se guarda en la ficha del propio escritorio en la plataforma.

Si no coincide con ninguna cuenta real dentro de la máquina, el bastión no se autentica en ningún sitio y obtienes un error sobre los métodos probados en lugar de una shell.

Responde Y y deja de preguntar. El identificador del escritorio va a ~/.config/isard/desktop-creds.json, que solo guarda identificadores y nada más — ninguna contraseña, solo el conjunto de máquinas que ya has confirmado.

Responde n y te pide otras nuevas, y las envía al escritorio:

$ isard ssh box-1 --user isard --password 'nova-contrasenya'
✓ Resolved desktop: box-1 (state: Started)
✓ Stop request sent for box-1
✓ box-1 is now Stopped
✓ Guest credentials updated for box-1
✓ Start request sent for box-1
✓ box-1 is now Started
✓ SSH bastion ready for box-1
Connecting: ssh -o StrictHostKeyChecking=no ... -p 443 -i /Users/david/.ssh/id_ed25519
isard@box-1:~$

Fíjate en el reinicio que hay en medio. Las credenciales de la máquina, igual que authorized_keys, se aplican al arrancar — así que cambiarlas cuesta una parada y un arranque, y isard ssh --password hace ambas cosas por ti en lugar de dejarte averiguar por qué no ha cambiado nada.

Publicar algo

Los puertos 80 y 443 son la razón por la que el bastión es más que un SSH cómodo.

Instala un servidor web:

$ isard ssh box-1 -- 'sudo apt update && sudo apt install -y nginx'

Escribe en él algo reconocible:

$ isard ssh box-1 -- 'echo "<h1>Hola des de box-1</h1>" | sudo tee /var/www/html/index.html'
<h1>Hola des de box-1</h1>

Y abre la URL HTTP del bastión en cualquier navegador, desde cualquier máquina, sin VPN:

http://e6a0307a-f48f-46e2-9fed-87e34a2d4f61.bastion.elmeuescriptori.cat/

Es una URL que puedes enviar a alguien.

EjercicioPublica una página

Sirve una página desde box-1 y ábrela desde un navegador que no esté en la VPN.

Mostrar la solución
$ isard ssh box-1 -- 'sudo apt update && sudo apt install -y nginx'
$ isard ssh box-1 -- 'echo "<h1>box-1</h1>" | sudo tee /var/www/html/index.html'
<h1>box-1</h1>

$ isard vpn down
Running: sudo /opt/homebrew/bin/wg-quick down /Users/david/.config/isard/isard-vpn.conf
...
VPN down.

Después, la URL HTTP del bastión, desde el botón del bastión de la plataforma.

Desactivar primero la VPN es la gracia del ejercicio. Con el túnel activo no puedes saber cuál de las dos rutas te ha respondido.

Ejecutar cosas sin una shell

Todos los ejemplos anteriores usan la forma de CLI:

$ isard ssh box-1 -- 'sudo apt install -y nginx'

El comando que va después de -- se ejecuta en la máquina y la sesión no es interactiva.

Eso es lo que convierte el bastión en un destino de compilación y no en un sitio que visitas.

Copia un proyecto y ejecuta sus pruebas:

$ tar czf - src tests | isard ssh box-1 -- 'tar xzf - -C /home/isard/work'
$ isard ssh box-1 -- 'cd work && uv run pytest -q'
........................                                        [100%]
24 passed in 1.83s

El código de salida es el de las pruebas, así que funciona como paso de un script:

$ isard ssh box-1 -- 'cd work && uv run pytest -q' && echo "green"

VPN o bastión

Los dos llegan a la máquina. No son intercambiables.

VPN bastión
puertos todos 22, 80, 443
la otra persona necesita el túnel y tu configuración un enlace
configuración por escritorio marcar una casilla al crearlo activarlo, registrar una clave
configuración en tu máquina isard vpn up, necesita sudo nada
sirve para trabajar en la máquina enseñar lo que funciona en ella

En la práctica usas los dos, y en ambos casos lo que escribes es isard ssh.

Ejercicios

EjercicioDesde cero

Crea una máquina Ubuntu Desktop nueva llamada bare y consigue una shell SSH en ella a través del bastión.

Mostrar la solución
$ isard create bare --template ubuntu-24-04-desktop --yes
...
✓ Desktop 'bare' created successfully!

$ isard start bare --wait
✓ Resolved desktop: bare (state: Stopped)
✓ bare → Starting
✓ bare is now Started

$ isard ssh bare
✓ Resolved desktop: bare (state: Started)
...
✓ SSH bastion ready for bare
...
Error connecting to target host: dial tcp 192.168.122.214:22: connect: connection refused
ssh exited 255 (auth/connection failed). Cached confirmation for 'bare' cleared.
If ssh reported 'Connection refused', the desktop has no SSH server yet. Open it in the viewer (isard view bare) and, in the guest:
...

Una plantilla Desktop no lleva servidor SSH, así que esa es la primera respuesta esperada.

Abre el visor e instala uno:

$ isard view bare

En la máquina:

$ sudo apt install -y openssh-server
$ sudo systemctl enable ssh --now

Después, desde tu propio terminal:

$ isard ssh bare
isard@bare:~$

Si en cambio obtienes Permission denied (publickey), la clave se registró cuando la máquina ya estaba en marcha. isard stop bare && isard start bare y vuelve a probar.

EjercicioLee los dos errores

Di qué significa cada uno de estos errores y qué lo soluciona:

  1. connect: connection refused
  2. Permission denied (publickey)
Mostrar la solución
  1. El bastión ha llegado a la máquina y no había nada escuchando en el puerto 22. Instala y activa un servidor SSH dentro de la máquina.

  2. El bastión ha llegado a sshd y tu clave aún no estaba en authorized_keys. Casi siempre es porque la clave se registró después de que la máquina arrancara — detenla y vuelve a arrancarla.

Merece la pena distinguirlos porque los dos parecen el SSH no funciona y ninguno se soluciona generando una clave nueva, que es lo que todo el mundo prueba primero.

EjercicioUn comando, tres máquinas

Con box-1, box-2 y box-3 en marcha, averigua la versión del kernel de cada una sin abrir ninguna shell.

Mostrar la solución
$ for n in 1 2 3; do
>   printf '%s: ' "box-$n"
>   isard ssh box-$n -- 'uname -r'
> done
box-1: 6.8.0-51-generic
box-2: 6.8.0-51-generic
box-3: 6.8.0-51-generic

El printf y la salida del comando quedan bien intercalados porque todo lo que isard dice sobre la búsqueda y el arranque va a stderr, no a stdout.

EjercicioQué ruta ha respondido

box-1 tiene una interfaz WireGuard y el bastión activado, y su servidor web responde por las dos.

¿Cómo demostrarías cuál ha usado una petición concreta?

Mostrar la solución

Quita una de las dos.

$ isard vpn down
Running: sudo /opt/homebrew/bin/wg-quick down /Users/david/.config/isard/isard-vpn.conf
...
VPN down.

$ curl -s -o /dev/null -w '%{http_code}\n' http://10.2.76.37
000

$ curl -s -o /dev/null -w '%{http_code}\n' \
    http://e6a0307a-f48f-46e2-9fed-87e34a2d4f61.bastion.elmeuescriptori.cat/
200

000 significa que curl ni siquiera ha podido conectarse, que es la respuesta correcta para una dirección privada de una red en la que ya no estás.

El hábito general vale más que el ejercicio: cuando hay dos cosas que podrían estar respondiendo, apaga una.