SNS topics should be encrypted at rest
SNS topics often carry sensitive payloads: PII in transactional notifications, secrets in deployment pipelines, or financial data in event-driven architectures. Without KMS encryption at rest, message content stored by SNS (including retained messages for retries and fanout) stays unencrypted in the service's internal storage. A misconfigured IAM policy or compromised credential could expose it.
Adding KMS encryption creates an authorization boundary. Even if an attacker gains read access to the underlying storage, they still need kms:Decrypt permission on the specific key. That separation of access is one of the most cost-effective data protection controls you can apply, at roughly $1/month per KMS key plus $0.03 per 10,000 requests.
Retrofit consideration
Enabling encryption on an existing SNS topic doesn't require recreation and won't disrupt the topic itself. The catch is permissions: publishing identities and the SNS service both need kms:GenerateDataKey and kms:Decrypt on the key before you apply. Miss this and the next publish attempt throws AccessDeniedException.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "sns" {
source = "soc2.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "pcidss.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "hipaa.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "gdpr.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "nist80053.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "nistcsf.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "fedrampmoderate.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "nist800171.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "awswellarchitected.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "cisacyberessentials.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "nydfs23.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "cccsmedium.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "acscism2023.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "eugmpannex11.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "cfrpart11.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "rbicybersecurity.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "fedramplow.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "hipaasecurity2003.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "iso270012013.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "nist80053rev4.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
module "sns" {
source = "pcidssv321.compliance.tf/terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
If you use terraform-aws-modules/sns/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "sns" {
source = "terraform-aws-modules/sns/aws"
version = ">=7.0.0"
name = "abc123"
}
Use AWS provider resources directly. See docs for the resources involved: aws_sns_topic.
resource "aws_sns_topic" "this" {
kms_master_key_id = "alias/aws/sns"
name = "pofix-abc123"
}
What this control checks
The control checks that the aws_sns_topic resource has kms_master_key_id set to a non-empty value. That value can be a key ID, key ARN, or alias pointing to either a customer-managed KMS key or the AWS-managed SNS key. It fails when the argument is omitted or empty.
Using a customer-managed key is recommended for key rotation control and cross-account access policies. With that approach, the aws_kms_key key policy must grant SNS service access plus any publisher and subscriber permissions your integration requires.
Common pitfalls
Subscribers lack KMS permissions
Adding
kms_master_key_idchanges the access path for every producer and consumer, not just the topic itself. The SNS service needskms:GenerateDataKeyandkms:Decrypton the key. SQS subscriptions are the most common failure point: both the queue policy and the KMS key policy must allow the access path, and a gap in either causes delivery failures. Test end-to-end with a subscriber before rolling this out to production topics.AWS-managed key blocks cross-account access
Using
alias/aws/snsas thekms_master_key_idworks for single-account setups but prevents cross-account subscriptions because the AWS-managed key policy cannot be modified. If any subscriber lives in a different AWS account, use a customer-managedaws_kms_keywith explicit cross-account grants.Terraform import loses encryption setting
When importing an existing encrypted SNS topic with
terraform import, thekms_master_key_idattribute may not appear in state if the Terraform configuration block omits it. The nextterraform applywould then remove encryption. Always declarekms_master_key_idin the configuration before importing.FIFO topic ordering unaffected but throughput may change
KMS encryption on FIFO SNS topics adds per-message latency from KMS calls. High-throughput FIFO topics can hit KMS request rate limits, which are regional and account-specific. Check AWS Service Quotas before enabling encryption on any topic publishing at scale and request increases proactively.
Audit evidence
Config rule evaluation results are the primary artifact: all in-scope topics should show COMPLIANT against SNS_ENCRYPTED_KMS or an equivalent custom rule. Console screenshots of each topic's Encryption section showing a KMS key ARN work as supplementary evidence. CloudTrail SetTopicAttributes events with KmsMasterKeyId in the request parameters establish when encryption was enabled and who enabled it. A Security Hub findings export filtered to this control across all active regions covers the continuous compliance requirement.
Framework-specific interpretation
SOC 2: CC6.1 and CC6.7 are what SOC 2 Type II auditors reach for when reviewing messaging infrastructure. Evidence of a KMS key ARN on every in-scope topic, combined with key policy documentation, satisfies both criteria.
PCI DSS v4.0: Requirement 3.4 expects stored account data to be rendered unreadable. If SNS topics carry card data in event payloads, KMS encryption addresses that expectation. Note that Requirement 3.5 separately governs the key management practices around those KMS keys, so key policy and rotation procedures need their own controls.
HIPAA Omnibus Rule 2013: Under 45 CFR 164.312(a)(2)(iv), encryption is an addressable implementation specification for ePHI at rest. SNS topics carrying patient notification events or health system integration messages need KMS encryption in place. An unencrypted messaging layer will surface as a gap in a HIPAA risk analysis.
GDPR: Article 32(1)(a) lists encryption as one of the appropriate technical measures for protecting personal data. When SNS topics carry information about EU data subjects, KMS at rest limits exposure and can affect the breach notification threshold under Article 34.
NIST SP 800-53 Rev 5: SC-28 requires cryptographic mechanisms to prevent unauthorized disclosure of information at rest. KMS on SNS provides FIPS 140-2 validated encryption for message data stored within the service, satisfying this control.
NIST Cybersecurity Framework v2.0: PR.DS in the Protect function calls for data-at-rest protections scaled to the organization's risk posture. Encrypting SNS topics covers message payloads stored temporarily during retry and fanout operations.
FedRAMP Moderate Baseline Rev 4: At the Moderate baseline, SC-28 mandates FIPS-validated encryption for all federal data at rest. KMS meets that bar when configured with FIPS-validated modules, making this the standard approach for FedRAMP-authorized SNS usage.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
sns_topic_encrypted_at_restAWS Config Managed Rule:
SNS_ENCRYPTED_KMSCheckov Check:
CKV_AWS_26Powerpipe Control:
aws_compliance.control.sns_topic_encrypted_at_restProwler Check:
sns_topics_kms_encryption_at_rest_enabledAWS Security Hub Control:
SNS.1KICS Queries:
28545147-2fc6-42d5-a1f9-cf226658e591,b1a72f66-2236-4f3b-87ba-0da1b366956fTrivy Checks:
AWS-0095,AWS-0136
Last reviewed: 2026-03-09