Comment utiliser rsync entre deux serveurs distants?
Vincent Bernat
scp -3
permet de copier des fichiers entre deux hôtes distants via
l’hôte local. Cela s’avère pratique lorsque les deux serveurs ne
peuvent pas communiquer directement ou s’ils sont incapables de
s’authentifier l’un auprès de l’autre1. Malheureusement, rsync
ne
supporte pas une telle fonctionnalité. Voici une astuce pour émuler le
comportement de scp -3
avec les tunnels SSH.
Lors de la synchronisation avec un hôte distant, rsync
s’y connecte
avec ssh
et lance un processus rsync --server
. Il interagit avec
lui par le biais de son entrée et sortie standard. L’idée est de
recréer le même dispositif en utilisant des tunnels SSH et socat,
un outil polyvalent pour établir des transferts de données
bidirectionnels.
La première étape consiste à se connecter au serveur source et à
demander à rsync
de fournir la ligne de commande utilisée pour
lancer le processus distant rsync --server
. L’option -e
remplace
la commande à utiliser pour obtenir un shell distant : au lieu de
ssh
, nous utilisons echo
.
$ ssh web04 $ rsync -e 'sh -c ">&2 echo $@" echo' -aLv /data/. web05:/data/. web05 rsync --server -vlogDtpre.iLsfxCIvu . /data/. rsync: connection unexpectedly closed (0 bytes received so far) [sender] rsync error: error in rsync protocol data stream (code 12) at io.c(228) [sender=3.2.3]
La deuxième étape consiste à se connecter au serveur de destination
avec une redirection de port local. Lors de la connexion au port
local 5000, la connexion TCP est redirigée par SSH vers le port
distant 5000. Elle est alors prise en charge par socat
. Lorsqu’il
reçoit la connexion, socat
lance la commande rsync --server
que
nous avons obtenue à l’étape précédente et connecte son entrée et sa
sortie standard à la chaussette TCP entrante.
$ ssh -L 127.0.0.1:5000:127.0.0.1:5000 web05 $ socat tcp-listen:5000,reuseaddr exec:"rsync --server -vlogDtpre.iLsfxCIvu . /data/."
La dernière étape consiste à se connecter à la source avec une
redirection de port distant. socat
est utilisé à la place d’une
connexion SSH normale et connecte son entrée et sa sortie standard à
une chaussette TCP connectée au port distant 5000. Grâce à la
redirection de port distant, SSH transmet les données au port
local 5000. De là, elles sont relayées vers la destination, comme
décrit à l’étape précédente.
$ ssh -R 127.0.0.1:5000:127.0.0.1:5000 web04 $ rsync -e 'sh -c "socat stdio tcp-connect:127.0.0.1:5000"' -aLv /data/. remote:/data/. sending incremental file list haproxy.debian.net/ haproxy.debian.net/dists/buster-backports-1.8/Contents-amd64.bz2 haproxy.debian.net/dists/buster-backports-1.8/Contents-i386.bz2 […] media.bernat.ch/videos/2021-frnog34-jerikan/progressive.mp4 sent 921,719,453 bytes received 26,939 bytes 7,229,383.47 bytes/sec total size is 7,526,872,300 speedup is 8.17
Ce petit schéma peut aider à comprendre comment tout s’imbrique :
La page de manuel de rsync dissuade d’utiliser
l’option --server
. Utilisez cette astuce à vos risques et périls !
Les options
--server
et--sender
sont utilisées en interne par rsync, et ne devraient jamais être tapées par un utilisateur dans des circonstances normales. Une certaine connaissance de ces options peut être nécessaire dans certains scénarios, comme lors de la configuration d’une connexion SSH qui ne peut exécuter qu’une commande rsync. Par exemple, le répertoire desupport/
de la distribution rsync contient un exemple de script nommérrsync
(pour rsync restreint) qui peut être utilisé avec une connexion SSH restreinte.
Addendum#
J’espérais obtenir quelque chose de similaire avec une simple ligne de commande. Mais cela ne fonctionne pas !
$ socat \ > exec:"ssh web04 rsync --server --sender -vlLogDtpre.iLsfxCIvu . /data/." \ > exec:"ssh web05 rsync --server -vlogDtpre.iLsfxCIvu /data/. /data/." \ over-long vstring received (511 > 255) over-long vstring received (511 > 255) rsync error: requested action not supported (code 4) at compat.c(387) [sender=3.2.3] rsync error: requested action not supported (code 4) at compat.c(387) [Receiver=3.2.3] socat[878291] E waitpid(): child 878292 exited with status 4 socat[878291] E waitpid(): child 878293 exited with status 4
-
Et le transfert de l’agent SSH est dangereux. Évitez de l’utiliser ! ↩︎