Hack de rsync para hacer rebotar archivos entre dos servidores desconectados

8

Aquí está la conexión:

[Server1] <---> [my desktop] <---> [Server2]

El servidor1 y el servidor2 no pueden hablar directamente entre sí (no preguntar). Mi escritorio, sin embargo, puede acceder a ambos servidores a través de ssh.

Necesito copiar archivos del servidor1 al servidor2.

Tradicionalmente, he estado usando un hack ssh + tar, como tal:

ssh -q root@Server1 'tar -vzc /path/to/files ' | ssh -q root@Server2 'tar -vzx -C /'

Y eso funciona muy bien, pero me gustaría ir un paso más allá y lograr que rsync funcione entre los dos servidores a través de mi escritorio.

Ahora sé que podría comenzar un túnel ssh port-forward en una terminal y luego rsync sobre ese túnel en otra ventana, pero no quiero preocuparme con una segunda terminal o hacer y romper un puerto reenvío de puerto separado. lo que quiero es:

  • Un comando de línea para rsync archivos del servidor1 al servidor2 a través de mi escritorio
  • todo en UNA línea de comando, una ventana de terminal
  • Quiero que el túnel de puerto hacia adelante solo exista durante la vida del comando rsync.
  • No quiero scp, quiero rsync.

¿Alguien tiene un truco para hacer eso?

EDITAR: ¡Aquí está el comando de trabajo! Buen trabajo para todos: 1. Para la ruta de clave rsa, no puedo usar tildae, tuve que usar "/ root /". 2. Aquí está la línea de comando final:

ssh -R 2200:SERVER2:22 root@SERVER1 "rsync -e 'ssh -p 2200 -i /root/.ssh/id_rsa_ROOT_ON_SERVER2' --stats --progress -vaz /path/to/big/files root@localhost:/destination/path"

Bum hace la dinamita.

regulatre
fuente
Esto es realmente excelente Lo único que debe cambiarse es deshabilitar la verificación de la clave del host. Tiene la clave SSH para la autenticación TTYless, pero como los servidores nunca se han comunicado entre sí, no pueden verificar las claves del host. Lo mejor es deshabilitarlo: -o StrictHostKeyChecking = no después de los indicadores -p o -i.
Amala

Respuestas:

5

Si está contento de conservar una copia de los datos en la máquina intermedia, simplemente puede escribir un script que actualice la copia local utilizando el servidor1 como referencia y luego actualice la copia de seguridad en el servidor2 utilizando la copia local como referencia:

#!/bin/sh
rsync user@server1:/path/to/stuff /path/to/loca/copy -a --delete --compress
rsync /path/to/loca/copy user@server2:/path/to/where/stuff/should/go -a --delete --compress

El uso de un script simple significa que ha deseado un solo comando para hacer todo. Por supuesto, esto podría ser un no-no de seguridad si los datos son confidenciales (usted u otras personas de su empresa, puede que no desee una copia flotando en su computadora portátil). Si el servidor1 es local para usted, puede eliminar la copia local después (ya que la próxima vez se reconstruirá rápidamente en la LAN local).

Construir un túnel para que los servidores puedan comunicarse efectivamente entre ellos de manera más directa debería ser posible así:

  1. En el servidor 2, haga una copia de / bin / sh como / usr / local / bin / shforkeepalive. Use un enlace simbólico en lugar de una copia, entonces no tiene que actualizarlo después de las actualizaciones de seguridad que parchean / bin / sh.
  2. En el servidor 2, cree una secuencia de comandos que no haga nada más que bucle en suspensión durante unos segundos y luego haga eco de una pequeña cantidad de texto, y haga que esto use la ahora "copia" de sh:

    #!/usr/local/bin/shforkeepalive
    while [ "1" != "0" ]; do
            echo Beep!
            sleep 5
    done
    

    ( echoprobablemente no sea necesario, ya que la sesión no estará inactiva durante el tiempo suficiente como para que se agote el tiempo de espera incluso si SSHd está configurado para ignorar los paquetes de mantenimiento del cliente ssh)

  3. Ahora puede escribir un script en su computadora portátil que inicie su túnel inverso en segundo plano, le dice al servidor1 que use rsync para realizar la operación de copia, luego mata el túnel inverso al eliminar el script de bucle (que cerrará la sesión SSH):

    #!/bin/sh
    ssh user@server2 -L2222:127.0.0.1:22 /usr/local/bin/keepalivesctipt &
    ssh user@server1 -R2222:127.0.0.1:2222 rsync /path/to/stuff [email protected]:/destination/path/to/update -a --delete --compress -e 'ssh -p 2222'
    ssh user@server2 killall shforkeepalive
    

La forma en que esto funciona:

  • Línea 1: marcador estándar "comando a utilizar para interpretar este script"
  • Línea 2: inicie una conexión SSH con túnel inverso y ejecute el script keepalive a través de él para mantenerlo abierto. Trailing & le dice a bash que ejecute esto en segundo plano para que las siguientes líneas puedan ejecutarse sin esperar a que termine
  • Línea 3: inicie un túnel que se conectará al túnel de arriba para que el servidor1 pueda ver el servidor2, y ejecute rsync para realizar la copia / actualización sobre este arreglo
  • Línea 4: elimine la secuencia de comandos keep-alive una vez que se complete la operación rsync (y así se devuelve la segunda llamada SSH), que lo hará y la primera sesión ssh.

Esto no se siente particularmente limpio, pero debería funcionar. No he probado lo anterior, por lo que es posible que deba modificarlo. Hacer que el comando rsync sea un script de una sola línea en el servidor1 puede ayudar al reducir la necesidad de escapar de caracteres como el 'en el comando ssh de llamada.

Por cierto: dices "no preguntes" por qué los dos servidores no pueden verse directamente, pero a menudo hay una buena razón para esto. Mi servidor doméstico y el servidor en el que se guardan las copias de seguridad en línea no pueden iniciar sesión entre sí (y tienen diferentes contraseñas + claves para todos los usuarios); esto significa que si uno de los dos es pirateado, no se puede usar como una ruta fácil para piratear el otro para que mis copias de seguridad en línea sean más seguras (alguien que borre maliciosamente mis datos de Live no puede usar su capacidad para actualizar las copias de seguridad para eliminar dichas copias de seguridad, ya que no tiene la capacidad directa de tocar el sitio de copia de seguridad principal). Ambos servidores pueden conectarse a un servidor intermedio en otro lugar: el servidor en vivo está configurado para enviar sus copias de seguridad (a través de rsync) a la máquina intermedia temprano en la mañana y el servidor de copia de seguridad está configurado (un poco más tarde para permitir que se complete el paso uno) para conectarse y recopile las actualizaciones (nuevamente a través de rsyc seguido de un paso de captura de imágenes para mantener varias edades de copia de seguridad). Esta técnica también puede ser útil en su caso, y si es así, la recomendaría como una forma mucho más limpia de hacer las cosas.

Editar: fusionando mi truco con Aaron's para evitar toda la intrusión con copias de / bin / sh y un script de keep-alive separado en server2, este script en su computadora portátil debería hacer todo el trabajo:

#!/bin/sh
ssh user@server2 -L2222:127.0.0.1:22 sleep 60 &
pid=$!
trap "kill $pid" EXIT 
ssh user@server1 -R2222:127.0.0.1:2222 rsync /path/to/stuff [email protected]:/destination/path/to/update -a --delete --compress -e 'ssh -p 2222'

Al igual que con lo anterior, rsync se conecta a localhost: 2222 que reenvía por el túnel al localhost de su computadora portátil: 2222 que reenvía a través del otro túnel al localhost del servidor2: 22.

Edición 2: si no le importa que el servidor1 tenga una clave que le permita autenticarse con el servidor2 directamente (aunque no pueda ver el servidor2 sin un túnel), puede simplificar aún más con:

#!/bin/sh
ssh user@server1 -R2222:123.123.123:22 rsync /path/to/stuff [email protected]:/destination/path/to/update -a --delete --compress -e 'ssh -p 2222'

donde 123.123.123.123 es una dirección pública para server2, que podría usarse como copiar + pegar una línea en lugar de un script.

David Spillett
fuente
Es una gran cantidad de datos (20 + gb) y prefiero transmitirlos al mismo tiempo en lugar de almacenarlos localmente. Deseo transmitir los datos a través de mi PC sin que se almacene nada. tienes razón sobre el "no preguntes", es por una buena razón, aunque sea una pita.
regular
Plesae ve nuevas ediciones en la pregunta original
regular el
Creo que mi última edición (publicada segundos antes de tu comentario de acuerdo con las marcas de tiempo, por lo que probablemente estábamos escribiendo al mismo tiempo) puede darte la frase que estás buscando.
David Spillett el
HOORAY !!! ¡Funciona! 1. para la clave rsa, no puedo usar tildae, tuve que usar "/ root /". 2. aquí está la línea de comando final:ssh -R 2200:SERVER2:22 root@SERVER1 "rsync -e 'ssh -p 2200 -i /root/.ssh/id_rsa_ROOT_ON_SERVER2' --stats --progress -vaz /path/to/big/files root@localhost:/destination/path"
regular el
Hola @David, gracias por este gran truco. Sin embargo, para que funcione, necesito la clave del servidor 2 en el servidor 1 usando ambas soluciones (en la primera y segunda edición). Creo que es normal (reenvío de puertos o no, el servidor1 todavía está intentando autenticarse en el servidor2), pero usted escribe If you don't mind server1 having a key .... ¿Puede decirme si es realmente posible evitar tener la clave del servidor2 en el servidor1 por favor?
ssssteffff
2

Aquí hay algunos métodos que hacen que la sincronización sea simple, pero requieren un trabajo de configuración.

  • Configure un túnel ssh inverso desde el servidor1 a su escritorio (lo siento, no puedo decirte el .ssh/configencantamiento de la parte superior de mi cabeza). Encadenarlo con una conexión desde su escritorio al servidor2. Ejecute rsync desde el servidor1.

  • Configure un proxy de calcetines (o un proxy http que acepte CONNECT) en su escritorio. Úselo para establecer una conexión ssh del servidor1 al servidor2. Ejecute rsync desde el servidor2.

  • Use unísono en lugar de rsync. Pero el flujo de trabajo es diferente.

  • Monte los directorios desde uno o ambos servidores en su escritorio usando sshfs .

Gilles 'SO- deja de ser malvado'
fuente
1

¿Por qué una línea? Use un pequeño script de shell:

#!/bin/bash
# Run me on server1

# Create the port forward server1 -> desktop -> server2 (i.e.
# the first forward creates a second tunnel running on the desktop)
ssh -L/-R ... desktop "ssh -L/-R ... server2 sleep 1h" &    
pid=$!

# Kill port forward process on exit and any error
trap "kill $pid" EXIT 

rsync -e ssh /path/to/files/ root@localhost:/path/to/files/on/server2

IIRC, puede configurar el tiempo de sueño más bajo; el primero sshno terminará mientras alguien use el canal.

Aaron Digulla
fuente
Estoy bastante seguro de que rsync no puede operar entre dos servidores remotos a través de SSH de esa manera (solo local-> remoto o remoto-> local), aunque su uso de sleepy trapes más limpio que el método "mantener vivo y matar" en mi respuesta .
David Spillett el
por favor vea ediciones en la pregunta original.
regular el
Maldición, tienes razón. No está permitido especificar dos hosts como argumentos en el comando ling. ... hmmm ..
Aaron Digulla
Bien, he mejorado mi solución. Debe crear dos puertos hacia adelante para que el servicio ssh del servidor2 sea visible en el servidor1.
Aaron Digulla
Agregue un par de ";" para convertirlo en una sola línea. La idea es más fácil de entender con un guión.
Aaron Digulla