-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sns): sns topics no http subscriptions (#4095)
Co-authored-by: Sergio <[email protected]>
- Loading branch information
1 parent
533f7cb
commit 98b7df6
Showing
6 changed files
with
361 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
32 changes: 32 additions & 0 deletions
32
...cription_not_using_http_endpoints/sns_subscription_not_using_http_endpoints.metadata.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"Provider": "aws", | ||
"CheckID": "sns_subscription_not_using_http_endpoints", | ||
"CheckTitle": "Ensure there are no SNS subscriptions using HTTP endpoints", | ||
"CheckType": [], | ||
"ServiceName": "sns", | ||
"SubServiceName": "", | ||
"ResourceIdTemplate": "arn:aws:sns:region:account-id:topic", | ||
"Severity": "high", | ||
"ResourceType": "AwsSNSTopic", | ||
"Description": "Ensure there are no SNS subscriptions using HTTP endpoints", | ||
"Risk": "When you use HTTPS, messages are automatically encrypted during transit, even if the SNS topic itself isn't encrypted. Without HTTPS, a network-based attacker can eavesdrop on network traffic or manipulate it using an attack such as man-in-the-middle.", | ||
"RelatedUrl": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", | ||
"Remediation": { | ||
"Code": { | ||
"CLI": "", | ||
"NativeIaC": "", | ||
"Other": "", | ||
"Terraform": "" | ||
}, | ||
"Recommendation": { | ||
"Text": "To enforce only encrypted connections over HTTPS, add the aws:SecureTransport condition in the IAM policy that's attached to unencrypted SNS topics. This forces message publishers to use HTTPS instead of HTTP", | ||
"Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit" | ||
} | ||
}, | ||
"Categories": [ | ||
"encryption" | ||
], | ||
"DependsOn": [], | ||
"RelatedTo": [], | ||
"Notes": "" | ||
} |
31 changes: 31 additions & 0 deletions
31
...ns/sns_subscription_not_using_http_endpoints/sns_subscription_not_using_http_endpoints.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from prowler.lib.check.models import Check, Check_Report_AWS | ||
from prowler.providers.aws.services.sns.sns_client import sns_client | ||
|
||
|
||
class sns_subscription_not_using_http_endpoints(Check): | ||
def execute(self): | ||
findings = [] | ||
for topic in sns_client.topics: | ||
for subscription in topic.subscriptions: | ||
if subscription.arn == "PendingConfirmation": | ||
continue | ||
report = Check_Report_AWS(self.metadata()) | ||
report.region = topic.region | ||
report.resource_id = subscription.id | ||
report.resource_arn = subscription.arn | ||
report.resource_tags = topic.tags | ||
report.resource_details = topic.arn | ||
report.status = "PASS" | ||
report.status_extended = ( | ||
f"Subscription {subscription.arn} is using an HTTPS endpoint." | ||
) | ||
|
||
if subscription.protocol == "http": | ||
report.status = "FAIL" | ||
report.status_extended = ( | ||
f"Subscription {subscription.arn} is using an HTTP endpoint." | ||
) | ||
|
||
findings.append(report) | ||
|
||
return findings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
234 changes: 234 additions & 0 deletions
234
...s_subscription_not_using_http_endpoints/sns_subscription_not_using_http_endpoints_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
from unittest import mock | ||
from uuid import uuid4 | ||
|
||
from prowler.providers.aws.services.sns.sns_service import Subscription, Topic | ||
from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1 | ||
|
||
kms_key_id = str(uuid4()) | ||
topic_name = "test-topic" | ||
topic_arn = f"arn:aws:sns:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:{topic_name}" | ||
subscription_id_1 = str(uuid4()) | ||
subscription_id_2 = str(uuid4()) | ||
subscription_arn_1 = f"{topic_arn}:{subscription_id_1}" | ||
subscription_arn_2 = f"{topic_arn}:{subscription_id_2}" | ||
|
||
|
||
class Test_sns_subscription_not_using_http_endpoints: | ||
def test_no_topics(self): | ||
sns_client = mock.MagicMock | ||
sns_client.topics = [] | ||
with mock.patch( | ||
"prowler.providers.aws.services.sns.sns_service.SNS", | ||
sns_client, | ||
): | ||
from prowler.providers.aws.services.sns.sns_subscription_not_using_http_endpoints.sns_subscription_not_using_http_endpoints import ( | ||
sns_subscription_not_using_http_endpoints, | ||
) | ||
|
||
check = sns_subscription_not_using_http_endpoints() | ||
result = check.execute() | ||
assert len(result) == 0 | ||
|
||
def test_no_subscriptions(self): | ||
sns_client = mock.MagicMock | ||
subscriptions = [] | ||
sns_client.topics = [] | ||
sns_client.topics.append( | ||
Topic( | ||
arn=topic_arn, | ||
name=topic_name, | ||
kms_master_key_id=kms_key_id, | ||
region=AWS_REGION_EU_WEST_1, | ||
subscriptions=subscriptions, | ||
) | ||
) | ||
|
||
with mock.patch( | ||
"prowler.providers.aws.services.sns.sns_service.SNS", | ||
sns_client, | ||
): | ||
from prowler.providers.aws.services.sns.sns_subscription_not_using_http_endpoints.sns_subscription_not_using_http_endpoints import ( | ||
sns_subscription_not_using_http_endpoints, | ||
) | ||
|
||
check = sns_subscription_not_using_http_endpoints() | ||
result = check.execute() | ||
assert len(result) == 0 | ||
|
||
def test_subscriptions_with_pending_confirmation(self): | ||
sns_client = mock.MagicMock | ||
subscriptions = [] | ||
subscriptions.append( | ||
Subscription( | ||
id="PendingConfirmation", | ||
arn="PendingConfirmation", | ||
owner=AWS_ACCOUNT_NUMBER, | ||
protocol="https", | ||
endpoint="https://www.endpoint.com", | ||
) | ||
) | ||
sns_client.topics = [] | ||
sns_client.topics.append( | ||
Topic( | ||
arn=topic_arn, | ||
name=topic_name, | ||
kms_master_key_id=kms_key_id, | ||
region=AWS_REGION_EU_WEST_1, | ||
subscriptions=subscriptions, | ||
) | ||
) | ||
|
||
with mock.patch( | ||
"prowler.providers.aws.services.sns.sns_service.SNS", | ||
sns_client, | ||
): | ||
from prowler.providers.aws.services.sns.sns_subscription_not_using_http_endpoints.sns_subscription_not_using_http_endpoints import ( | ||
sns_subscription_not_using_http_endpoints, | ||
) | ||
|
||
check = sns_subscription_not_using_http_endpoints() | ||
result = check.execute() | ||
assert len(result) == 0 | ||
|
||
def test_subscriptions_with_https(self): | ||
sns_client = mock.MagicMock | ||
subscriptions = [] | ||
subscriptions.append( | ||
Subscription( | ||
id=subscription_id_1, | ||
arn=subscription_arn_1, | ||
owner=AWS_ACCOUNT_NUMBER, | ||
protocol="https", | ||
endpoint="https://www.endpoint.com", | ||
) | ||
) | ||
sns_client.topics = [] | ||
sns_client.topics.append( | ||
Topic( | ||
arn=topic_arn, | ||
name=topic_name, | ||
kms_master_key_id=kms_key_id, | ||
region=AWS_REGION_EU_WEST_1, | ||
subscriptions=subscriptions, | ||
) | ||
) | ||
|
||
with mock.patch( | ||
"prowler.providers.aws.services.sns.sns_service.SNS", | ||
sns_client, | ||
): | ||
from prowler.providers.aws.services.sns.sns_subscription_not_using_http_endpoints.sns_subscription_not_using_http_endpoints import ( | ||
sns_subscription_not_using_http_endpoints, | ||
) | ||
|
||
check = sns_subscription_not_using_http_endpoints() | ||
result = check.execute() | ||
assert len(result) == 1 | ||
assert result[0].status == "PASS" | ||
assert ( | ||
result[0].status_extended | ||
== f"Subscription {subscription_arn_1} is using an HTTPS endpoint." | ||
) | ||
assert result[0].resource_id == subscription_id_1 | ||
assert result[0].resource_arn == subscription_arn_1 | ||
|
||
def test_subscriptions_with_http(self): | ||
sns_client = mock.MagicMock | ||
subscriptions = [] | ||
subscriptions.append( | ||
Subscription( | ||
id=subscription_id_2, | ||
arn=subscription_arn_2, | ||
owner=AWS_ACCOUNT_NUMBER, | ||
protocol="http", | ||
endpoint="http://www.endpoint.com", | ||
) | ||
) | ||
sns_client.topics = [] | ||
sns_client.topics.append( | ||
Topic( | ||
arn=topic_arn, | ||
name=topic_name, | ||
kms_master_key_id=kms_key_id, | ||
region=AWS_REGION_EU_WEST_1, | ||
subscriptions=subscriptions, | ||
) | ||
) | ||
|
||
with mock.patch( | ||
"prowler.providers.aws.services.sns.sns_service.SNS", | ||
sns_client, | ||
): | ||
from prowler.providers.aws.services.sns.sns_subscription_not_using_http_endpoints.sns_subscription_not_using_http_endpoints import ( | ||
sns_subscription_not_using_http_endpoints, | ||
) | ||
|
||
check = sns_subscription_not_using_http_endpoints() | ||
result = check.execute() | ||
assert len(result) == 1 | ||
assert result[0].status == "FAIL" | ||
assert ( | ||
result[0].status_extended | ||
== f"Subscription {subscription_arn_2} is using an HTTP endpoint." | ||
) | ||
assert result[0].resource_id == subscription_id_2 | ||
assert result[0].resource_arn == subscription_arn_2 | ||
|
||
def test_subscriptions_with_http_and_https(self): | ||
sns_client = mock.MagicMock | ||
subscriptions = [] | ||
subscriptions.append( | ||
Subscription( | ||
id=subscription_id_1, | ||
arn=subscription_arn_1, | ||
owner=AWS_ACCOUNT_NUMBER, | ||
protocol="https", | ||
endpoint="https://www.endpoint.com", | ||
) | ||
) | ||
subscriptions.append( | ||
Subscription( | ||
id=subscription_id_2, | ||
arn=subscription_arn_2, | ||
owner=AWS_ACCOUNT_NUMBER, | ||
protocol="http", | ||
endpoint="http://www.endpoint.com", | ||
) | ||
) | ||
sns_client.topics = [] | ||
sns_client.topics.append( | ||
Topic( | ||
arn=topic_arn, | ||
name=topic_name, | ||
kms_master_key_id=kms_key_id, | ||
region=AWS_REGION_EU_WEST_1, | ||
subscriptions=subscriptions, | ||
) | ||
) | ||
|
||
with mock.patch( | ||
"prowler.providers.aws.services.sns.sns_service.SNS", | ||
sns_client, | ||
): | ||
from prowler.providers.aws.services.sns.sns_subscription_not_using_http_endpoints.sns_subscription_not_using_http_endpoints import ( | ||
sns_subscription_not_using_http_endpoints, | ||
) | ||
|
||
check = sns_subscription_not_using_http_endpoints() | ||
result = check.execute() | ||
assert len(result) == 2 | ||
assert result[0].status == "PASS" | ||
assert ( | ||
result[0].status_extended | ||
== f"Subscription {subscription_arn_1} is using an HTTPS endpoint." | ||
) | ||
assert result[0].resource_id == subscription_id_1 | ||
assert result[0].resource_arn == subscription_arn_1 | ||
|
||
assert result[1].status == "FAIL" | ||
assert ( | ||
result[1].status_extended | ||
== f"Subscription {subscription_arn_2} is using an HTTP endpoint." | ||
) | ||
assert result[1].resource_id == subscription_id_2 | ||
assert result[1].resource_arn == subscription_arn_2 |