http://bjoernstechblog.rueffer.info/posts/bash/backup/rsync/mac/networking/2011/06/15/Network-backup-of-network-backup/
last updated on 25 May 2018

15 June 2011

Network backup of network backup

I have the following scenario: A couple of Mac computers push their hourly/daily backups to a timecapsule device using timemachine (actually, pushing to a samba share would do equally well, see this older post of mine). One of the benefits is that my work group has total control over this timecapsule, it is always accessible to us. On the other hand, in case of fire or burglary, not only our workstations might be lost, but also our backup device.

So, the easiest workaround to this problem is to make frequent backups of the contents of the backup device, it would seem. This way I do not need to reconfigure many individual Mac computers which users usually prefer to administer themselves. Also, there is the advantage of having two redundant copies of the same data in two geographically distinct places.

The possibly easiest way to proceed is to run rsync on my local machine to copy all the data accross the network. Catch is, this slows down my network connection and that of the group. Also, I don’t want to run rsync during business hours, but, say, before I go home, and ideally not on my laptop but on some stationary office machine.

To automate all that, I need to store passwords for accessing the timecapsule as well as a network storage (which is a samba share in our case) somehow. Leaving those passwords in plaintext in a script file is a dumb idea, coming up with some type of your own purpose built cryptography would be reinventing the wheel and might actually only provide a very weak security measure.

But there’s hope: Mac OS knows a command line command named security which allows to access secrets stored in a keychain. That is the place, where Mac OS likes to store passwords. And if Mac OS can do it, why shouldn’t I?

Below you see a shell script that I run (by hand) regularly on a remote machine (encapsulated in the fantastic screen command) to move around our precious backups. The script accesses passwords stored in a custom built keychain file located in the current directory. It mounts the network shares (one is the timecapsule and one the samba share) and then uses rsync to copy all the data. The advantage is that I only need to enter a password of my choosing once to initiate this entire process, while the password secrets are really stored on a machine that potentially untrusted persons would have access to.

My intention here is to give some hints on how I managed to automate this recurring task. I do not intend to provide working software or counseling for those whose setups are different from mine. Hence, the following software is provided as is, and without any warranty. Your milage may wary, use at your own risk!

#!/bin/bash
# Copyright (C) 2011 by Bjoern Rueffer
# Time-stamp: <2011-06-14 20:58:26 rueffer>

# Configuration
# #############

# In order for this script to work, a file 'mykeychain.keychain' has
# to be created in this directory which contains password entries for
# the network volumes this script is supposed to access. Only the user
# who knows the password to this keychain will be able to successfully
# run this script.

# To create that file, attach the two volumes that you plan to copy to
# and from, and let Keychain store all credentials. Do then open
# 'Keychain Access.app' to create a new keychain, whereto you copy the
# two newly created password items. Optionally, delete the original
# password items in your login keychain. When you first run this
# script, you will be asked if a a command named security may (via
# Terminal.app) access the new password items. Inform the dialog that
# this process may always access the passwords.

# You also need to create two mount points in the current directory,
# namely $SOURCE_SUBDIR and $DEST_SUBDIR (you can decide below for the
# actual names of the directories represented by these variables).

# Usage
# #####

# Execute this script e.g. as
#
#    ./tc2storageserver_sync.sh 2>&1 | tee log-'`date`' ; sudo shutdown -h +2
#
# before you go home. It will sync your network backup to a second
# server and then shut down your local machine (assuming you have
# configured sudo correctly).

function log(){   # a function to output log messages
echo $* >&2
}

function fail(){  # a function called to fail this
# process in case something goes wrong
echo $* >&2
exit 1
}

WORK_DIR=~/storageserver-backup # where this script and the
# moint-points live

log ===
log $0 invoked on `date`
log unlocking storageserver keychain to access server passwords:
security unlock-keychain $WORK_DIR/mykeychain.keychain || fail 'unlocking keychain failed'
log -n initializing...

SOURCE_SUBDIR=timecapsule-mount
DEST_SUBDIR=storageserver-mount

# suppose you want to transfer data as username to
# //storage.server.name.de/the_name_of_your_share_here then use:

DEST_SERVER=storage.server.name.de
DEST_USER=username
DEST_SHARE=the_name_of_your_share_here
DEST_PASSWORD=`(security find-internet-password -s $DEST_SERVER -a $DEST_USER -g  $WORK_DIR/mykeychain.keychain >/dev/null) 2>&1 |sed -e 's/^password: '\(.*\)'$/\1/'` # extract password from keychain
DEST_MOUNTSTR='mount_smbfs //$DEST_USER:$DEST_PASSWORD@$DEST_SERVER/$DEST_SHARE $WORK_DIR/$DEST_SUBDIR'

# supposing that the data comes from a timecapsule device, you may use
# a setting similar to this one; however, any other form of mountable
# network storage might do as well. Instead of the apple file protocol
# (afp) your environment may use smb (windows file transfer protocol)
# or similar.

SOURCE_SERVER=timecapsule1.local # local address (domain name) of your timecapsule
SOURCE_PASSWORD=`(security find-internet-password -s $SOURCE_SERVER -g  $WORK_DIR/mykeychain.keychain >/dev/null) 2>&1 |sed -e 's/^password: '\(.*\)'$/\1/'` # extract password from keychain
SOURCE_MOUNTSTR='mount_afp afp://nobody:$SOURCE_PASSWORD@$SOURCE_SERVER/Data $WORK_DIR/$SOURCE_SUBDIR'

log done.

log locking keychain again.
security lock-keychain $WORK_DIR/mykeychain.keychain

# before we can begin, we remove any stale mounts from previous
# sessions:

log -n cleaning up...
umount '$WORK_DIR/$DEST_SUBDIR' '$WORK_DIR/$SOURCE_SUBDIR' || true
log done.

# so far we have set up all the configuration. Now we are going to
# make sure file systems are properly mounted where they should be:

log -n Mounting file systems...
eval $SOURCE_MOUNTSTR || fail Failure mounting source, aborting.
log -n \(source OK\)...
eval $DEST_MOUNTSTR || fail Failure mounting destination, aborting.
log -n \(destination OK\)...
log done.

# here is the actual copying procedure; the --delete-during ensures
# that on the receiving side we delete files which aren't any longer
# on the sending side. If we would not do this clean up, cache and
# temporary files might clutter up precious space on the receiving side

cd '$WORK_DIR/$DEST_SUBDIR'
rsync --delete-during -avP '$WORK_DIR/$SOURCE_SUBDIR' . 

# and that was it; now a little clean up afterwards

log -n Unmounting file systems...
umount '$WORK_DIR/$DEST_SUBDIR' '$WORK_DIR/$SOURCE_SUBDIR' 
log done.
log $0 done.
Björn Rüffer — Copyright © 2009–2018 — bjoern.rueffer.info