Free version available
Magnifying Glass

Blog archive for July, 2009

Syndicated Posts

FaceBook

Twitter

  • #financialconfession of the day: "I get really annoyed when my friends spend frivolously and then complain about... http://fb.me/I1qhJW4p 4 days ago
  • "Bye Bye Quicken Online, Hello Mint!" by Jay Monee on Budgets Are Sexy - "PocketSmith: This big pull with these... http://fb.me/EuooR2LH 1 week ago
  • "Too many people spend money they haven't earned, to buy things they don't want, to impress people they don't like." Will Smith #quote 1 week ago
  • More updates...

Nations united under PocketSmith

Thursday, July 16th, 2009 by Jason

So today we rustled up a few numbers around our userbase for a report we had to generate, and I thought we’d share them with you. We started collecting a bit more geographical information around our users when we soft-launched the subscription model, and based on nearly two months’ data, we have ascertained that:

  • PocketSmith has users from 71 countries
    From Angola to Venezuela, you guys are truly a global bunch. 71 countries! We can’t wait for an opportunity to leave the office and come say hi to all of you!

  • The majority of our users are from the USA, with NZ coming in a close second
    New Zealand has a population of around 4.3 million, which is less than two-thirds of the population of the Bay Area.

  • Hong Kong, Japan, Canada and the UK are closely tied
    Do you guys train at the same gym or something?

  • 1628 goals created in total
    That’s a lot of goals. Keep up the good work, we hope you’re on your way towards achieving them!

  • Total amount of money managed so far: $107,919,461
    Not quite enough for an Airbus A380 yet. Nevertheless, we hope we’re helping you make a real difference.

Needless to say, we’re delighted to have all of you on board. And guess what? We’re working on translations too. We’ll start with a few and see what you guys think. If you are, or know of a good translator for your language, please drop us a line – we’d love to talk to you.

Setting Up DKIM and DomainKeys using DKIMProxy with Postfix in Ubuntu Hardy

Sunday, July 5th, 2009 by James

Background

DKIM (http://www.dkim.org/) and DomainKeys (http://en.wikipedia.org/wiki/DomainKeys) are two distinct but similar technologies, which enables a public / private key pair, signatures in the email header, and a DNS record to check that an email has come from a particular server. They are each used by different mail servers as a spam check – Yahoo uses both, and Google / Gmail uses DKIM (the newer technology).

DKIMProxy (http://dkimproxy.sourceforge.net/) is a package that has made my life so much easier because it implements and sends both of these key types with one install.

It was a little painful for me to setup, and it took a fair while for me to work through all the various issues / configuration bits and pieces, so I have written this in the hope that things are made easier for others. The below is the process that I took to get this all up and running on our live production server, based upon trial-and-error, hack-and-slash on our staging server.

Note that I am distributing this information without warranty of any kind – I am not a dedicated sysadmin. The below instructions worked for us, but it isn’t our fault if your email world crumbles down ;) Our setup is Postfix on Ubuntu 8.04LTS (Hardy), and these instructions were gleaned from http://dkimproxy.sourceforge.net/,  http://anothersysadmin.wordpress.com/2008/01/16/domainkeysdkim-with-postfix/ and http://dkimproxy.sourceforge.net/postfix-outbound-howto.html. These instructions also only cover outgoing mail – I edited the init script to only server for outgoing mail as well – so if you want to Authorize incoming mail you’re going to need to look elsewhere, although you may find the bits in here useful.

It is STRONGLY recommended that if you are to follow the below instructions, you do so in staging environment first, and test extensively using a @yahoo email address, and a @gmail address. This is also recommended by the creators of DKIMProxy as well, so just stage it first, ok?

After all, Rudder had a security blunder after a dodgy DKIM install. SO JUST STAGE IT FIRST, OK? Seriously, don’t mess with the absolute truth of this statement.

Testing the Authenticity – Email Headers

With each of the above, you can view the full headers to see what the mail receiver makes of your message. The below examples are our headers after installing everything – so it can act as a basis of comparison for you.

In Gmail, click on the menu arrow to the right of “Reply” in the message, and choose “Show original”. This will put out the full headers for the message. The below are the relevant parts of the message that we will be looking for in future testing:

Received-SPF: pass (google.com: best guess record for domain of accounts@pocketsmith.com designates 68.64.33.16 as permitted sender) client-ip=68.64.33.16;
Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of accounts@pocketsmith.com designates 68.64.33.16 as permitted sender) smtp.mail=accounts@pocketsmith.com; dkim=pass (test mode) header.i=@pocketsmith.com
Received: from mail.pocketsmith.com (localhost [127.0.0.1])
by mail.pocketsmith.com (Postfix) with ESMTP id 7FC639680E0
for <contactpocketsmith+appemails@gmail.com>; Sat,  4 Jul 2009 22:26:02 -0400 (EDT)

And then in Yahoo, click on the down arrow next to “Compact Header” and select “Full Header”. Again, the juicy bits we want to see at the end of this process are below:

Authentication-Results: mta186.mail.re3.yahoo.com  from=pocketsmith.com; domainkeys=pass (ok); from=pocketsmith.com; dkim=pass (ok)
Received: from 68.64.33.16  (EHLO mail.pocketsmith.com) (68.64.33.16)
by mta186.mail.re3.yahoo.com with SMTP; Sat, 04 Jul 2009 19:25:17 -0700
Received: from mail.pocketsmith.com (localhost [127.0.0.1])
by mail.pocketsmith.com (Postfix) with ESMTP id 6C6299680DE
for <wigsgiw@yahoo.co.nz>; Sat,  4 Jul 2009 22:26:02 -0400 (EDT)

Another thing that you will see crop up in the headers is DomainKey-Signature and DKIM-Signature. You probably won’t have them yet, but the aim is to send these with each email and have them pass against the DNS record we’ll be setting up later.

DomainKey-Signature: a=rsa-sha1; c=nofws; d=pocketsmith.com; h=date:from
:reply-to:to:subject:mime-version:content-type:message-id; q=
dns; s=mail; b=QlTpx3...VA=
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; d=pocketsmith.com; h=date
:from:reply-to:to:subject:mime-version:content-type:message-id;
s=mail; bh=heQ/E1X...Sc=

Now lets quickly, for reference, check out how yahoo sees Google’s mail and vice-versa, just as a basis of comparison to make sure I ended up being correct in my setup I describe below.

Gmail >> Yahoo

Authentication-Results: mta208.mail.mud.yahoo.com  from=gmail.com; domainkeys=pass (ok)
Received: from 209.85.210.179  (EHLO mail-yx0-f179.google.com) (209.85.210.179)
by mta208.mail.mud.yahoo.com with SMTP; Sat, 04 Jul 2009 20:06:16 -0700

Yahoo >> Gmail

Authentication-Results: mx.google.com; spf=neutral (google.com: 76.13.13.67 is neither permitted nor denied by best guess record for domain of wigsgiw@yahoo.co.nz) smtp.mail=wigsgiw@yahoo.co.nz; dkim=pass (test mode) header.i=@yahoo.co.nz
Received: from [76.13.13.25] by n4.bullet.mail.ac4.yahoo.com with NNFMP; 05 Jul 2009 03:13:09 -0000

So things look pretty good; we have the DKIM and DomainKeys; Google / Yahoo each only have one or the other. We can see that having mail.pocketsmith.com as the “Received: from” doesn’t matter; Google has mail-yx0-f179.google.com. I was initially concerned because the Domain in the DKIM-Signatuer etc above is pocketsmith.com – not mail.pocketsmith.com – but it appears this will not matter.

So go get familiar with these headers – you are likely to be looking at these extensively over the next wee while ;)

Setting DKIM and DomainKeys Up with Postfix, using DKIMProxy

This is the exact process that I went through in getting this going on our production server. It may seem a little backwards at times, however, well, it worked for me.

First of all, lets get our required RSA keys generated, and the DNS records setup so they have time to propagate prior to testing.

Note that the below is strictly my choice for the location of these configuration files. This could well be wrong in terms of how things ’should’ be setup for configuration files / keys etc, but it makes sense to me. And that is all that matters really ;) Anyway, I’ll be using /etc/postfix/dkim as the main directory where I store the keys etc for DKIMProxy.

Generating the keys and DNS records

cd /etc/postfix/
sudo mkdir dkim
cd dkim
sudo openssl genrsa -out private.key 1024
sudo openssl rsa -in private.key -out public.key -pubout -outform PEM
cat public.key

Once you have that public key in hand, you need to create a DNS record with the key. We use Slicehost for our DNS (they kick ass), however just create the record in whatever you use – whether it is an external DNS or if you use Bind9.

You create a TXT record for the domain [selector]._domainkey.[domain.tld] – where selector is used later on in this process. I never quite got 100% into what this means… but bugger it. I chose ‘mail’ as our selector, as we send all mail from mail.pocketsmith.com and again, this just makes sense to me. This means I created the record for the following domain (note this is the complete domain, which I check for the record against):

mail._domainkey.pocketsmith.com

Then remove all the line-breaks in the public.key that we cat’d just before, so it is one long string. Then replace the “M5GfMA0…….fIDAQAB” bit below with it, and add this as the TXT record for the above domain (i.e. for us: mail._domainkey.pocketsmith.com).

k=rsa; t=y; p=M5GfMA0.......fIDAQAB

If you are doing this in Bind9, you’d just add something like:

[selector]._domainkey IN TXT "k=rsa; t=s; p=M5GfMA0.......fIDAQAB"

And these were the fields in Slicehost:

Type: TXT
Name: mail._domainkey
Data: k=rsa; t=s; p=M5GfMA0.......fIDAQAB
TTL seconds: 300

Note that if you can, set the TTL seconds to a low number (e.g. 300 as above) as this means that all servers will know to check back every 5 minutes – pretty important as you move from staging to production. Once you are happy, you can put this back up to 86400 :)

Now that we have out keys we can:

Install core dependencies for Perl Libraries (Ubuntu Hardy)

I found this to be agony, however I’ll keep this short and sharp as I learnt all I needed to and nothing more.

First, we need to make sure that the openssl development libraries is installed – to do this you may also need to update your apt-get or aptitude package lists, so do that first.

sudo aptitude update
(or sudo apt-get update, depending on what you use)
sudo aptitude install libssl-dev

Then we can install all required perl modules. The first run of CPAN (A perl package manager) below will ask you to configure it – I had no problems using the defaults on all options)

Although all dependencies would be install if you jumped straight to Mail::DKIM, it is always nice to manually install the required dependencies so you can see them all.

sudo perl -MCPAN -e 'install Crypt::OpenSSL::RSA'
sudo perl -MCPAN -e 'install Digest::SHA'
sudo perl -MCPAN -e 'install Mail::Address'
sudo perl -MCPAN -e 'install MIME::Base64'
sudo perl -MCPAN -e 'install Net::DNS'
sudo perl -MCPAN -e 'install Net::Server'
sudo perl -MCPAN -e 'install Mail::DKIM'

With Perl dependencies taken care of, we can install dkimproxy.

Installing DKIMProxy

I use /usr/src for all our source files, and I chose to install dkimproxy in /usr/local/dkimproxy.

cd /usr/src
sudo wget http://downloads.sourceforge.net/dkimproxy/dkimproxy-1.1.tar.gz
sudo tar xfh dkimproxy-1.1.tar.gz
cd dkimproxy-1.1/
./configure --prefix=/usr/local/dkimproxy
sudo make install

Done! Now for configuration – first of all, lets get PostFix talking to our DKIMProxy.

sudo nano /etc/postfix/master.cf

And just under the smtp inet n – - – - smtpd line put:

submission inet n       -       y       -       -       smtpd
    -o smtpd_etrn_restrictions=reject
    -o content_filter=dksign:[127.0.0.1]:10027
    -o receive_override_options=no_address_mappings
    -o smtpd_recipient_restrictions=permit_mynetworks,reject

(I left the rest of the commented-out stuff there… for prosperity)

And then right at the end of the same file:

#
# specify the location of the DKIM signing proxy
# Note: we allow "4" simultaneous deliveries here; high-volume sites may
#   want a number higher than 4.
# Note: the smtp_discard_ehlo_keywords option requires Postfix 2.2 or
#   better. Leave it off if your version does not support it.
#
dksign    unix  -       -       n       -       4       smtp
    -o smtp_send_xforward_command=yes
    -o smtp_discard_ehlo_keywords=8bitmime,starttls
#
# service for accepting messages FROM the DKIM signing proxy
#
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

Then we need to add our users and groups that we are going to use. So back at the command line:

sudo groupadd -g 4321 dkim
sudo useradd -u 4321 -s /bin/false -d /dev/null -g dkim dkim

Then jump back into the dkim configuration / key folder:

cd /etc/postfix/dkim

And create a domain.key file, which tells DKIM to send out DKIM and DomainKeys, with our specific options. I called the file this… because I liked having all the files in /etc/postfix/dkim/ to have a .key suffix, which is kind of silly, I know.

Note this is different from the ’standard’ set up, as I was having great difficulty getting a consistent pass from both Yahoo and Gmail. Hence, is an amalgamation of a number of options – however it isn’t necessarily 100% (but it works for us).

pocketsmith.com domainkeys(a=rsa-sha1,c=nofws), dkim(a=rsa-sha256,c=relaxed)

Now create the init script – this is definitely very different from the ’standard’ example that comes with the DKIMProxy package, for the same reaasons as the above.

But hey, it works.

Note you should edit / update the bits within the ### BEGIN CONFIGURABLE BITS block to suit your setup, and especially the setup of the DNS entry you did above (i.e. the $DKIMPROXY_SELECTOR).

UPDATE: Brian helpfully put the below up on pastie without any of the HTML oddities that plagues this sort of thing – just grab the below code from: http://www.pastie.org/579385


#!/bin/sh
#
# Copyright (c) 2005-2007 Messiah College.
# Edited heavily by James Wigglesworth (PocketSmith) July 2009
# Note: These edits make this init file only good for OUTGOING DKIM signing
#
### BEGIN INIT INFO
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Description: Runs dkimproxy
### END INIT INFO


### BEGIN CONFIGURABLE BITS
DKIMPROXYDIR=/usr/local/dkimproxy
DKIMPROXYUSER=dkim
DKIMPROXYGROUP=dkim
DKIMPROXY_PRIVATE_KEY="/etc/postfix/dkim/private.key"
DKIMPROXY_SELECTOR="mail"
DKIMPROXY_SENDER_MAP="/etc/postfix/dkim/domain.key"
### END CONFIGURABLE BITS


HOSTNAME=`hostname -f`
DKIMPROXY_OUT_ARGS="
  --conf_file=$DKIMPROXY_OUT_CFG"


DKIMPROXY_COMMON_ARGS="--user=$DKIMPROXYUSER --group=$DKIMPROXYGROUP --daemonize --keyfile=$DKIMPROXY_PRIVATE_KEY --selector=$DKIMPROXY_SELECTOR --sender_map=$DKIMPROXY_SENDER_MAP"
DKIMPROXY_OUT_BIN="$DKIMPROXYDIR/bin/dkimproxy.out"


PIDDIR=/var/run
DKIMPROXY_OUT_PID=$PIDDIR/dkimproxy_out.pid


case "$1" in
  start)
    echo -n "Starting outbound DKIM-proxy (dkimproxy.out)..."


    # create directory for pid files if necessary
    test -d $PIDDIR || mkdir -p $PIDDIR || exit 1


    # start the daemon
    $DKIMPROXY_OUT_BIN $DKIMPROXY_COMMON_ARGS --pidfile=$DKIMPROXY_OUT_PID 127.0.0.1:10027 127.0.0.1:10028
#    echo "$DKIMPROXY_OUT_BIN $DKIMPROXY_COMMON_ARGS --pidfile=$DKIMPROXY_OUT_PID 127.0.0.1:10027 127.0.0.1:10028"
    RETVAL=$?
    if [ $RETVAL -eq 0 ]; then
      echo done.
    else
      echo failed.
      exit $RETVAL
    fi
    ;;


  stop)
    echo -n "Shutting down outbound DKIM-proxy (dkimproxy.out)..."
    if [ -f $DKIMPROXY_OUT_PID ]; then
      kill `cat $DKIMPROXY_OUT_PID` && rm -f $DKIMPROXY_OUT_PID
      RETVAL=$?
      [ $RETVAL -eq 0 ] && echo done. || echo failed.
      exit $RETVAL
    else
      echo not running.
    fi
    ;;


  restart)
    $0 stop && $0 start || exit $?
    ;;


  status)
    echo -n "dkimproxy.out..."
    if [ -f $DKIMPROXY_OUT_PID ]; then
      pid=`cat $DKIMPROXY_OUT_PID`
      if ps -ef |grep -v grep |grep -q "$pid"; then
        echo " running (pid=$pid)"
      else
        echo " stopped (pid=$pid not found)"
      fi
    else
      echo " stopped"
    fi
    ;;


  *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac

Save this, and then we can get this to start on start up.

sudo chmod +x /etc/init.d/dkimproxy

I prefer to use sysv-rc-conf (http://sysv-rc-conf.sourceforge.net/) to manage startup events, so if you don’t have it, I highly recommend it:

sudo aptitude install sysv-rc-conf (or sudo apt-get install sysv-rc-conf)
sudo sysv-rc-conf --priority

Then I found the dkimproxy line and used the following values (I chose S21 as Postfix starts on S20… makes sense to me)

dkimproxy  [K20 ]  [S21 ]  [S21 ]  [S21 ]  [S21 ]  [K20 ]  [    ]  [    ]

Done!

Now we can start dkimproxy:

sudo /etc/init.d/dkimproxy start

Restart postfix:

sudo /etc/init.d/postfix restart

Then make sure that your mail is sending through port 587 – as PocketSmith is a rails app and we have our mail configuration in config/initializers/mail.rb, I just added in :port => ‘587′ instead of :port => ‘25′ and we were good to go.

All mail that is sent through port 587 will go through DKIMProxy, creating the DKIM and DomainKeys Signatures in the headers, or it will skip it if through port 25.

Some gotchas

You need to remove the test from the DNS entry when you are 100% happy that things are working correctly. I’m going to do this 24 hours from now, once I am 100% sure that the DKIM and DomainKeys records have completely, 100%, without-a-doubt propogated around the world.

The reason for this is that ONCE YOU REMOVE THIS TEST, YOU ARE EFFECTIVELY TELLING ALL SERVERS THAT MESSAGES WITHOUT A GOOD DKIM OR DOMAINKEYS IS SPAM.

I found with testing that the Yahoo Mail Authentication servers update at different times. I tested this by sending a flurry of emails from PocketSmith, all to the same account, and here are the results:

Authentication-Results: mta137.mail.re4.yahoo.com  from=pocketsmith.com; domainkeys=pass (ok); from=pocketsmith.com; dkim=pass (ok)
Authentication-Results: mta172.mail.ac4.yahoo.com  from=pocketsmith.com; domainkeys=fail (bad sig); from=pocketsmith.com; dkim=permerror (bad  sig)

This is because I had the DNS record setup for a key from our testing server, while I butchered my way through getting this setup (and writing this article).

It appears that mta137 has obtained the correct record, but mta172 has not yet got the correct record – it is using the old one. Gmail however only uses one server for the Auth testing: mx.google.com. This means that once this one server has the correct DNS entry cached, all is well. Trust Yahoo to make things harder ;)

So, I’m going to be patient, and wait before I remove that test call. And I’ll send through a lot more emails (around say, 10 – 15) from the application to my test yahoo address and check that all the mta’s are seeing the correct DKIM DNS record, in about 24 hours.

Remember – patience is key here – if you remove the test from the DNS record too quickly, you’re telling the world that you are 100% ready to go when you may not be!

And there you have it – you are one step closer to not being thrown in the spam folder :D

Update 6th July 2009 – I just sent through 15 test emails to the Yahoo test account, and all of them passed DomainKeys and DKIM authorisation. Success! Looks like Yahoo does like the caching of the DKIM DNS entry quite a lot, so give it 24 hours before you panic – particularly if you set a relatively high TTL on the  DNS record.