Skip to main content

Enable KMS Encryption at Rest for SNS Topics

Overview

This check verifies that your Amazon SNS (Simple Notification Service) topics are encrypted at rest using AWS KMS (Key Management Service). When an SNS topic lacks a configured KMS key (specifically missing the KmsMasterKeyId attribute), messages stored in the topic are not encrypted, leaving sensitive data potentially exposed.

Encryption at rest ensures that message data is protected while stored in AWS infrastructure, adding an important layer of defense for your messaging workflows.

Risk

Without KMS encryption enabled on your SNS topics:

  • Data exposure: Message bodies remain unencrypted at rest, which could expose sensitive information if storage is compromised
  • Insider threat vulnerability: Compromised service components or malicious insiders could access plaintext messages
  • Compliance gaps: Many regulatory frameworks (HIPAA, PCI-DSS, SOC 2) require encryption of data at rest
  • Limited audit trail: You lose the ability to track key usage through AWS CloudTrail, making it harder to detect unauthorized access
  • No key rotation: Without KMS, you cannot benefit from automated key rotation policies

Remediation Steps

Prerequisites

You need:

  • AWS Console access with permissions to modify SNS topics, OR
  • AWS CLI configured with appropriate credentials
  • Permission to use the KMS key you plan to use for encryption
Required IAM permissions

Your IAM user or role needs these permissions:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sns:SetTopicAttributes",
"sns:GetTopicAttributes",
"sns:ListTopics"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"kms:DescribeKey",
"kms:GenerateDataKey",
"kms:Decrypt"
],
"Resource": "<your-kms-key-arn>"
}
]
}

AWS Console Method

  1. Open the SNS console: Go to Amazon SNS Console

  2. Navigate to Topics: In the left sidebar, click Topics

  3. Select your topic: Click on the name of the topic you want to encrypt

  4. Edit the topic: Click the Edit button in the top right corner

  5. Enable encryption:

    • Scroll down to the Encryption section
    • Check the box for Enable encryption
    • For Customer master key (CMK), choose one of:
      • AWS managed key (alias/aws/sns) - simplest option, managed by AWS
      • Customer managed key - select your own KMS key for more control
  6. Save changes: Click Save changes at the bottom of the page

  7. Verify: You should see a confirmation message, and the topic details will show the KMS key ID

AWS CLI (optional)

Enable encryption on an existing topic

Use the set-topic-attributes command to enable KMS encryption:

# Using the AWS-managed SNS key (simplest option)
aws sns set-topic-attributes \
--region us-east-1 \
--topic-arn arn:aws:sns:us-east-1:123456789012:my-topic \
--attribute-name KmsMasterKeyId \
--attribute-value alias/aws/sns
# Using a customer-managed KMS key (more control)
aws sns set-topic-attributes \
--region us-east-1 \
--topic-arn arn:aws:sns:us-east-1:123456789012:my-topic \
--attribute-name KmsMasterKeyId \
--attribute-value arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012

Create a new encrypted topic

# Create topic with encryption enabled
aws sns create-topic \
--region us-east-1 \
--name my-encrypted-topic \
--attributes KmsMasterKeyId=alias/aws/sns

List all topics to find unencrypted ones

# List all topics
aws sns list-topics --region us-east-1

# Check encryption status of a specific topic
aws sns get-topic-attributes \
--region us-east-1 \
--topic-arn arn:aws:sns:us-east-1:123456789012:my-topic \
--query 'Attributes.KmsMasterKeyId'
CloudFormation (optional)

Create an encrypted SNS topic

AWSTemplateFormatVersion: '2010-09-09'
Description: SNS Topic with KMS encryption at rest enabled

Parameters:
TopicName:
Type: String
Description: Name of the SNS topic
Default: my-encrypted-topic

KmsKeyId:
Type: String
Description: KMS key ID, ARN, or alias for encryption
Default: alias/aws/sns

Resources:
EncryptedSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Ref TopicName
KmsMasterKeyId: !Ref KmsKeyId
Tags:
- Key: Environment
Value: Production
- Key: Encryption
Value: Enabled

Outputs:
TopicArn:
Description: ARN of the encrypted SNS topic
Value: !Ref EncryptedSNSTopic
Export:
Name: !Sub '${AWS::StackName}-TopicArn'

TopicName:
Description: Name of the SNS topic
Value: !GetAtt EncryptedSNSTopic.TopicName

Deploy the stack

aws cloudformation deploy \
--region us-east-1 \
--stack-name encrypted-sns-topic \
--template-file template.yaml \
--parameter-overrides TopicName=my-encrypted-topic KmsKeyId=alias/aws/sns

Using a customer-managed KMS key

If you want to use a customer-managed key for enhanced control, add a KMS key resource:

AWSTemplateFormatVersion: '2010-09-09'
Description: SNS Topic with customer-managed KMS key

Resources:
SNSEncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key for SNS topic encryption
EnableKeyRotation: true
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
- Sid: Allow SNS to use the key
Effect: Allow
Principal:
Service: sns.amazonaws.com
Action:
- kms:GenerateDataKey*
- kms:Decrypt
Resource: '*'

SNSEncryptionKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/sns-encryption-key
TargetKeyId: !Ref SNSEncryptionKey

EncryptedSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: my-encrypted-topic
KmsMasterKeyId: !Ref SNSEncryptionKey
Terraform (optional)

Basic encrypted SNS topic

terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0"
}
}
}

variable "topic_name" {
description = "Name of the SNS topic"
type = string
default = "my-encrypted-topic"
}

variable "kms_key_id" {
description = "KMS key ID, ARN, or alias for encryption (use 'alias/aws/sns' for AWS-managed key)"
type = string
default = "alias/aws/sns"
}

variable "tags" {
description = "Tags to apply to the SNS topic"
type = map(string)
default = {
Environment = "Production"
Encryption = "Enabled"
}
}

resource "aws_sns_topic" "encrypted" {
name = var.topic_name
kms_master_key_id = var.kms_key_id
tags = var.tags
}

output "topic_arn" {
description = "ARN of the encrypted SNS topic"
value = aws_sns_topic.encrypted.arn
}

output "topic_name" {
description = "Name of the SNS topic"
value = aws_sns_topic.encrypted.name
}

With customer-managed KMS key

resource "aws_kms_key" "sns_encryption" {
description = "KMS key for SNS topic encryption"
deletion_window_in_days = 30
enable_key_rotation = true

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = "kms:*"
Resource = "*"
},
{
Sid = "Allow SNS to use the key"
Effect = "Allow"
Principal = {
Service = "sns.amazonaws.com"
}
Action = [
"kms:GenerateDataKey*",
"kms:Decrypt"
]
Resource = "*"
}
]
})

tags = {
Name = "sns-encryption-key"
}
}

resource "aws_kms_alias" "sns_encryption" {
name = "alias/sns-encryption-key"
target_key_id = aws_kms_key.sns_encryption.key_id
}

resource "aws_sns_topic" "encrypted" {
name = "my-encrypted-topic"
kms_master_key_id = aws_kms_key.sns_encryption.arn

tags = {
Environment = "Production"
Encryption = "Enabled"
}
}

data "aws_caller_identity" "current" {}

Apply the configuration

terraform init
terraform plan
terraform apply

Verification

After enabling encryption, verify it was applied successfully:

  1. In the AWS Console:

    • Navigate to your SNS topic
    • Check the Encryption section in the topic details
    • You should see the KMS key ID or alias displayed
  2. Re-run the Prowler check:

    prowler aws --check sns_topics_kms_encryption_at_rest_enabled
CLI verification commands
# Verify encryption is enabled on a specific topic
aws sns get-topic-attributes \
--region us-east-1 \
--topic-arn arn:aws:sns:us-east-1:123456789012:my-topic \
--query 'Attributes.KmsMasterKeyId' \
--output text

# Expected output: alias/aws/sns (or your KMS key ARN)
# If empty or "None", encryption is not enabled

# Check all topics for encryption status
for topic in $(aws sns list-topics --region us-east-1 --query 'Topics[].TopicArn' --output text); do
key=$(aws sns get-topic-attributes --topic-arn "$topic" --query 'Attributes.KmsMasterKeyId' --output text 2>/dev/null)
if [ "$key" == "None" ] || [ -z "$key" ]; then
echo "UNENCRYPTED: $topic"
else
echo "ENCRYPTED ($key): $topic"
fi
done

Additional Resources

Notes

  • AWS-managed key vs. Customer-managed key: The AWS-managed key (alias/aws/sns) is the simplest option and requires no additional setup. However, customer-managed keys provide more control over key policies, rotation schedules, and access auditing.

  • No service interruption: Enabling encryption on an existing topic does not interrupt message delivery or require topic recreation.

  • Subscriber compatibility: Subscribers do not need to change how they receive messages. Decryption is handled transparently by AWS.

  • Cross-account access: If your topic has cross-account subscribers, ensure the KMS key policy allows those accounts to use the key for decryption.

  • Cost consideration: Using a customer-managed KMS key incurs KMS API charges. The AWS-managed SNS key is free for SNS encryption operations.

  • FIFO topics: Encryption works the same way for both standard and FIFO SNS topics.