Configuring automount for LUKS encrypted disk image on SMB share
In my previous post, I detailed how I set up an LUKS-encrypted filesystem on a loop device (a.k.a. sparse disk image file). To make automated backups easier and not have to add commands in my backup script to handle the mounting and unmounting of the disk image, I set up automount
to:
- Mount the SMB share when accessing the
/cifs
directory - Attach a loop device and set up LUKS filesystem access when accessing the
/encrypted
directory
Following along with the examples in my previous posts, I have a SMB share available at //lacie-2big/backup
with the encrypted disk image linuxbackup.sparseimage
sitting on it. My goal was to be able to do this:
$ ls /encrypted/linuxbackup
and for automount to auto-magically mount the SMB share and then mount the encrypted disk image. Unfortunately I could not find a way for automount to handle this "cascading" or "recursive" mount operation. Instead I have to execute two commands:
$ ls /cifs/lacie-2big/backup linuxbackup.sparseimage $ ls /encrypted/linuxbackup hda1 hda2 hda3 hda6 hda7 lost+found
Still, two simple ls
commands are better than the 4 hard-to-remember mount
, losetup
, cryptsetup
, and mount
commands needed to do this manually. And with the help of a small script along with what automount
provides, I don't have to worry about the 4 hard-to-remember umount
, cryptsetup
, losetup
, umount
commands needed to unmount everything when I'm finished.
Automount CIFS mount script
I found online an example automount
script based from the auto.smb
one that comes in many distributions called auto.cifs
that will work with SMB mounts requiring authentication. That script looks like:
#!/bin/bash # $Id$ # This file must be executable to work! chmod 755! key="$1" # Note: create a cred file for each windows/Samba-Server in your network # which requires password authentification. The file should contain # exactly two lines: # username=user # password=***** # Please don't use blank spaces to separate the equal sign from the # user account name or password. credfile="/etc/auto.smb.$key" # Note: Use cifs instead of smbfs: mountopts="-fstype=cifs,file_mode=0644,dir_mode=0755,uid=root,gid=wheel" smbclientopts="" for P in /bin /sbin /usr/bin /usr/sbin do if [ -x $P/smbclient ] then SMBCLIENT=$P/smbclient break fi done #echo $SMBCLIENT >&2 [ -x $SMBCLIENT ] || exit 1 if [ -e "$credfile" ] then mountopts=$mountopts",credentials=$credfile" smbclientopts="-A "$credfile else smbclientopts="-N" fi #echo $smbclientopts -gL $key >&2 $SMBCLIENT $smbclientopts -gL $key 2>/dev/null \ | awk -v key="$key" -v opts="$mountopts" -F'|' -- ' BEGIN { ORS=""; first=1 } /Disk/ { if (first) { print opts; first=0 }; gsub(/ /, "\\ ", $2); sub(/\$/, "\\$", $2); print " \\\n\t /" $2, "://" key "/" $2 } END { if (!first) print "\n"; else exit 1 } '
I created that as /etc/auto.cifs
and made it executable. Then in /etc/auto.master
I added this line:
/cifs /etc/auto.cifs --timeout=60
The credentials for mounting the SMB share are then stored in a /etc/auto.smb.lacie-2big
file, which is how I set things up originally in my last post. Now, after reloading the autofs
service, I am able to:
$ ls /cifs/lacie-2big/backup
linuxbackup.sparseimage
Automount LUKS script
Then I created another automount
script /etc/auto.luks.loop.0
:
#!/bin/bash # This file must be executable to work! chmod 755! # Make links to this file with the last digit replaced # with other numbers for corresponding loop devices, # e.g. if this script is executed as auto.luks.loop.1 the # /dev/loop1 device will be used. # # The LUKS key must exist as a file at /etc/.key key="$1" los="" cry="" name=`basename $0` l=${name##*.} img="/cifs/lacie-2big/backup/$key.sparseimage" mountopts="-fstype=ext3,defaults,noatime,nodiratime" if [ ! -e "/etc/$key.key" ]; then exit 1 fi # search for losetup and cryptsetup for P in /bin /sbin /usr/bin /usr/sbin do if [ -z "$los" -a -x $P/losetup ]; then los=$P/losetup fi if [ -z "$cry" -a -x $P/cryptsetup ]; then cry=$P/cryptsetup fi if [ -n "$los" -a -n "$cry" ]; then break fi done # check if loop device already attached, if not then attach it chk=`$los -a |grep /dev/loop$l` if [ -z "$chk" ]; then if [ ! -e $img ]; then echo "Image file $img not found." >&2 exit 1 fi $los /dev/loop$l $img $cry --key-file /etc/$key.key luksOpen /dev/loop$l \ luks-`$cry luksUUID /dev/loop$l` >/dev/null 2>&1 fi echo $mountopts / :/dev/mapper/luks-`$cry luksUUID /dev/loop$l`
This script is hard-coded to look for disk image files in /cifs/lacie-2big/backup
named imagefilename.sparseimage
where filename will be the automount directory name. The script uses the last number of the script name to determine which loop device to use, although it could be easily adapted to use any freely-available device (by way of losetup -f
).
Then it uses cryptsetup
to open the LUKS device, using a key file located at /etc/imagefilename.key
. Then it configures automount
to mount the LUKS filesystem. In short, the script basically does:
$ losetup /dev/loop0 /cifs/lacie-2big/backup/linuxbackup.sparseimage $ cryptsetup --key-file /etc/linuxbackup.key luksOpen /dev/loop0 \ luks-`cryptsetup luksUUID /dev/loop0` $ echo -fstype=ext3,defaults,noatime,nodiratime \ / :/dev/mapper/luks-`cryptsetup luksUUID /dev/loop0`
That last line is what is returned to automount
and causes it to mount the image file as a directory named filename
.
Finally in /etc/auto.master
I added this line:
/encrypted /etc/auto.luks.loop.0 --timeout=600
Afer having the autofs
reload this configuration, I am then able to do this:
ls /encrypted/linuxbackup
hda1 hda2 hda3 hda6 hda7 lost+found
With the caveat that the /cifs/lacie-2big/linuxbackup
directory is already mounted. This is where I couldn't find a way for automount
to mount both file systems in one call.
Auto-umount
One final piece remains to be automated, however: completely unmounting both the encrypted and SMB file systems. automount
will take care unmounting the LUKS encrypted filesystem after the configured period of inactivity. However, it won't be able to unmount the SMB filesystem because the auto.luks.loop.0
script has attached the /dev/loop0
device to the disk image file on that share. In effect, the SMB share is still in use.
It would be very nice if automount
provided a way to execute scripts when it unmounted a filesystem. But it does not. My solution was to write a small script that runs every so often (via cron) that looks to see if any loop devices are attached to filesystems that are "not in use" and if found, detach them. Here's the script, which I have stored at /etc/auto.luks.loop.umount
:
#!/bin/bash los="" cry="" # search for losetup and cryptsetup for P in /bin /sbin /usr/bin /usr/sbin do if [ -z "$los" -a -x $P/losetup ]; then los=$P/losetup fi if [ -z "$cry" -a -x $P/cryptsetup ]; then cry=$P/cryptsetup fi if [ -n "$los" -a -n "$cry" ]; then break fi done for dev in `$los -a|cut -d: -f1`; do file=`$los -a|grep /dev/loop |sed 's/.*(\(.*\)).*/\1/'` dir=${file%/*} # check if the only open file on loopback file's filesystem # is from automount, if so close loopback device so automount # can un-mount filesystem for us later match=`lsof |grep $dir|cut -d" " -f1 |grep -v automount` if [ -n "$match" ]; then echo "Loop device $dev attched to in-use filesystem $dir" >&2 else echo "Loop device $dev on unused filesystem $dir" $cry isLuks $dev 2>/dev/null if [ "$?" -eq "0" ]; then echo "Closing LUKS on $dev" $cry luksClose luks-`$cry luksUUID $dev` fi echo "Unattaching loop device $dev" $los -d $dev fi done
It's not particularly clever. I'm sure it would not work on systems using loop devices for other things that what I'm using them for on my system and it's making assumptions on the output of losetup
. But it does the job nicely for what I need. I have this run every so often via cron
. After it runs, and if it found any loop devices it could detach, then automount
will eventually unmount the SMB share for us and we're done.
These scripts can be obtained via anonymous CVS:
cvs -d :pserver:anonymous@msqr.us:/data/cvs co twobig