Running duplicacy as root from OS X launchd with Keychain access

Spent a fair bit of time figuring this out so here goes in case it’s useful for anyone else.

I wanted to run as root from launchd to backup files owned by multiple users. I am backing up to Wasabi, and also wanted to keep the API and storage keys in Keychain instead of storing them in environment variables, etc.

There appear to be two key requirements to get this to work:

  1. copy the Keychain entries for duplicacy from the user to the System keychain
  2. ensure UserName and SessionCreate keys are not set in the plist

You will find setting those keys is often suggested as necessary for accessing Keychain entries through launchd in other instances, but in this case duplicacy fails with a ‘password not found’ error -25308 if they are set.

Here is a sample plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>EnvironmentVariables</key>
        <dict>
                <key>PATH</key>
                <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/opt/X11/bin:/usr/local/sbin</string>
        </dict>
        <key>Label</key>
        <string>com.duplicacy-util.repository-name</string>
        <key>ProgramArguments</key>
        <array>
		<string>/var/root/gobackup.sh</string>
        </array>
        <key>LowPriorityIO</key>
        <false/>
        <key>StartCalendarInterval</key>
                <dict>
                        <key>Hour</key>
                        <integer>3</integer>
                        <key>Minute</key>
                        <integer>00</integer>
                </dict>
		<key>Nice</key>
		<integer>-20</integer>
		<key>ProcessType</key>
		<string>Background</string>

</dict>
</plist>

gobackup.sh switches to the repository directory and runs duplicacy as usual.

Because I want to wake my sleeping MacBook with lid closed to run the backup and it doesn’t have an external display attached, I schedule the wakeup in Energy Saver for one minute after launchd time, wait a couple minutes for WiFi to connect while running caffeinate to prevent it going right back to sleep, and then call duplicacy:

#!/bin/bash

/usr/bin/caffeinate -s -t 180 &
sleep 2m

cd /Users
/usr/bin/caffeinate -s /usr/bin/nice /usr/local/bin/duplicacy backup -storage wasabi

Not sure if the -storage flag is needed for this to work. It looks like maybe it is reflected in the Keychain entries. In my case, I initialized the repository and ran an initial backup operation to store the keys in the root user Keychain before copying them to the System keychain by running the following as root:

duplicacy init -e -storage-name wasabi repository-name wasabi://<storage-path>
duplicacy backup -storage wasabi

I’m actually using duplicacy-util which has the benefit of emailing completion reports among other features, and that works as well with .duplicacy-util directory and config in /var/root.

1 Like

Two comments and one question.

  1. You probably should caffeinate the whole script, because the system will go to sleep immediately after first caffeinate ends

  2. Nice does nothing because it’s likely the only process running/nobody else is (ab)using cpu. You should run duplicacy under severe cpu throttler like cpulimit until it can moderate it’s use of resources natively. The point of dark wake/power nap is to be invisible and unnoticeable. Dark wake that blasts fans is ridiculous.

  3. Why dance around with keychain if you can just put encryption keys into preferences file readable only by duplicacy and owned by admin?