macOS and local APFS snapshots

Hey all :slight_smile:

I’ve been in front of this problem for several months now and can’t seem to find a proper solution.

Plan:
I want to use macOS local APFS snapshots as the source of restic backups.
So whenever restic is scheduled to run a backup command, my idea is to make a local APFS snapshot, mount it and then point restic at this read only mounted APFS snapshot.
All this logic is put in a bash script and being scheduled with launchd.

Problem:
In order to automatically mount a local APFS snapshots with this script, I have to add bash to the list of FDA (Full Disk Access) applications in the macOS settings pane.
I have tried all the tricks I could think of but couldn’t find a way other than the above.

From a security perspective I absolutely don’t want to give bash full disk access to my machine.
That’s just not going to happen.

So I guess this isn’t restic specific I guess, but around it heh
Here is a little screenshot showing how I set it up and reproduced it:


If someone wants to play around with it, here is a minimal setup which reproduced the problem:

demo.sh:

#!/bin/bash
set -x
mkdir -p /tmp/restic/backup

local_apfs_snapshot_full="$(tmutil localsnapshot /)"
local_apfs_snapshot=$(echo "$local_apfs_snapshot_full" | grep 'Created local' | awk '{ print $6 }')

mount_apfs -s com.apple.TimeMachine."$local_apfs_snapshot".local /Users/ "/tmp/restic/backup"

# Cleanup
umount "/tmp/restic/backup"
rm -rf /tmp/restic/backup

exit 0

com.moritzdietz.restic-backup.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.moritzdietz.restic-backup</string>
    <key>Program</key>
    <string>/Users/moritzdietz/Desktop/demo.sh</string>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>900</integer>
    <key>StandardOutPath</key>
    <string>/Users/moritzdietz/Library/Logs/com.moritzdietz.restic-backup.out.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/moritzdietz/Library/Logs/com.moritzdietz.restic-backup.error.log</string>
</dict>
</plist>

Then you need to go into the FDA settings and add and remove /bin/bash to see the result.

FWIW, I have a bash script that runs restic which I wrap as a macOS .app using GitHub - sveinbjornt/Platypus: Create native Mac applications from command line scripts. . I then install that .app in ~/Applications, give that .app FDA in the System Settings, and it can then happily read the files it needs to.

I only ever backed up ~ or stuff thereunder, in case that matters. But what I can say is that without giving that .app FDA it will produce a lot of read errors during backup runs, and having given it FDA it’s happy. I’ve tried other methods too through the years but this one always works for me.

1 Like

Ha! Thanks. Will definitely give that a try and report back if that works.

The thing is, I know of another backup software which has allowed access to Apples private APFS APIs and I am super jealous that they are gatekeeping it from others.

Making an .app bundle using the software you recommended worked to mount the local APFS snapshot! Thank you :slight_smile:

Now I need to see if using launchd to schedule this, works as well. But a first test by simply starting the .app with the bash script which invokes restic, tmutil and mount_apfs commands worked perfectly.

FWIW I use /usr/bin/open -ga $HOME/Applications/Backup.app to run the .app from crontab.