I’ve recently chosen to take more control over my data when it’s stored in the cloud. Some big parts of that data are my email accounts. Like most geeks, I have a few “vanity” domains that I receive email at. Also like most geeks, I host them on Google Apps. So, I’ve decided to encrypt all incoming emails before they get stored on Google’s servers.
I searched around for methods of implementing this, but many used Exim or Procmail. I’m partial to Postfix myself, I like they’re privilege separation model. I was running up blanks, until I stumbled upon https://code.google.com/p/gpg-mailgate/. This project is a very straightforward filter to GPG encrypt mail if a recipient’s key is locally stored. Getting this operational on Ubuntu was easy.
Creating a mail forwarder
First, I installed Postfix with a blank configuration. Then, to create a basic forwarder configuration I made /etc/postfix/main.cf:
myhostname = forwarder.DOMAIN.COM mydomain = localhost myorigin = $mydomain inet_interfaces = all mydestination = $myhostname, localhost.$mydomain, $mydomain mynetworks_style = host smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) biff = no alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases append_dot_mydomain = no readme_directory = no relay_domains = DOMAIN.COM transport_maps = hash:/etc/postfix/transport
Next I needed to make /etc/postfix/transport:
DOMAIN.COM smtp:[ASPMX.L.GOOGLE.COM]
And due a slight bug in Ubuntu’s blank configuration, I needed to make an aliases db:
echo 'postmaster: root' >> /etc/aliases newaliases
Restart Postfix:
service postfix restart
At this point I changed my DNS to point the MX record to this server. I sent a test email to ensure fowarding worked.
Installing the GPG encryption filter
You’ll want to install gpg, then install GPG-Mailgate:
cd /root hg clone https://code.google.com/p/gpg-mailgate/ cd gpg-mailgate
From here I mostly followed the steps from INSTALL, but they’re a bit dated and didn’t quite work for me. Here’s the short version, my apologies for the lazy instructions, make sure you replace the python version below with the version that’s live on your system:
cp -R GnuPG /usr/lib/python2.6/ vi /usr/lib/python2.6/GnuPG/__init__.py
Above, we need to add “–trust-model always” to the command in line 43. Otherwise GPG throws an error about not trusting the key and fails to encrypt messages.
cp gpg-mailgate.conf.sample /etc/gpg-mailgate.conf vi /etc/gpg-mailgate.conf
In /etc/gpg-mailgate.conf, modify the domains variable to include all domains you want to encrypt messages for. Then, if you have mail aliases, you’ll probably want to add entries under [keymap] in the format email = longKeyID. Leave keyhome as default.
After this is done, we need to get the public keys we want to use for encryption. We can take advantage of Postfix’s privilege separation here:
adduser -s /bin/false -d /var/gpg -M gpgmap mkdir -p /var/gpg/.gnupg chown -R gpgmap /var/gpg chmod 700 /var/gpg/.gnupg
The next command needs to be repeated for each email address you want to encrypt mails for. If you want an email alias encrypted with a key, use the keymap section of the config file above.
sudo -u gpgmap /usr/bin/gpg --homedir /var/gpg/.gnupg --keyserver hkp://keys.indymedia.org --search myemail@DOMAIN.COM
Then, we’ll need to tell Postfix to have a filter that calls the external script, and a channel to accept mail from the script after it’s encrypted. The following goes in /etc/postfix/master.cf, keep in mind that I’m using a different username than the INSTALL directions do (this part gets a bit wide, you may need to expand your viewing window):
gpg-mailgate unix - n n - - pipe flags= user=gpgmap argv=/usr/local/bin/gpg-mailgate.py 127.0.0.1:10028 inet n - n - 10 smtpd -o content_filter= -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks -o smtpd_helo_restrictions= -o smtpd_client_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o smtpd_authorized_xforward_hosts=127.0.0.0/8
And then we tell Postfix to use the filter by running this quick command to add a line to /etc/postfix/master.cf
echo 'content_filter = gpg-mailgate' >> /etc/postfix/main.cf
Restart Postfix:
service postfix restart
With all that, you should find that a test email sent to the email address you specified ends up in your Google inbox encrypted with your gpg key. This works perfectly with a PGP-capable IMAP client, such as Thunderbird or K-9 Mail on Android.
Hardening
As an added bonus, I threw together an apparmor profile. If your system uses AppArmor, you can place the following in /etc/apparmor.d/usr.local.bin.gpg-mailgate.py — keep in mind that you’ll need to match the version of python below with the version used on your system.
#include <tunables/global> /usr/local/bin/gpg-mailgate.py { #include <abstractions/base> #include <abstractions/nameservice> #include <abstractions/python> /usr/bin/python2.6 ix, /usr/include/python2.6/pyconfig.h r, /usr/lib/python2.6/GnuPG/__init__.pyc r, /usr/local/bin/gpg-mailgate.py r, /usr/bin/gpg Cx -> gpg, /etc/gpg-mailgate.conf r, /etc/default/apport r, /tmp/gpg-mailgate.log rw, profile gpg { #include <abstractions/base> #include <abstractions/nameservice> /usr/bin/gpg r, /var/gpg/.gnupg/* r, /var/gpg/.gnupg/.* w, /var/gpg/.gnupg/trustdb.gpg w, /var/gpg/.gnupg/random_seed wk, } }
Then just run the following to activate the profile:
aa-enforce /etc/apparmor.d/usr.local.bin.gpg-mailgate.py
I found that I still get one apparmor warning, about it wanting to unlink the GnuPG library, which I thought was odd so I didn’t write a rule for it. If this bothers you, add a ‘d’ beside the ‘r’ for that line. Obviously debugging AppArmor is out of scope for this blog post, but there are plenty of useful resources that are just a Google search away.
Edit: I am not at all confident that this AppArmor profile improves the security of using the gpg-mailgate script. Use at your own risk, etc.
Anyways, there you have it. Now all your mail is encrypted before it hits Google’s server for data mining. There’s probably a double-encryption bug that needs to be worked out, and outgoing mail won’t be stored encrypted, but we can at least regain a little bit of control over the data we store in the cloud.