File: pull-backup.rst

package info (click to toggle)
borgbackup2 2.0.0b20-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 16,852 kB
  • sloc: python: 33,830; pascal: 3,599; sh: 215; makefile: 156; tcl: 94; ansic: 21
file content (502 lines) | stat: -rw-r--r-- 20,613 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
.. include:: ../global.rst.inc
.. highlight:: none
.. _pull_backup:

=======================
Backing up in pull mode
=======================

Typically the Borg client connects to a backup server using SSH as a transport
when initiating a backup. This is referred to as push mode.

However, if you require the backup server to initiate the connection, or prefer
it to initiate the backup run, one of the following workarounds is required to
allow such a pull-mode setup.

A common use case for pull mode is to back up a remote server to a local personal
computer.

SSHFS
=====

Assume you have a pull backup system set up with Borg, where a backup server
pulls data from the target via SSHFS. In this mode, the backup client's filesystem
is mounted remotely on the backup server. Pull mode is even possible if
the SSH connection must be established by the client via a remote tunnel. Other
network file systems like NFS or SMB could be used as well, but SSHFS is very
simple to set up and probably the most secure one.

There are some restrictions caused by SSHFS. For example, unless you define UID
and GID mappings when mounting via ``sshfs``, owners and groups of the mounted
filesystem will probably change, and you may not have access to those files if
Borg is not run with root privileges.

SSHFS is a FUSE filesystem and uses the SFTP protocol, so there may also be
unsupported features that the actual implementations of SSHFS, libfuse, and
SFTP on the backup server do not support, like filename encodings, ACLs, xattrs,
or flags. Therefore, there is no guarantee that you can restore a system
completely in every aspect from such a backup.

.. warning::

    To mount the client's root filesystem you will need root access to the
    client. This contradicts the usual threat model of Borg, where
    clients do not need to trust the backup server (data is encrypted). In pull
    mode the server (when logged in as root) could cause unlimited damage to the
    client. Therefore, pull mode should be used only with servers you fully
    trust!

.. warning::

    Additionally, while chrooted into the client's root filesystem,
    code from the client will be executed. Therefore, you should do this only when
    you fully trust the client.

.. warning::

    The chroot method was chosen to get the right user and group name-id
    mappings, assuming they only come from files (/etc/passwd and group).
    This assumption might be wrong, e.g. if users/groups also come from
    ldap or other providers.
    Thus, it might be better to use ``--numeric-ids`` and not archive any
    user or group names (but just the numeric IDs) and not use chroot.

Creating a backup
-----------------

Generally, in a pull backup situation there is no direct way for borg to know
the client's original UID:GID name mapping of files, because Borg would use
``/etc/passwd`` and ``/etc/group`` of the backup server to map the names. To
derive the right names, Borg needs to have access to the client's passwd and
group files and use them in the backup process.

The solution to this problem is chrooting into an sshfs mounted directory. In
this example the whole client root file system is mounted. We use the
stand-alone BorgBackup executable and copy it into the mounted file system to
make Borg available after entering chroot; this can be skipped if Borg is
already installed on the client.

::

    # Mount client root file system.
    mkdir /tmp/sshfs
    sshfs root@host:/ /tmp/sshfs
    # Mount BorgBackup repository inside it.
    mkdir /tmp/sshfs/borgrepo
    mount --bind /path/to/repo /tmp/sshfs/borgrepo
    # Make borg executable available.
    cp /usr/local/bin/borg /tmp/sshfs/usr/local/bin/borg
    # Mount important system directories and enter chroot.
    cd /tmp/sshfs
    for i in dev proc sys; do mount --bind /$i $i; done
    chroot /tmp/sshfs

Now we are on the backup system but inside a chroot with the client's root file
system. We have a copy of Borg binary in ``/usr/local/bin`` and the repository
in ``/borgrepo``. Borg will back up the client's user/group names, and we can
create the backup, retaining the original paths, excluding the repository:

::

    borg create --exclude borgrepo --files-cache ctime,size --repo /borgrepo archive  /

For the sake of simplicity only ``borgrepo`` is excluded here. You may want to
set up an exclude file with additional files and folders to be excluded. Also
note that we have to modify Borg's file change detection behaviour – SSHFS
cannot guarantee stable inode numbers, so we have to supply the
``--files-cache`` option.

Finally, we need to exit chroot, unmount all the stuff and clean up:

::

    exit # exit chroot
    rm /tmp/sshfs/usr/local/bin/borg
    cd /tmp/sshfs
    for i in dev proc sys borgrepo; do umount ./$i; done
    rmdir borgrepo
    cd ~
    umount /tmp/sshfs
    rmdir /tmp/sshfs

Thanks to secuser on IRC for this how-to!

Restore methods
---------------

The counterpart of a pull backup is a push restore. Depending on the type of
restore – full restore or partial restore – there are different methods to make
sure the correct IDs are restored.

Partial restore
~~~~~~~~~~~~~~~

In case of a partial restore, using the archived UIDs/GIDs might lead to wrong
results if the name-to-ID mapping on the target system has changed compared to
backup time (might be the case e.g. for a fresh OS install).

The workaround again is chrooting into an sshfs mounted directory, so Borg is
able to map the user/group names of the backup files to the actual IDs on the
client. This example is similar to the backup above – only the Borg command is
different:

::

    # Mount client root file system.
    mkdir /tmp/sshfs
    sshfs root@host:/ /tmp/sshfs
    # Mount BorgBackup repository inside it.
    mkdir /tmp/sshfs/borgrepo
    mount --bind /path/to/repo /tmp/sshfs/borgrepo
    # Make borg executable available.
    cp /usr/local/bin/borg /tmp/sshfs/usr/local/bin/borg
    # Mount important system directories and enter chroot.
    cd /tmp/sshfs
    for i in dev proc sys; do mount --bind /$i $i; done
    chroot /tmp/sshfs

Now we can run

::

    borg extract --repo /borgrepo archive PATH

to restore whatever we like partially. Finally, do the clean-up:

::

    exit # exit chroot
    rm /tmp/sshfs/usr/local/bin/borg
    cd /tmp/sshfs
    for i in dev proc sys borgrepo; do umount ./$i; done
    rmdir borgrepo
    cd ~
    umount /tmp/sshfs
    rmdir /tmp/sshfs

Full restore
~~~~~~~~~~~~

When doing a full restore, we restore all files (including the ones containing
the ID-to-name mapping, ``/etc/passwd`` and ``/etc/group``). Everything will be
consistent automatically if we restore the numeric IDs stored in the archive. So
there is no need for a chroot environment; we just mount the client file system
and extract a backup, utilizing the ``--numeric-ids`` option:

::

    sshfs root@host:/ /mnt/sshfs
    cd /mnt/sshfs
    borg extract --numeric-ids --repo /path/to/repo archive
    cd ~
    umount /mnt/sshfs

Simple (lossy) full restore
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Using ``borg export-tar`` it is possible to stream a backup to the client and
directly extract it without the need of mounting with SSHFS:

::

    borg export-tar --repo /path/to/repo archive - | ssh root@host 'tar -C / -x'

Note that in this scenario the tar format is the limiting factor – it cannot
restore all the advanced features that BorgBackup supports. See
:ref:`borg_export-tar` for limitations.

socat
=====

In this setup a SSH connection from the backup server to the client is
established that uses SSH reverse port forwarding to tunnel data
transparently between UNIX domain sockets on the client and server and the socat
tool to connect these with the borg client and server processes, respectively.

The program socat has to be available on the backup server and on the client
to be backed up.

When **pushing** a backup the borg client (holding the data to be backed up)
connects to the backup server via ssh, starts ``borg serve`` on the backup
server and communicates via standard input and output (transported via SSH)
with the process on the backup server.

With the help of socat this process can be reversed. The backup server will
create a connection to the client (holding the data to be backed up) and will
**pull** the data.

In the following example *borg-server* connects to *borg-client* to pull a backup.

To provide a secure setup sockets should be stored in ``/run/borg``, only
accessible to the users that run the backup process. So on both systems,
*borg-server* and *borg-client* the folder ``/run/borg`` has to be created::

   sudo mkdir -m 0700 /run/borg

On *borg-server* the socket file is opened by the user running the ``borg
serve`` process writing to the repository
so the user has to have read and write permissions on ``/run/borg``::

   borg-server:~$ sudo chown borgs /run/borg

On *borg-client* the socket file is created by ssh, so the user used to connect
to *borg-client* has to have read and write permissions on ``/run/borg``::

   borg-client:~$ sudo chown borgc /run/borg

On *borg-server*, we have to start the command ``borg serve`` and make its
standard input and output available to a unix socket::

   borg-server:~$ socat UNIX-LISTEN:/run/borg/reponame.sock,fork EXEC:"borg serve --restrict-to-path /path/to/repo"

Socat will wait until a connection is opened. Then socat will execute the
command given, redirecting Standard Input and Output to the unix socket. The
optional arguments for ``borg serve`` are not necessary but a sane default.

.. note::
   When used in production you may also use systemd socket-based activation
   instead of socat on the server side. You would wrap the ``borg serve`` command
   in a `service unit`_ and configure a matching `socket unit`_
   to start the service whenever a client connects to the socket.

   .. _service unit: https://www.freedesktop.org/software/systemd/man/systemd.service.html
   .. _socket unit: https://www.freedesktop.org/software/systemd/man/systemd.socket.html

Now we need a way to access the unix socket on *borg-client* (holding the
data to be backed up), as we created the unix socket on *borg-server*
Opening a SSH connection from the *borg-server* to the *borg-client* with reverse port
forwarding can do this for us::

   borg-server:~$ ssh -R /run/borg/reponame.sock:/run/borg/reponame.sock borgc@borg-client

.. note::

   As the default value of OpenSSH for ``StreamLocalBindUnlink`` is ``no``, the
   socket file created by sshd is not removed. Trying to connect a second time,
   will print a short warning, and the forwarding does **not** take place::

      Warning: remote port forwarding failed for listen path /run/borg/reponame.sock

   When you are done, you have to remove the socket file manually, otherwise
   you may see an error like this when trying to execute borg commands::

      Remote: YYYY/MM/DD HH:MM:SS socat[XXX] E connect(5, AF=1 "/run/borg/reponame.sock", 13): Connection refused
      Connection closed by remote host. Is borg working on the server?


When a process opens the socket on *borg-client*, SSH will forward all
data to the socket on *borg-server*.

The next step is to tell borg on *borg-client* to use the unix socket to communicate with the
``borg serve`` command on *borg-server* via the socat socket instead of SSH::

   borg-client:~$ export BORG_RSH="sh -c 'exec socat STDIO UNIX-CONNECT:/run/borg/reponame.sock'"

The default value for ``BORG_RSH`` is ``ssh``. By default Borg uses SSH to create
the connection to the backup server. Therefore Borg parses the repo URL
and adds the server name (and other arguments) to the SSH command. Those
arguments can not be handled by socat. We wrap the command with ``sh`` to
ignore all arguments intended for the SSH command.

All Borg commands can now be executed on *borg-client*. For example to create a
backup execute the ``borg create`` command::

   borg-client:~$ borg create --repo ssh://borg-server/path/to/repo archive /path_to_backup

When automating backup creation, the
interactive ssh session may seem inappropriate. An alternative way of creating
a backup may be the following command::

   borg-server:~$ ssh \
      -R /run/borg/reponame.sock:/run/borg/reponame.sock \
      borgc@borg-client \
      borg create \
      --rsh "sh -c 'exec socat STDIO UNIX-CONNECT:/run/borg/reponame.sock'" \
      --repo ssh://borg-server/path/to/repo archive /path_to_backup \
      ';' rm /run/borg/reponame.sock

This command also automatically removes the socket file after the ``borg
create`` command is done.

ssh-agent
=========

In this scenario *borg-server* initiates an SSH connection to *borg-client* and forwards the authentication
agent connection.

After that, it works similar to the push mode:
*borg-client* initiates another SSH connection back to *borg-server* using the forwarded authentication agent
connection to authenticate itself, starts ``borg serve`` and communicates with it.

Using this method requires ssh access of user *borgs* to *borgc@borg-client*, where:

* *borgs* is the user on the server side with read/write access to local borg repository.
* *borgc* is the user on the client side with read access to files meant to be backed up.

Applying this method for automated backup operations
----------------------------------------------------

Assume that the borg-client host is untrusted.
Therefore we do some effort to prevent a hostile user on the borg-client side to do something harmful.
In case of a fully trusted borg-client the method could be simplified.

Preparing the server side
~~~~~~~~~~~~~~~~~~~~~~~~~

Do this once for each client on *borg-server* to allow *borgs* to connect itself on *borg-server* using a
dedicated ssh key:

::

  borgs@borg-server$ install -m 700 -d ~/.ssh/
  borgs@borg-server$ ssh-keygen -N '' -t rsa  -f ~/.ssh/borg-client_key
  borgs@borg-server$ { echo -n 'command="borg serve --restrict-to-repo ~/repo",restrict '; cat ~/.ssh/borg-client_key.pub; } >> ~/.ssh/authorized_keys
  borgs@borg-server$ chmod 600 ~/.ssh/authorized_keys

``install -m 700 -d ~/.ssh/``

  Create directory ~/.ssh with correct permissions if it does not exist yet.

``ssh-keygen -N '' -t rsa  -f ~/.ssh/borg-client_key``

  Create an ssh key dedicated to communication with borg-client.

.. note::
  Another more complex approach is using a unique ssh key for each pull operation.
  This is more secure as it guarantees that the key will not be used for other purposes.

``{ echo -n 'command="borg serve --restrict-to-repo ~/repo",restrict '; cat ~/.ssh/borg-client_key.pub; } >> ~/.ssh/authorized_keys``

  Add borg-client's ssh public key to ~/.ssh/authorized_keys with forced command and restricted mode.
  The borg client is restricted to use one repo at the specified path.

``chmod 600 ~/.ssh/authorized_keys``

  Fix permissions of ~/.ssh/authorized_keys.

Pull operation
~~~~~~~~~~~~~~

Initiating borg command execution from *borg-server* (e.g. init)::

  borgs@borg-server$ (
    eval $(ssh-agent) > /dev/null
    ssh-add -q ~/.ssh/borg-client_key
    echo 'your secure borg key passphrase' | \
      ssh -A -o StrictHostKeyChecking=no borgc@borg-client "BORG_PASSPHRASE=\$(cat) borg --rsh 'ssh -o StrictHostKeyChecking=no' init --encryption repokey ssh://borgs@borg-server/~/repo"
    kill "${SSH_AGENT_PID}"
  )

Parentheses around commands are needed to avoid interference with a possibly already running ssh-agent.
Parentheses are not needed when using a dedicated bash process.

``eval $(ssh-agent) > /dev/null``

  Run the SSH agent in the background and export related environment variables to the current bash session.

``ssh-add -q ~/.ssh/borg-client_key``

  Load the SSH private key dedicated to communication with the borg-client into the SSH agent.
  Look at ``man 1 ssh-add`` for a more detailed explanation.

.. note::
  Care needs to be taken when loading keys into the SSH agent. Users on the *borg-client* having read/write permissions
  to the agent's UNIX-domain socket (at least borgc and root in our case) can access the agent on *borg-server* through
  the forwarded connection and can authenticate using any of the identities loaded into the agent
  (look at ``man 1 ssh`` for more detailed explanation). Therefore there are some security considerations:

  * Private keys loaded into the agent must not be used to enable access anywhere else.
  * The keys meant to be loaded into the agent must be specified explicitly, not from default locations.
  * The *borg-client*'s entry in *borgs@borg-server:~/.ssh/authorized_keys* must be as restrictive as possible.

``echo 'your secure borg key passphrase' | ssh -A -o StrictHostKeyChecking=no borgc@borg-client "BORG_PASSPHRASE=\$(cat) borg --rsh 'ssh -o StrictHostKeyChecking=no' init --encryption repokey ssh://borgs@borg-server/~/repo"``

  Run the *borg init* command on *borg-client*.

  *ssh://borgs@borg-server/~/repo* refers to the repository *repo* within borgs's home directory on *borg-server*.

  *StrictHostKeyChecking=no* is used to add host keys automatically to *~/.ssh/known_hosts* without user intervention.

``kill "${SSH_AGENT_PID}"``

  Kill ssh-agent with loaded keys when it is not needed anymore.

Remote forwarding
=================

The standard ssh client allows to create tunnels to forward local ports to a remote server (local forwarding) and also
to allow remote ports to be forwarded to local ports (remote forwarding).

This remote forwarding can be used to allow remote backup clients to access the backup server even if the backup server
cannot be reached by the backup client.

This can even be used in cases where neither the backup server can reach the backup client and the backup client cannot
reach the backup server, but some intermediate host can access both.

A schematic approach is as follows

::

      Backup Server (backup@mybackup)          Intermediate Machine (john@myinter)              Backup Client (bob@myclient)

                                              1. Establish SSH remote forwarding  ----------->  SSH listen on local port

                                                                                                2. Starting ``borg create`` establishes
                                              3. SSH forwards to intermediate machine  <------- SSH connection to the local port
      4. Receives backup connection <-------  and further on to backup server
      via SSH

So for the backup client the backup is done via SSH to a local port and for the backup server there is a normal backup
performed via ssh.

In order to achieve this, the following commands can be used to create the remote port forwarding:

1. On machine ``myinter``

``ssh bob@myclient -v -C -R 8022:mybackup:22 -N``

This will listen for ssh-connections on port ``8022`` on ``myclient`` and forward connections to port 22 on ``mybackup``.

You can also remove the need for machine ``myinter`` and create the port forwarding on the backup server directly by
using ``localhost`` instead of ``mybackup``

2. On machine ``myclient``

``borg create -v --progress --stats ssh://backup@localhost:8022/home/backup/repos/myclient /``

Make sure to use port ``8022`` and ``localhost`` for the repository as this instructs borg on ``myclient`` to use the
remote forwarded ssh connection.

SSH Keys
--------

If you want to automate backups when using this method, the ssh ``known_hosts`` and ``authorized_keys`` need to be set up
to allow connections.

Security Considerations
-----------------------

Opening up SSH access this way can pose a security risk as it effectively opens remote access to your
backup server on the client even if it is located outside of your company network.

To reduce the chances of compromise, you should configure a forced command in ``authorized_keys`` to prevent
anyone from performing any other action on the backup server.

This can be done e.g. by adding the following in ``$HOME/.ssh/authorized_keys`` on ``mybackup`` with proper
path and client-fqdn:

::

  command="cd /home/backup/repos/<client fqdn>;borg serve --restrict-to-path /home/backup/repos/<client fqdn>"


All the additional security considerations for borg should be applied, see :ref:`central-backup-server` for some additional
hints.

More information
----------------

See `remote forwarding`_ and the `ssh man page`_ for more information about remote forwarding.

   .. _remote forwarding: https://linuxize.com/post/how-to-setup-ssh-tunneling/
   .. _ssh man page: https://manpages.debian.org/testing/manpages-de/ssh.1.de.html