Reenviar el puerto local o el archivo de socket al archivo de socket remoto

24

Pregunta rápida: ejecuto dos cajas de Linux, una en mi propio escritorio y otra en mi VPS. Por razones de seguridad en el extremo de VPS, opté por conexiones de socket a MySQL ( /var/run/mysqld/mysql.sock). Sé que puedo hacer un túnel de esta manera: ssh -L 3307:127.0.0.1:3306 [email protected]si configuro el servidor SQL remoto para escuchar en algún puerto, pero lo que quiero saber es ¿puedo hacer algo como: ssh -L /path/to/myremotesqlserver.sock:/var/run/mysqld/mysql.socktunelizar dos sockets, en lugar de dos puertos?

Una solución perfectamente aceptable también sería reenviar un puerto local al archivo de socket remoto, pero donde sea posible, estoy tratando de no tener servidores tcp ejecutándose en la caja remota.

(y sí, sé que tcp sería más fácil).


fuente
Si la razón por la que no desea utilizar TCP en el cuadro mySQL es por problemas de seguridad (es decir, ataques remotos, etc.), por supuesto, puede usar el firewall, y si eso no es lo suficientemente bueno, haga que mySQL solo escuche 127.0.0.1 para sus conexiones TCP, entonces puede hacer un túnel a través de SSH fácilmente. Si no, apoyo la solución socat a continuación.
Mattias Ahnberg
lwn.net/Articles/609321 OpenSSH 6.7 traerá reenvío de socket
Hubbitus
@Hubbitus, ¿está disponible esta función ahora? De ser así, ¿puede proporcionar una respuesta de ejemplo?
CMCDragonkai
Ese comentario estaba en forma de respuesta, pero alguien lo convirtió en comentario. Y ahora veo que ya sugieres una respuesta a continuación.
Hubbitus

Respuestas:

35

Reenviar un socket local a pedido

  • Configurar la autenticación de clave pública SSH
  • Instalar socaten ambos extremos
  • cree un directorio local para sus sockets, inaccesible para otros usuarios.
export SOCKET_DIR=~/.remote-sockets
mkdir -p $SOCKET_DIR
socat "UNIX-LISTEN:$SOCKET_DIR/mysqld.sock,reuseaddr,fork" \
EXEC:'ssh user@server socat STDIO UNIX-CONNECT\:/var/run/mysqld/mysqld.sock'

luego

mysql -S $SOCKET_DIR/mysqld.sock -u mysqluser -p

robado de reenviar sockets de dominio unix con ssh y socat

ijk
fuente
Esto es increíble y debería ser la respuesta aceptada.
John Smith Opcional
32

Aunque en el momento, cuando se hizo la pregunta, era realmente imposible, pero es posible hoy en día.

Puede tanto para: UNIX => TCP y UNIX => reenvío de UNIX.

Por ejemplo:

ssh \
  -R/var/run/mysql.sock:/var/run/mysql.sock \
  -R127.0.0.1:3306:/var/run/mysql.sock \
  somehost

Es posible desde OpenSSH 6.7.

Igor Chubin
fuente
1
Me las arreglé para reenviar mi local socket a socket del servidor remoto a través de arriba y cliente de ejecución ventana acoplable de forma remota (que podría hacerse mediante ssh directamente, pero ¿dónde está la diversión en eso :)ssh -L /home/user/docker.sock:/var/run/docker.sock dockerhost -N
sdkks
11

No he hecho esto, pero lo intentaría con Socat . tal vez algo como:

ssh [email protected] -L 9999:localhost:9999 "socat TCP-LISTEN:localhost:9999 UNIX-CONNECT:/var/run/mysqld/mysql.sock"
socat UNIX-LISTEN:/path/to/local/socket TCP:localhost:9999

De nuevo, nunca he hecho algo así.

Javier
fuente
Lo intentaré y te diré cómo va. He estado usando la implementación basada en tcp.
No puedo hacer que funcione en este momento, pero de todos modos por la idea de +1, me gusta. Te avisaré si lo soluciono.
+1 parece una utilidad útil.
Warner
5

No se necesita más socat desde ssh 6.7. Puede reenviar sockets de dominio Unix directamente como:

ssh -nNT -L $(pwd)/docker.sock:/var/run/docker.sock user@someremote

Más información: https://medium.com/@dperny/forwarding-the-docker-socket-over-ssh-e6567cfab160

CMCDragonkai
fuente
También encontré esto útil para conectarse a un socket local como un usuario diferente. Esto me permite ejecutar programas de cliente contra un proceso de servidor que desconecta ciertas ID de usuario (conexiones que provienen de sus propios corredores de trabajo).
Warbo
¿Reenviar un socket a la misma máquina, pero un directorio diferente controlado por un usuario diferente, usando sshd para autenticar el acceso? ¿Cuál es tu caso de uso?
CMCDragonkai
Los permisos / acceso al directorio no son un problema. Por el contrario, un demonio en particular descarta cualquier intento de conexión realizado por los usuarios de un determinado grupo (supuestamente para evitar que los novatos se confundan). El uso de ssh permite que esos usuarios se conecten (a través del socket tunelizado) como si fueran un usuario que no está en ese grupo y, por lo tanto, no se desconecten.
Warbo
Interesante, divertido cómo te refieres al nix-daemon, también estoy lidiando con problemas al respecto. Me pregunto por qué nix-daemon está dejando caer las conexiones a los usuarios de un determinado grupo ¿Es esto una cuestión de configuración de seguridad? ¿O relacionado con: nixos.org/nix/manual/#idm140737318362784 ?
CMCDragonkai
Según el mensaje de confirmación , es para evitar el uso "accidental". Lo traje aquí
Warbo
2

Otra modificación de la respuesta de @mpontes '/ @ javier que

ssh user@remoteserver -L 9999:localhost:9999 'socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock& pid=$!; trap "kill $pid" 0; while echo -ne " \b"; do sleep 5; done'

Limpiador

ssh user@remoteserver -L 9999:localhost:9999 '
  socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock&
  pid=$!
  trap "kill $pid" 0
  while echo -ne " \b"; do
    sleep 5
  done
'

PROS

  1. Funciona en openssh anterior a 6.7 (como CentOS 7)
  2. Mata socat en la terminación ssh en lugar de tener que volver a ssh en el servidor remoto
  3. Permite el inicio de sesión ssh no público (a diferencia de la solución ijk)

Característica

  1. Como -fno se usa la opción, puede usar una clave pública y ejecutarla en segundo plano a través de &o puede iniciar sesión de forma interactiva y usar Ctrl + Z y usar la misma $!para almacenar el pid.

CONTRAS

  1. No se puede usar fácilmente la -fopción ssh, ya que perderá el pid de ssh de esa manera. Este método se basa en ejecutarse en primer plano y Ctrl + C para matar.
  2. Mucho más complicado

Explicación

  • socat ...& - ejecutar socat en segundo plano en el servidor remoto
  • pid=$! - almacenar el pid
  • trap kill\ $pid 0- ejecutar kill $piden terminación bash
  • while :; sleep... - sentarse en un bucle infinito
  • echo -ne \ \b- Espacio de eco seguido de retroceso. Esto falla tan pronto como se desconecta el ssh. Con un sleep 5, esto significa que socatpuede ejecutarse hasta 5 segundos después de ssh

Nota: En realidad probado usando cargador de muelle, puerto 2375, /var/run/docker.socky la variable de entorno DOCKER_HOST='tcp://localhost:2375', pero debería funcionar para todos el mismo MySQL

Actualizar

Usando los controles SSH , puede usar la -fbandera a mi manera, solo agregue las siguientes banderas

-f -o ControlPath=~/.ssh/%C -o ControlMaster=auto

Y obtendrás

ssh -f -o ControlPath=~/.ssh/%C -o ControlMaster=auto user@remoteserver -L 9999:localhost:9999 'set -m; socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock& pid=$!; trap "kill $pid" 0; while echo -ne " \b"; do sleep 5; done'

Ahora puede terminar todas las sesiones controladas usando

ssh -o ControlPath=~/.ssh/%C -O exit remoteserver

Las -oopciones se pueden guardar en su .ssh/configarchivo, o puede usar -S en su lugar (pero aún lo necesitará -o ControlMaster)

Andy
fuente
Estoy usando scripts dentro de un contenedor Docker para implementar código en otros hosts. Su lógica de conexión es sorprendente, pero termina cuando finaliza la sesión de bash. Esto evita que llame docker run ... connect.shpara configurar el túnel seguido de docker run ... deploy.sh. Lo intenté nohup, &y disownparece que se rompen socatal cerrar stdouty activar el kill. ¿Alguna idea de ajustes para respaldar este caso (es decir, todavía está cerca cuando SSH lo hace pero sobrevive a un rechazo)?
Claytond
OKAY. Esto realmente funciona bien (w / -fy & disown) en una terminal. Aparentemente, el problema es creado por el script "wrapper". Agradecería la entrada, pero ahora estoy mirando preguntas y respuestas más apropiadas.
claytond
@claytond No estoy seguro exactamente de lo que está haciendo, pero sí, todos los demás comandos se terminan cuando finaliza el pid 1 de un contenedor. Lo que normalmente haría en su escenario de despliegue de script es usar el comando "deploy" y escribir un punto de entrada para mi contenedor imagen que dirá "if $ 1 (the command) == deploay then" ejecuta los comandos ssh, y los comandos de despliegue, y luego finaliza, lo que cerrará la conexión ssh. También puedes docker run ... connect.sh, y docker exec {container name/id} deploy.sh, para que jueguen juntos.
Andy
Tienes razón. De hecho, estoy usando execun runcontenedor que ya estaba y la tubería SSH no persistía después de execfinalizar. Aclaré que se debía a una peculiaridad con la forma en que se ejecutan los scripts. Si moví la llamada a su propio script y llamé nohup <script.sh> & disown, sobrevivirá a la finalización de exec.
claytond
1

Desarrollando la respuesta de Javier, esto funciona para mí:

ssh -f [email protected] -L 9999:localhost:9999 "socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock"

Necesita forkpoder conectarse varias veces sin morir socat una vez que cierra la primera conexión. Además, la forma en que socat le permite especificar una dirección a la que vincularse es a través de la bindopción, no como una dirección antes del puerto.

Después de esto, simplemente conéctese localhost:9999normalmente como lo haría. Luego para derribar el túnel:

ssh -f [email protected] "killall socat"

(o algo similar, puede hacer cosas más elaboradas que implican mantener el PID de socat)

mpontes
fuente
1

Sí, puedes usar socat.

Primero haga el túnel TCP con SSH. Luego usa socat así:

socat unix-listen: /var/run/mysqld/mysqld.sock,fork,unlink-early tcp: 127.0.0.1: 3306

Luego otorgue permisos al nuevo socket creado (chmod 777 puede ser)

usuario190133
fuente
Esto es posible desde OpenSSH 6.6.
ysdx
3
chmod 777: ¡no no no no no! Nunca corras chmod 777. ¡Prácticamente nunca se requiere! Ni siquiera para "fines de prueba". Si el archivo es legible, entonces es legible. Si es escribible por usero groupque necesita escribir, entonces es escribible. No hay absolutamente ninguna necesidad de dar a todos permisos de escritura, y olvidarlo de chmodnuevo a algo cuerdo es exactamente cómo las multinacionales son pirateadas. Solo no lo hagas. Siempre. Escribí una introducción a los permisos de Unix . ¡Por favor leelo!
Martin Tournoij