Feedback Loops in Amazon Simple Email Service (SES) (Part 2)

In Part 1, I explained the general feedback mechanisms that are available in Amazon Simple Email Service (SES), and compared their strengths and weaknesses. Now I will explain the different configuration methods that can be used to select a feedback mechanism.

Domain-Level SNS Configuration

You can configure Simple Notification Service (SNS) feedback for an entire domain. Select one of your domains and expand the Notifications section. You can select an SNS topic for bounces, complaints, and deliveries. This is the most straightforward way to enable SNS feedback if you want to treat all email for a domain in exactly the same way.

Address-Specific SNS Configuration

In some cases, you should not treat all email in the domain in the same way. For example, you might have different software environments (dev, staging, production) that use the same domain, but send from different email addresses. Email bounces from Dev should go to developers, bounces from Staging to QA, and bounces from Production to the customer service team. You also might use the same domain for email marketing (not a great idea), and that feedback should go to the marketing team. You can configure each verified email address in SES with a different set of SNS topics.

Configuration Sets

SES Configuration Sets are my least favorite option. However, configuration sets are the only way to send email statistics to CloudWatch or to S3 via Kinesis Firehose, so sometimes you are stuck with using them. The application of a Configuration Set to an email message is determined by setting a special header when submitting the email to SES:

X-SES-CONFIGURATION-SET: ConfigSet

There are several problems with Configuration Sets:

  • Not transparent. In the SES interface, you can see the configuration sets, but you can’t see to which emails each set is being applied.
  • Too easy for a server admin to accidentally break the SMTP server configuration and disable monitoring.
  • A server admin has to get involved if the configuration set needs to be changed.
  • Configuring SMTP servers to set customer headers may be tricky.

I recommend configuring each domain or specific email addresses with SNS topics. Only use configuration sets for getting email statistics into a CloudWatch dashboard.

Write-only bucket policy example for Amazon S3

Amazon S3 is widely used as a repository for backups. Backups are an important aspect of a resilient system, but they are also a potential security vulnerability. Unauthorized access to a database backup is still a PCI or HIPAA violation. The permissions on Amazon S3 should be configured to minimize access to critical backups. My strategy is to use IAM to create a backup user with no password (cannot log in to AWS) and a single access key. The backup user’s access key is used to put backup files into S3. The S3 bucket policy is configured to allow “write-only” access for the backup user. The backups cannot be obtained, even if the backup user’s credentials are compromised.

It is fairly difficult to figure out how to create a “write only” bucket policy. The policy shown below is the “write only” policy that I use. It consists of two statements: BucketPermissions gives a user ability to locate the bucket (necessary to do anything in the bucket) and list its contents (to verify that a backup was written). You may remove the s3:ListBucket action if true write-only access is desired. The statement called ObjectPermissions allows the user to create objects in the specified bucket.

{
 "Version": "2012-10-17",
 "Id": "YOUR_POLICY_ID_NUMBER",
 "Statement": [
 {
 "Sid": "BucketPermissions",
 "Effect": "Allow",
 "Principal": {
 "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:user/USERNAME"
 },
 "Action": [
 "s3:ListBucket",
 "s3:GetBucketLocation"
 ],
 "Resource": "arn:aws:s3:::BUCKET_NAME"
 },
 {
 "Sid": "ObjectPermissions",
 "Effect": "Allow",
 "Principal": {
 "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:user/USERNAME"
 },
 "Action": [
 "s3:PutObjectAcl",
 "s3:PutObject"
 ],
 "Resource": "arn:aws:s3:::BUCKET_NAME/*"
 }
 ]
}

S3 does one odd thing: this policy allows the user to verify that a particular object exists in S3, even if they don’t have permission to GET the object. For example, running the command:

s3cmd get s3://BUCKET_NAME/PATH/BACKUP_FILE_NAME.tgz

Produces the output:

s3://BUCKET_NAME/PATH/BACKUP_FILE_NAME.tgz -> ./BACKUP_FILE_NAME.tgz
ERROR: S3 error: Unknown error

It appears that the file is being downloaded, but in fact only an empty file is created! While it is generally a bad idea to allow unauthorized users to guess file names, it is not a real problem in this case, because the backup user’s credentials would have to be compromised even to confirm the existence of a file stored in S3.

References

  1. AWS Bucket Policy Reference
  2. S3 Encryption (high recommended)