Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Do I have the horrible hack for you!

It is possible to do pull backups with borg, with some gruesome ssh hackery.

On the backup client side, you need to have a /root/.authorized_keys line like this (edit borg options to suit):

  command="BORG_PASSPHRASE=$(cat /root/.borg-passphrase) borg create --rsh 'ssh -o \"ProxyCommand socat - UNIX-CLIENT:/root/.socket/borg-socket\" ' --compression auto,zstd -s -x ssh://borg-backup@localhost/<repo location>::<backup name> <backup dirs>" ssh-ed25519 <keydata> <keyname>
Then, on your borg server, you need an authorized_keys file like this:

  command="borg serve --append-only --restrict-to-repo <repo location>",restrict ssh-ed25519 <keydata> <keyname>
Finally, run a small shell script like this from the borg server to trigger a pull backup:

  #!/bin/bash
  eval $(ssh-agent) > /dev/null
  ssh-add -q /home/borg-backup/.ssh/<keyname>
  ssh -A -R /root/.socket/borg-socket:localhost:22 -i .ssh/<keyname> root@borg-client
  ssh-agent -k
I trigger this using cron every night, but systemd timers will work too.

The first neat thing about this setup is that the client never even sees the private key that it uses to authenticate to the borg server - the key stays on the server & authentication is tunnelled between client & server via ssh-agent. You don't even need to be able to make a tcp connection from the client to the server - so long as the borg server can make an outgoing tcp connection to the client then everything just works. The client connects back to the server via a socat connection through a unix socket created by the outgoing ssh connection that tunnels any tcp connection made through it back to the sshd on the server. (You could probably tunnel the repo passphrase through as well, if you really wanted to.)

The second neat thing is the use of authorized_keys commands which are tied to an ssh keypair means that you're giving the minimal possible access - each ssh connection can only trigger that specific command & no other. You can issue ssh keys on a per-host basis & revoke them individually if necessary.

You have to use socat as a proxy program for the return ssh connection as ssh doesn't know how to connect to a unix socket & this setup requires

  config
    StreamLocalBindUnlink yes
in the .ssh/config on the client (possibly both client + server?), as otherwise the unix socket doesn't get cleaned up after the connection ends & the whole thing only works once before you have to remove the socket by hand. I'm not sure why this isn't the default for ssh to be honest.

This method is outlined in the ssh-agent section of https://borgbackup.readthedocs.io/en/stable/deployment/pull-... but the docs don't really call it out as a method of getting pull backups working properly. It's a bit convoluted, but it does work!

(If your client can make a direct tcp connection to the server you can skip the whole song + dance with the unix sockets of course.)



Wow, I only just saw this now but ... my mind is boggled. I don't know if I'd trust this for general use, but it's super cool. Thanks for sharing!


If you strip out the unix socket stuff (which I need for oddball network config reasons...) it’s just standard ssh authorised keys configs & ssh-agent working exactly as designed. It’s quite elegant really!

It’s the unix socket dance that introduces the gruesome hackery (imo at least!).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: