Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions cloudsplaining/output/policy_finding.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from cloudsplaining.shared.constants import (
ACTIONS_THAT_RETURN_CREDENTIALS,
BYPASSES_NETWORK_CONTROLS_ACTIONS,
ISSUE_SEVERITY,
READ_ONLY_DATA_EXFILTRATION_ACTIONS,
RISK_DEFINITION,
Expand Down Expand Up @@ -77,6 +78,10 @@ def services_affected(self) -> list[str]:
for action in self.data_exfiltration:
service = action.partition(":")[0]
services_affected.add(service)
# Bypasses network controls; may be used for control-plane/API access paths
for action in self.bypasses_network_controls:
service = action.partition(":")[0]
services_affected.add(service)
return sorted(services_affected)

@property
Expand Down Expand Up @@ -108,6 +113,17 @@ def data_exfiltration(self) -> list[str]:
if action.lower() not in self.exclusions.exclude_actions
]

@property
def bypasses_network_controls(self) -> list[str]:
"""Returns actions that can bypass network layer controls in the policy, if present"""
return [
action
for action in self.policy_document.allows_specific_actions_without_constraints(
BYPASSES_NETWORK_CONTROLS_ACTIONS
)
if action.lower() not in self.exclusions.exclude_actions
]

@property
def service_wildcard(self) -> list[str]:
"""Determine if the policy gives access to all actions within a service - simple grepping"""
Expand Down Expand Up @@ -157,6 +173,16 @@ def results(self) -> dict[str, Any]:
else []
),
},
"BypassesNetworkControls": {
"severity": ISSUE_SEVERITY["BypassesNetworkControls"],
"description": RISK_DEFINITION["BypassesNetworkControls"],
"findings": (
self.bypasses_network_controls
if ISSUE_SEVERITY["BypassesNetworkControls"] in [x.lower() for x in self.severity]
or not self.severity
else []
),
},
"ResourceExposure": {
"severity": ISSUE_SEVERITY["ResourceExposure"],
"description": RISK_DEFINITION["ResourceExposure"],
Expand Down
10 changes: 10 additions & 0 deletions cloudsplaining/shared/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
"secretsmanager:GetSecretValue",
]

BYPASSES_NETWORK_CONTROLS_ACTIONS = [
"redshift:GetClusterCredentials",
]

ISSUE_SEVERITY = {
"PrivilegeEscalation": "high",
"DataExfiltration": "medium",
Expand All @@ -92,6 +96,7 @@
"AssumableByCrossAccountPrincipal": "medium",
"AssumableByAnyPrincipal": "critical",
"AssumableByAnyPrincipalWithConditions": "medium",
"BypassesNetworkControls": "medium",
}

RISK_DEFINITION = {
Expand All @@ -105,6 +110,11 @@
"AssumableByCrossAccountPrincipal": "<p>IAM Roles that can be assumed from other AWS accounts can present a greater risk than roles that can only be assumed within the same AWS account. This is especially true if the trusting account is not owned by your organization.</p>",
"AssumableByAnyPrincipal": "<p>IAM Roles that can be assumed by any principal (i.e. Principal: '*') present a very high risk and should be remediated immediately.</p>",
"AssumableByAnyPrincipalWithConditions": "<p>IAM Roles that can be assumed by any principal (i.e. Principal: '*') but have conditions present can lead to unexpected outcomes. The conditions should be carefully reviewed to ensure they are not overly permissive.</p>",
"BypassesNetworkControls": (
"<p>These policies allow IAM actions that can access resources via AWS-managed control planes or service APIs "
"without requiring direct network access to the target (for example, bypassing VPC Security Groups and "
"NACLs). This can make traditional network-layer protections ineffective for these access paths.</p>"
),
}

PRIVILEGE_ESCALATION_METHODS = {
Expand Down
35 changes: 29 additions & 6 deletions test/command/test_scan_policy_file.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import unittest
import os
import json

from cloudsplaining.command.scan_policy_file import scan_policy
from cloudsplaining.shared.constants import DEFAULT_EXCLUSIONS_CONFIG
from cloudsplaining.shared.exclusions import DEFAULT_EXCLUSIONS, Exclusions

BYPASSES_NETWORK_CONTROLS_DESCRIPTION = (
"<p>These policies allow IAM actions that can access resources via AWS-managed control planes or service APIs "
"without requiring direct network access to the target (for example, bypassing VPC Security Groups and NACLs). "
"This can make traditional network-layer protections ineffective for these access paths.</p>"
)


class PolicyFileTestCase(unittest.TestCase):
Expand Down Expand Up @@ -59,6 +62,11 @@ def test_policy_file(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": [],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"ServiceWildcard": {
"severity": "medium",
"description": '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>',
Expand Down Expand Up @@ -111,6 +119,11 @@ def test_excluded_actions_scan_policy_file(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": ["s3:GetObject"],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"ServiceWildcard": {
"severity": "medium",
"description": '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>',
Expand Down Expand Up @@ -161,6 +174,11 @@ def test_excluded_actions_scan_policy_file_v2(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": ["s3:GetObject"],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"CredentialsExposure": {
"severity": "high",
"description": "<p>Credentials Exposure actions return credentials as part of the API response , such as ecr:GetAuthorizationToken, iam:UpdateAccessKey, and others. The full list is maintained here: https://gist.github.com/kmcquade/33860a617e651104d243c324ddf7992a</p>",
Expand Down Expand Up @@ -215,7 +233,7 @@ def test_checkov_gh_990_condition_restricted_action(self):
}
exclusions_cfg_custom = {}
results = scan_policy(test_policy, exclusions_cfg_custom)
print(json.dumps(results, indent=4))
# print(json.dumps(results, indent=4))
self.assertListEqual(results.get("InfrastructureModification")["findings"], [])
self.assertListEqual(results.get("DataExfiltration")["findings"], [])
self.assertListEqual(results.get("ServicesAffected"), [])
Expand All @@ -232,7 +250,7 @@ def test_checkov_gh_990_condition_restricted_action(self):
],
}
results = scan_policy(test_policy_without_condition, exclusions_cfg_custom)
print(json.dumps(results, indent=4))
# print(json.dumps(results, indent=4))
self.assertListEqual(results.get("InfrastructureModification")["findings"], [])
self.assertListEqual(results.get("DataExfiltration")["findings"], ["s3:GetObject"])
self.assertListEqual(results.get("ServicesAffected"), ["s3"])
Expand Down Expand Up @@ -308,6 +326,11 @@ def test_gh_254_all_risky_actions_scan_policy(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": ["s3:GetObject"],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"CredentialsExposure": {
"severity": "high",
"description": "<p>Credentials Exposure actions return credentials as part of the API response , such as ecr:GetAuthorizationToken, iam:UpdateAccessKey, and others. The full list is maintained here: https://gist.github.com/kmcquade/33860a617e651104d243c324ddf7992a</p>",
Expand Down
50 changes: 47 additions & 3 deletions test/output/test_policy_finding.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import unittest
import json

from cloudsplaining.output.policy_finding import PolicyFinding
from cloudsplaining.scan.policy_document import PolicyDocument
from cloudsplaining.shared.exclusions import Exclusions

BYPASSES_NETWORK_CONTROLS_DESCRIPTION = (
"<p>These policies allow IAM actions that can access resources via AWS-managed control planes or service APIs "
"without requiring direct network access to the target (for example, bypassing VPC Security Groups and NACLs). "
"This can make traditional network-layer protections ineffective for these access paths.</p>"
)


class TestPolicyFinding(unittest.TestCase):
def test_policy_finding_for_data_exfiltration(self):
Expand All @@ -12,8 +18,6 @@ def test_policy_finding_for_data_exfiltration(self):
"Statement": [{"Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "*"}],
}
policy_document = PolicyDocument(test_policy)
# (1) If the user is a member of an excluded group, return True

exclusions_cfg = dict(users=["obama"], groups=["exclude-group"], roles=["MyRole"], policies=["exclude-policy"])
exclusions = Exclusions(exclusions_cfg)
policy_finding = PolicyFinding(policy_document, exclusions)
Expand All @@ -35,6 +39,11 @@ def test_policy_finding_for_data_exfiltration(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": ["s3:GetObject"],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"ServiceWildcard": {
"severity": "medium",
"description": '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>',
Expand Down Expand Up @@ -79,6 +88,11 @@ def test_policy_finding_for_resource_exposure(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": [],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"ServiceWildcard": {
"severity": "medium",
"description": '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>',
Expand Down Expand Up @@ -128,6 +142,11 @@ def test_policy_finding_for_privilege_escalation(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": [],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"ServiceWildcard": {
"severity": "medium",
"description": '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>',
Expand Down Expand Up @@ -186,6 +205,11 @@ def test_finding_actions_excluded(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": [],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"ServiceWildcard": {
"severity": "medium",
"description": '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>',
Expand Down Expand Up @@ -224,6 +248,11 @@ def test_finding_actions_excluded(self):
"description": '<div style="text-align:left"><p>Policies with Data Exfiltration potential allow certain read-only IAM actions without resource constraints, such as <code>s3:GetObject</code>, <code>ssm:GetParameter*</code>, or <code>secretsmanager:GetSecretValue</code>. <br> <ul> <li>Unrestricted <code>s3:GetObject</code> permissions has a long history of customer data leaks.</li> <li><code>ssm:GetParameter*</code> and <code>secretsmanager:GetSecretValue</code> are both used to access secrets.</li> <li><code>rds:CopyDBSnapshot</code> and <code>rds:CreateDBSnapshot</code> can be used to exfiltrate RDS database contents.</li> </ul></p></div>',
"findings": [],
},
"BypassesNetworkControls": {
"severity": "medium",
"description": BYPASSES_NETWORK_CONTROLS_DESCRIPTION,
"findings": [],
},
"ServiceWildcard": {
"severity": "medium",
"description": '<p>"Service Wildcard" is the unofficial way of referring to IAM policy statements that grant access to ALL actions under a service - like s3:*. Prioritizing the remediation of policies with this characteristic can help to efficiently reduce the total count of issues in the Cloudsplaining report.</p>',
Expand All @@ -242,3 +271,18 @@ def test_finding_actions_excluded(self):
}
# print(json.dumps(results, indent=4))
self.assertDictEqual(results, expected_results)

def test_policy_finding_for_bypasses_network_controls(self):
test_policy = {
"Version": "2012-10-17",
"Statement": [{"Effect": "Allow", "Action": ["redshift:GetClusterCredentials"], "Resource": "*"}],
}
policy_document = PolicyDocument(test_policy)
exclusions = Exclusions({})
policy_finding = PolicyFinding(policy_document, exclusions)
results = policy_finding.results

self.assertListEqual(results["BypassesNetworkControls"]["findings"], ["redshift:GetClusterCredentials"])
self.assertIn("redshift", results["ServicesAffected"])
self.assertEqual(results["BypassesNetworkControls"]["severity"], "medium")
self.assertEqual(results["BypassesNetworkControls"]["description"], BYPASSES_NETWORK_CONTROLS_DESCRIPTION)