Scaling Postfix on AWS with Elastic Load Balancing

Agari’s mission to solve email phishing often presents unique technical challenges. Our data ingestion process involves coping with large-scale inbound SMTP traffic. We’ve chosen Postfix as our MTA of choice. The traditional way to scale SMTP is simply to maintain MX records for multiple ingestion paths. This works but can be very limiting. Agari’s Amazon Web Services-hosted infrastructure provides some other alternatives. Advantages to using Amazon’s Elastic Load Balancer for handling SMTP traffic include simple load-based autoscaling, load distribution that’s aware of distribution across availability zones and even integration with Route53’s latency-based routing for distributing load across regions. The primary downside to using a TCP load-balancer in front of your MTA is losing the source IP in your mail logs. However, there’s a workaround.

Amazon ELB supports Proxy Protocol. This will write a TCP header that can later be read by applications which support it. Luckily for us, Postfix supports Proxy Protocol in versions 2.10 and above.

Unfortunately, the AWS web console doesn’t have an easy way to enable Proxy Protocol, but it’s pretty easy to accomplish with the AWS CLI tools. First, we need to create a policy:

aws elb create-load-balancer-policy --load-balancer-name YOUR-ELB-HERE --policy-name EnableProxyProtocol --policy-type-name ProxyProtocolPolicyType --policy-attributes AttributeName=ProxyProtocol,AttributeValue=True

Then, apply the policy:

aws elb set-load-balancer-policies-for-backend-server --load-balancer-name YOUR-ELB-HERE --instance-port 25 --policy-names EnableProxyProtocol

We can check to make sure our changes were applied:

aws elb describe-load-balancers --load-balancer-name YOUR-ELB-HERE

You should see EnableProxyProtocol listed under policies. That’s it for the ELB side, now you just need to enable Proxy Protocol on Postfix. In your /etc/postfix/ you’ll need to add the line:

postscreen_upstream_proxy_protocol = haproxy

And then your service configuration in /etc/ should look something like this:

smtp inet n - - - 1 postscreen smtpd pass - - - - - smtpd

Restart Postfix and you’re done! You should immediately see proper source IP start to show up in your mail.log.