๐ I Fixed Something AWS Says Doesn't Work
Friday, July 10, 20264 min read

Encrypted SNS topics, KMS denials, and a feature called Forward Access Sessions
I was codifying our AWS Config setup with Terraform and decided to encrypt the SNS topic (Simple Notification Service, the thing that receives Config findings and fans them out to subscribers) with a customer-managed KMS key (Key Management Service, AWS's encryption key manager). Standard stuff.
Notifications stopped arriving. No error in Config, no CloudTrail denial, no alarm. Just silence. SNS delivery status was flipping to FAILURE, but delivery-status logging is off by default so nobody saw it.
The fix turned out to be a single principal in a KMS key policy. But figuring out why it's needed is the interesting part.
What you'd expect to happen#
When Config publishes to an encrypted SNS topic, you'd think SNS calls KMS to encrypt the message, KMS sees sns.amazonaws.com as the caller, you grant encrypt permissions to sns.amazonaws.com, done.
That's not what happens.
SNS uses something called Forward Access Sessions (FAS). Instead of calling KMS as itself, SNS forwards the identity of whoever originally published the message. So KMS ends up checking its key policy against the service that started the chain, not the one doing the encryption.
In my case: Config publishes to SNS, SNS tries to encrypt with KMS, but KMS sees config.amazonaws.com as the caller, not sns.amazonaws.com. If your KMS key policy only grants to sns.amazonaws.com, the request is denied. And SNS swallows the error instead of passing it back to Config, so nothing tells you it happened.
How I figured it out#
I spent a while going through the usual debugging. KMS key policy looked right, SNS topic policy looked right, Config was configured correctly. Everything should have worked.
Then I found this Reddit thread where someone had a similar issue but with S3 event notifications to an encrypted SNS topic. One of the comments explained that SNS uses FAS to call KMS, so KMS actually sees s3.amazonaws.com instead of sns.amazonaws.com. That clicked for me immediately because my case was the same pattern, just with Config instead of S3. The KMS policy wasn't wrong, it was just granting to the wrong principal.
The fix#
Two policy changes.
KMS key policy grant to the publishing service, not just the encrypting one:
principals {
type = "Service"
identifiers = ["config.amazonaws.com", "sns.amazonaws.com"]
}You need both. config.amazonaws.com is what KMS actually sees via FAS. sns.amazonaws.com is still needed because SNS calls KMS directly for things like GenerateDataKey.
SNS topic policy Config publishes as a service principal, not an IAM principal, so the default AWS:SourceOwner condition doesn't cover it. You need an explicit allow:
statement {
sid = "AllowConfigPublish"
actions = ["SNS:Publish"]
principals {
type = "Service"
identifiers = ["config.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "AWS:SourceAccount"
values = [local.account_id]
}
}After applying both, Config notifications started coming through again right away.
Why you won't find this in the docs#
The AWS Config docs straight up say "Encrypted Amazon SNS not supported." What that really means is they don't test this path and won't help you debug it. But FAS works at the IAM layer so it doesn't care what the Config support matrix says.
The SNS encryption docs have a buried compatibility table listing services that behave differently with encrypted topics. Config is on that list, but the docs never connect it to FAS or explain why the KMS call fails. The pieces are spread across three different doc pages and you have to connect the dots yourself.
Which services have this same problem?#
Not all services do this the same way. Here's what I found:
- S3 event notifications โ s3.amazonaws.com, uses FAS, works with service principal
- CloudWatch Alarms โ cloudwatch.amazonaws.com, uses FAS, works with service principal
- EventBridge โ events.amazonaws.com, uses FAS, but can't use aws:SourceAccount condition on KMS
- AWS Config โ config.amazonaws.com, uses FAS, docs say "unsupported" but works
- EC2 Auto Scaling โ needs IAM role ARN, not service principal
- CodePipeline โ needs IAM role ARN
- Elastic Beanstalk โ needs IAM role ARN
If you're wiring up a new service to an encrypted SNS topic and notifications aren't arriving, check this list before you start debugging your Terraform.
FAS means KMS doesn't see the service doing the encryption. It sees the service that caused it. One extra principal in a KMS key policy, and you're done. The docs say it doesn't work. It does.