Sunday, December 18, 2016

Using AWS Simple Email Service (SES) for Inbound Mail

Oy! Good thing no one else can see THIS message!
We all know what a pain in the rump it is to setup, manage, and secure an inbound mail server.  It's a thankless job that is increasingly the point of attack for bad guys.  It's also possible that if you screw it up you might find yourself in front of Congress!

In our architectures, now more than ever, it is important to reduce the surface area for attacks. That means closing down as many access points to your network as possible.  SMTP running on port 25 is a gaping hole that most architects interested in securing their networks want turned off, like yesterday!

If you don't want to completely outsource your inbound mail to a managed service, AWS SES inbound email service is one way to have your cake and eat it too.   It's especially useful if you want to allow your application to receive mail but you don't necessarily want or need to host an email service that includes an IMAP or POP server.  You may only need to receive mail in which case AWS SES is the perfect solution.  Along with a scalable managed service, SES also includes spam filtering capabilities.

In this two part blog, we'll explore setting up a simple inbound mail handler for openbedrock.net using Amazon Web Services Simple Email Service (SES).

The Goal


Figure 1 - Using AWS SES for inbound mail
Let's see if we can use AWS SES for something simple like receiving mail for any email sent to  openbedrock.net and then forwarding the mail to another email provider for selected addresses.

There are certainly other ways to attach a domain to another email account, but using this process you can do a lot more than just forward mail.  The diagram on the left depicts our target architecture.

As you can see we have a few AWS resources we'll need to provision.  Here's a list:

  1. S3 bucket - mail.openbedrock.net
  2. SQS queue - openbedrock-mail
  3. SNS topic - ses-openbedrock
  4. EC2 instance (or a Lambda function) to process queue messages

S3 Bucket


You'll need to create and setup your S3 bucket in the region where you are operating.  Follow AWS recommendations to name your buckets in alignment with the domains you own.  In our case we'll setup the bucket mail.openbedrock.net.  The AWS SMTP endpoint we will use later will also be in the same region.  Additionally you'll need to setup some bucket policies so SES can write to your bucket.

{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "GiveSESPermissionToWriteEmail",
"Effect": "Allow",
"Principal": {
"Service": "ses.amazonaws.com"
},
"Action": [
"s3:PutObjectAcl",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::mail.openbedrock.net/*",
"Condition": {
"StringEquals": {
"aws:Referer": "your-account-number"
}
}
}
]
}

SQS


Next we'll setup an SQS queue named openbedrock-mail. You'll need to setup a policy to allow SNS to write a message to this queue.

{
  "Version": "2012-10-17",
  "Id": "arn:aws:sqs:us-east-1:your-account-number:openbedrock-mail/SQSDefaultPolicy",
  "Statement": [
    {
      "Sid": "Sid1482077151429",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "SQS:SendMessage",
      "Resource": "arn:aws:sqs:us-east-1:your-account-number:openbedrock-mail",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:sns:us-east-1:your-account-number:ses-openbedrock"
        }
      }
    }
  ]
}

SNS

Setup an SNS topic. The topic will be used in our Rule we create in the SES console.  Subscribe the SQS queue we created above to the SNS topic.


Figure 2 - SNS Setup (click to enlarge)
At this point, we've provisioned all of the resources necessary to have SES dispose of our mail once it receives it.  Before we can start sending mail to our domain however, there are a few more steps we need to follow.

  1. Setup the domain to receive mail in the SES console by verifying your domain.
  2. Point your MX record to Amazon's SMTP server
  3. Create and enable an SES Rule Set

Verify Your Domain


In the SES console, on the left hand side click on "Domains".  Then click the "Verify a New Domain" button.  You should see a screen that looks similar to the one below.
Figure 3


Figure 4
Enter the name of your domain and click the checkbox to generate the DKIM settings if you plan on sending email from your domain.

Once you click the "Verify This Domain" button you'll see a screen similar to the one shown in Figure 4.  If you're using Route 53 to manage the domain, click the "Use Route 53" button.  This will automatically insert the appropriate DNS records for you so that SES can verify you own the domain.  You can then begin using SES for inbound email.

Figure 5
If your domain is managed somewhere else like GoDaddy for example, you'll need to update your DNS records manually with that domain registrar. 


Setup the MX Record


After clicking the "Use Route 53" button you'll get a verification screen similar to the one shown in Figure 5.  Click the checkbox labeled "Email Receiving Record" to update your domain's MX record.  Now click the "Create Record Sets" button to complete the process.  SES will now verify your domain by looking for the signatures in the DNS records it inserted, proving you own the domain.

Again, if your domain is not being managed within Route 53 (shame on you!) then you'll need to update your MX record using your DNS provider's site. For the record (pardon the pun) I've moved all of my domains to AWS and manage them all with Route 53.  If you're working in the AWS environment do yourself a favor and learn about Route 53 and all of the benefits you can derive in your application stack from using it.  I think a Route 53 blog might be needed...

Create a Rule


Figure 6
We're almost ready to start receiving mail.  All we need to do now is set up a Rule Set.  Access the SES console and click on "Rules Sets" in the left hand menu.

Click "Create a Rule Set" to create a new rule set that we'll setup to tell SES to send our mail to our S3 bucket and create an SNS notification.  Enter the name of a new rule set and click the "Create a Rule Set" button.  You'll now have a new rule set that you can add rules to.  By default, this rule set is not active.  Click on the rule set name and we'll proceed to add our rule.
Figure 7

Click on the "Create a Rule" button.  You'll then see a screen that will walk you through the rule creation process.   First add a recipient.  This can be for one particular email address or if you do not prefix the domain with an email address, will apply to all email addresses sent to that domain.
Figure 8
For actions, we'll select the S3 bucket and SNS topics we created previously.

Figure 9




Figure 10
Click the "Next Step" button in the right hand corner to show the Rule Details display.  Enter a name for the rule and click "Next Step" to continue.  Review the rule and click "Create Rule" to finalize the rule.

Figure 11
Once you've created the rule set you'll need to make this the Active rule set.  Don't be fooled by the green "Enabled" label.  Your rule is enabled, but the Rule Set is not.  Go back to the SES "Rule Set" screen and click on your rule set.  Click on the "Set as Active Rule Set" button to complete the process.
Figure 12

You now have a Rule Set that should be active and should accept mail! Verify you can receive mail on your domain.

  1. Send an email to anyone@yourdomain.com. 
  2. Check the S3 bucket to see if you a file was written.
  3. Check your SQS queue to see if a message was delivered.

Troubleshooting


Verify your MX record is setup properly.  If you have access to a Linux command line, try this:

$ dig yourdomain.com mx

You should see something like:

[rlauer@openbedrock ~]$dig openbedrock.net mx

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.47.rc1.el6 <<>> openbedrock.net mx
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51705
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;openbedrock.net.               IN      MX

;; ANSWER SECTION:
openbedrock.net.        60      IN      MX      10 inbound-smtp.us-east-1.amazonaws.com.

;; Query time: 35 msec
;; SERVER: 10.0.0.2#53(10.0.0.2)
;; WHEN: Sun Dec 18 14:29:18 2016

;; MSG SIZE  rcvd: 85

If your MX record is not pointing to one of Amazon's SMTP endpoints, you need to make sure to get that squared away first.  Unless mail is actually getting to SES via Amazon's SMTP endpoint, you're not going to get very far.  If you're not seeing any mail in your S3 bucket, make sure you entered the recipient correctly (see Figure 8).   Your recipient domain must match the domain of the MX record you pointed at Amazon's SMTP endpoint.  Also make sure the SMTP endpoint and your bucket are in the same region.

Conclusion


So far we've setup a pipeline to get our mail, move it to an S3 bucket and notify us via SNS and SQS that we've got mail.  What next?   In part 2 of this series we'll setup a worker to read the SQS queue and forward the mail to another email provider.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.