Restrict Amazon SES by domain name

This post is more than 6 years old.

Amazon Simple Email Service (SES) makes it easy, and cheap, to send emails reliably from a website. Here’s how to set it up for use with multiple domains.

When we set up Amazon SES for our website, we need to create an Amazon IAM user with API access. This will give us an API key and password that we can use to configure our application. On WordPress, for example, we would follow some simple instructions to configure the the WP SES plugin.

If we are managing multiple websites from one Amazon AWS account, there’s a problem: without some extra bits in their security policies, every one of those websites can send email that pretends to be from the other websites. For example, the shop.example.com website could send emails impersonating www.example.net (imagine those as separate clients… not good! and could be a big problem if a website gets hacked!)

But it’s relatively easy to restrict a website’s SES credentials so that it can only send emails for its own domain. We just need to add a Condition clause to the security policy. There’s quite a lot of scope for restricting what an IAM user can do by using conditions, and Amazon even has a page about controlling access to Amazon SES using conditions.

For our purposes, we want to limit the From address of all emails to be from our website’s domain. We can do that by adding a Condition for the FromAddress for strings that are like “*@example.net”, using the StringLike operator. Amazon has more information about available Condition operators and managing multiple key values in its IAM guide.

Here’s a policy script that lets a website check quota limits and statistics, and send from a specific domain. It’s simple JSON which can be pasted into the policy editor (after correcting the domain name, of course!)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ses:GetSendQuota",
                "ses:GetSendStatistics",
                "ses:SendEmail",
                "ses:SendRawEmail"
            ],
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "ses:FromAddress": "*@example.net"
                }
            }
        }
    ]
}

That stops a website using API access to send its emails from impersonating another website. But the API isn’t the only way to send emails through Amazon SES: we can also create users for SMTP access to Amazon SES, allowing pretty much any website that can send email to use Amazon SES. The IAM user we create for SMTP access must also have a security policy, and we can edit that policy in the inline editor to achieve the same result: add a Condition clause for the From address.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ses:SendRawEmail",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "ses:FromAddress": "*@example.net"
                }
            }
        }
    ]
}

With a simple Condition added to our security policies, job is done but only for the sender addresses we allow.