Using an Encrypted Filesystem for Mail Directories

As I use a server that is not under my physical control (VPS in a datacenter), I don't like the idea of somebody just making a copy of my disk image, mounting it and going through my mail. In addition to encrypting all of the home directories, I decided to encrypt the mailstore as well.

This was done on a Debian based system using an already running and configured instance of postfix and dovecot, but should be easily adaptable to any Linux based system as it uses eCryptfs and to any other MTA and IMAP/POP server.

Installation

Install the eCryptfs utilities. On Debian based systems:

root@system:~# apt-get install ecryptfs-utils

Back up existing mailstore

Stop all of the mail services

root@system:~# service postfix stop
* Stopping Postfix Mail Transport Agent postfix                         [ OK ] 
root@system:~# service dovecot stop
dovecot stop/waiting
root@system:~# 

Archive the mail directory into a tar file:

root@system:/var# cd /var/
root@system:/var# tar cvpf mail.tar mail
mail/
mail/router.lab/
mail/router.lab/user1/
.
..
...
mail/blackhole-networks.com/user1/dovecot.index.log
mail/blackhole-networks.com/user1/dovecot-uidvalidity
mail/blackhole-networks.com/user1/dovecot.mailbox.log
root@system:/var# 

Clean out the old unencrypted mail files:

root@system:/var# cd mail
root@system:/var/mail# ls
blackhole-networks.com  router.lab
root@system:/var/mail# rm -rf *
root@system:/var/mail# 

Encrypt the Mail Directories

Mount the directory as an encrypted fileystem, using a big, nasty, hard to remember passphrase -- "Really_Hard2GuessPassPhraseThatNobodyWillEverThinkUV...EVER!!!" Follow the prompts from eCryptfs, and select the encryption that suits your needs and tastes. I chose the passphrase above (not realy), aes with 32 byte keys, not to allow non-encrypted files, and to encrypt filenames.

root@system:/root# mount -t ecryptfs /var/mail /var/mail
Passphrase: Really_Hard2GuessPassPhraseThatNobodyWillEverThinkUV...EVER!!!
Select cipher: 
 1) aes: blocksize = 16; min keysize = 16; max keysize = 32 (loaded)
 2) des3_ede: blocksize = 8; min keysize = 24; max keysize = 24 (not loaded)
 3) cast6: blocksize = 16; min keysize = 16; max keysize = 32 (not loaded)
 4) cast5: blocksize = 8; min keysize = 5; max keysize = 16 (not loaded)
Selection [aes]: 
Select key bytes: 
 1) 16
 2) 32
 3) 24
Selection [16]: 2
Enable plaintext passthrough (y/n) [n]: 
Enable filename encryption (y/n) [n]: y
Filename Encryption Key (FNEK) Signature [f88d8974c82e5ea8]: 
Attempting to mount with the following options:
  ecryptfs_unlink_sigs
  ecryptfs_fnek_sig=f88d8974c82e5ea8
  ecryptfs_key_bytes=32
  ecryptfs_cipher=aes
  ecryptfs_sig=f88d8974c82e5ea8
WARNING: Based on the contents of [/root/.ecryptfs/sig-cache.txt],
it looks like you have never mounted with this key 
before. This could mean that you have typed your 
passphrase wrong.

Would you like to proceed with the mount (yes/no)? : yes
Would you like to append sig [f88d8974c82e5ea8] to
[/root/.ecryptfs/sig-cache.txt] 
in order to avoid this warning in the future (yes/no)? : yes
Successfully appended new sig to user sig cache file
Mounted eCryptfs
root@system:/root# 

Create an rc file "/root/.ecryptfsrc" that has all of the encryption parameters for the encrypted directory. The sig comes from /root/.ecryptfs/sig-cache.txt or saved from the setup above. Leave out the key directive if you want to manually provide this each time it needs to start the filesystem -- you'll be prompted for it instead.

key=Really_Hard2GuessPassPhraseThatNobodyWillEverThinkUV...EVER!!!
ecryptfs_cipher=aes
ecryptfs_passthrough=n
ecryptfs_enable_filename_crypto=y
ecryptfs_unlink_sigs
ecryptfs_fnek_sig=f88d8974c82e5ea8
ecryptfs_key_bytes=32
ecryptfs_cipher=aes
ecryptfs_sig=f88d8974c82e5ea8

Test the Encrypted Mailstore

Make sure everything works as intended. Create a testfile in the encrypted filesystem after it has been mounted.

root@system:/var/mail#  echo "Encrypt this bitch" > testfile
root@system:/var/mail# cat testfile 
Encrypt this bitch

Unmount the filesystem and inspect our file.

root@system:/var/mail# cd ..
root@system:/var# umount /var/mail
root@system:/var# cd mail/
root@system:/var/mail# ls
ECRYPTFS_FNEK_ENCRYPTED.FWbrTE.ne3tTw-k0xHmj9dKza1lba.NA.ukoD9v7Ms4OzWnUNKUTcAb2Y---

Mount the filesystem back up and take a look again.

root@system:/var/#  mount -t ecryptfs /var/mail /var/mail
Passphrase: Really_Hard2GuessPassPhraseThatNobodyWillEverThinkUV...EVER!!!
Attempting to mount with the following options:
  ecryptfs_unlink_sigs
  ecryptfs_fnek_sig=f88d8974c82e5ea8
  ecryptfs_key_bytes=32
  ecryptfs_cipher=aes
  ecryptfs_sig=f88d8974c82e5ea8
Mounted eCryptfs
root@pippacott:/var# ls mail
testfile

Restore the Contents of the Mailstore - Encrypting them in the Process

Extract the email back into it's original location to encrypt it, and get rid of our testfile

root@system:/var# tar xpf mail.tar 
root@system:/var# ls mail
blackhole-networks.com  router.lab  testfile
root@system:/var# rm mail/testfile 
root@system:/var# 

Save Time with an fstab Entry

Add a convienent line to /etc/fstab so you can just mount /var/mail, don't mount at boot so you'll have to provide a password by hand later. This is generated by looking at system mounts and adding noauto and noatime to the options.

/var/mail /var/mail ecryptfs rw,ecryptfs_sig=f88d8974c82e5ea8,ecryptfs_cipher=aes,ecryptfs_key_bytes=32,ecryptfs_fnek_sig=f88d8974c82e5ea8,ecryptfs_unlink_sigs,noauto,noatime 0 0

Stop Mail Services from Starting Unless the Encrypted Volume is Mounted

Whle the encrypted filesystem is mounted create a file called "OK" for a quick test item in shell scripts whether or not the volume is properly mounted.

root@system:/var/mail# touch OK

Make sure that dovecot won't start unless the file OK is readable by adding the following line to the "pre-start script" and the "script" sections of the upstart job in /etc/init/dovecot.conf.

..
...
pre-start script
    test -r /var/mail/OK || { stop ; exit 0; }
    test -x /usr/sbin/dovecot || { stop ; exit 0; }
    test -r /etc/dovecot/dovecot.conf || { stop ; exit 0; }

    # dont check for inetd.conf if its not installed
    if [ -f /etc/inetd.conf ]; then
...
..
.
script
        test -r /var/mail/OK || { stop ; exit 0; }
        test -x /usr/sbin/ntp-wait && ntp-wait -n 2 || true
        exec /usr/sbin/dovecot -F -c /etc/dovecot/dovecot.conf
end script

Make sure postfix wont start unless the OK file is readable by adding the following line to the /etc/init.d/postfix rc file.

.
..
...
unset TZ

# Defaults - don't touch, edit /etc/default/postfix
SYNC_CHROOT="y"

test -f /etc/default/postfix && . /etc/default/postfix

test -r /var/mail/OK || exit 0

test -x $DAEMON && test -f /etc/postfix/main.cf || exit 0

. /lib/lsb/init-f
...
..
.

The best way to test this is a reboot, but you can also kill the postfix and dovecot services, and unmount the encrypted filesystem to test.

Final Notes

The pain in the butt that this creates, is the fact that if your system ever reboots your mail service aren't going to automatically start. To help allieviate this problem, I installed nullmailer to send me an alert so I can login (via my phone if needed), mount the mailstore and start the MTA and associated services. See Using nullmailer as a Reboot Alerter for setup of an MTA-less alerting system.

Finally, I created a quicky shell script to assist me with mounting the mailstore and starting the mail services after a reboot.

root@system:/root# cat reboot-recover.sh 
#!/bin/sh
mount /var/mail
/etc/init.d/postfix start
start dovecot
root@system:/root#