mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
fix(m365): skip defender preset policies without rules (#12809)
(cherry picked from commit 61ef44a03b)
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
`KeyError` in M365 Defender malware, anti-phishing and inbound anti-spam checks when the tenant has Standard or Strict preset security policies
|
||||||
+6
@@ -55,6 +55,12 @@ class defender_antiphishing_policy_configured(Check):
|
|||||||
policy_name,
|
policy_name,
|
||||||
policy,
|
policy,
|
||||||
) in defender_client.antiphishing_policies.items():
|
) in defender_client.antiphishing_policies.items():
|
||||||
|
# Preset security policies are scoped by protection policy rules, not filter rules
|
||||||
|
if (
|
||||||
|
not policy.default
|
||||||
|
and policy.name not in defender_client.antiphishing_rules
|
||||||
|
):
|
||||||
|
continue
|
||||||
report = CheckReportM365(
|
report = CheckReportM365(
|
||||||
metadata=self.metadata(),
|
metadata=self.metadata(),
|
||||||
resource=policy,
|
resource=policy,
|
||||||
|
|||||||
+6
@@ -51,6 +51,12 @@ class defender_antispam_policy_inbound_no_allowed_domains(Check):
|
|||||||
default_policy_well_configured = False
|
default_policy_well_configured = False
|
||||||
|
|
||||||
for policy in defender_client.inbound_spam_policies:
|
for policy in defender_client.inbound_spam_policies:
|
||||||
|
# Preset security policies are scoped by protection policy rules, not filter rules
|
||||||
|
if (
|
||||||
|
not policy.default
|
||||||
|
and policy.identity not in defender_client.inbound_spam_rules
|
||||||
|
):
|
||||||
|
continue
|
||||||
report = CheckReportM365(
|
report = CheckReportM365(
|
||||||
metadata=self.metadata(),
|
metadata=self.metadata(),
|
||||||
resource=policy,
|
resource=policy,
|
||||||
|
|||||||
+6
@@ -51,6 +51,12 @@ class defender_malware_policy_common_attachments_filter_enabled(Check):
|
|||||||
default_policy_well_configured = False
|
default_policy_well_configured = False
|
||||||
|
|
||||||
for policy in defender_client.malware_policies:
|
for policy in defender_client.malware_policies:
|
||||||
|
# Preset security policies are scoped by protection policy rules, not filter rules
|
||||||
|
if (
|
||||||
|
not policy.is_default
|
||||||
|
and policy.identity not in defender_client.malware_rules
|
||||||
|
):
|
||||||
|
continue
|
||||||
report = CheckReportM365(
|
report = CheckReportM365(
|
||||||
metadata=self.metadata(),
|
metadata=self.metadata(),
|
||||||
resource=policy,
|
resource=policy,
|
||||||
|
|||||||
+6
@@ -114,6 +114,12 @@ class defender_malware_policy_comprehensive_attachments_filter_applied(Check):
|
|||||||
default_policy_well_configured = False
|
default_policy_well_configured = False
|
||||||
|
|
||||||
for policy in defender_client.malware_policies:
|
for policy in defender_client.malware_policies:
|
||||||
|
# Preset security policies are scoped by protection policy rules, not filter rules
|
||||||
|
if (
|
||||||
|
not policy.is_default
|
||||||
|
and policy.identity not in defender_client.malware_rules
|
||||||
|
):
|
||||||
|
continue
|
||||||
report = CheckReportM365(
|
report = CheckReportM365(
|
||||||
metadata=self.metadata(),
|
metadata=self.metadata(),
|
||||||
resource=policy,
|
resource=policy,
|
||||||
|
|||||||
+6
@@ -51,6 +51,12 @@ class defender_malware_policy_notifications_internal_users_malware_enabled(Check
|
|||||||
default_policy_well_configured = False
|
default_policy_well_configured = False
|
||||||
|
|
||||||
for policy in defender_client.malware_policies:
|
for policy in defender_client.malware_policies:
|
||||||
|
# Preset security policies are scoped by protection policy rules, not filter rules
|
||||||
|
if (
|
||||||
|
not policy.is_default
|
||||||
|
and policy.identity not in defender_client.malware_rules
|
||||||
|
):
|
||||||
|
continue
|
||||||
report = CheckReportM365(
|
report = CheckReportM365(
|
||||||
metadata=self.metadata(),
|
metadata=self.metadata(),
|
||||||
resource=policy,
|
resource=policy,
|
||||||
|
|||||||
+83
@@ -521,3 +521,86 @@ class Test_defender_antiphishing_policy_configured:
|
|||||||
check = defender_antiphishing_policy_configured()
|
check = defender_antiphishing_policy_configured()
|
||||||
result = check.execute()
|
result = check.execute()
|
||||||
assert len(result) == 0
|
assert len(result) == 0
|
||||||
|
|
||||||
|
def test_preset_policy_without_rule_is_skipped(self):
|
||||||
|
defender_client = mock.MagicMock()
|
||||||
|
defender_client.audited_tenant = "audited_tenant"
|
||||||
|
defender_client.audited_domain = DOMAIN
|
||||||
|
defender_client.audit_config = {}
|
||||||
|
|
||||||
|
with (
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||||
|
return_value=set_mocked_m365_provider(),
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client",
|
||||||
|
new=defender_client,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import (
|
||||||
|
defender_antiphishing_policy_configured,
|
||||||
|
)
|
||||||
|
from prowler.providers.m365.services.defender.defender_service import (
|
||||||
|
AntiphishingPolicy,
|
||||||
|
AntiphishingRule,
|
||||||
|
)
|
||||||
|
|
||||||
|
defender_client.antiphishing_policies = {
|
||||||
|
"Default": AntiphishingPolicy(
|
||||||
|
name="Default",
|
||||||
|
spoof_intelligence=True,
|
||||||
|
spoof_intelligence_action="Quarantine",
|
||||||
|
dmarc_reject_action="Quarantine",
|
||||||
|
dmarc_quarantine_action="Quarantine",
|
||||||
|
safety_tips=True,
|
||||||
|
unauthenticated_sender_action=True,
|
||||||
|
show_tag=True,
|
||||||
|
honor_dmarc_policy=True,
|
||||||
|
default=True,
|
||||||
|
),
|
||||||
|
"Standard Preset Security Policy1663355404982": AntiphishingPolicy(
|
||||||
|
name="Standard Preset Security Policy1663355404982",
|
||||||
|
spoof_intelligence=True,
|
||||||
|
spoof_intelligence_action="Quarantine",
|
||||||
|
dmarc_reject_action="Quarantine",
|
||||||
|
dmarc_quarantine_action="Quarantine",
|
||||||
|
safety_tips=True,
|
||||||
|
unauthenticated_sender_action=True,
|
||||||
|
show_tag=True,
|
||||||
|
honor_dmarc_policy=True,
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
"Custom1": AntiphishingPolicy(
|
||||||
|
name="Custom1",
|
||||||
|
spoof_intelligence=True,
|
||||||
|
spoof_intelligence_action="Quarantine",
|
||||||
|
dmarc_reject_action="Quarantine",
|
||||||
|
dmarc_quarantine_action="Quarantine",
|
||||||
|
safety_tips=True,
|
||||||
|
unauthenticated_sender_action=True,
|
||||||
|
show_tag=True,
|
||||||
|
honor_dmarc_policy=True,
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
defender_client.antiphishing_rules = {
|
||||||
|
"Custom1": AntiphishingRule(
|
||||||
|
state="Enabled",
|
||||||
|
priority=1,
|
||||||
|
users=["user1@example.com"],
|
||||||
|
groups=None,
|
||||||
|
domains=None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
check = defender_antiphishing_policy_configured()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 2
|
||||||
|
assert "Standard Preset Security Policy1663355404982" not in [
|
||||||
|
finding.resource_id for finding in result
|
||||||
|
]
|
||||||
|
|||||||
+62
@@ -410,3 +410,65 @@ class Test_defender_antispam_policy_inbound_no_allowed_domains:
|
|||||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||||
result = check.execute()
|
result = check.execute()
|
||||||
assert len(result) == 0
|
assert len(result) == 0
|
||||||
|
|
||||||
|
def test_preset_policy_without_rule_is_skipped(self):
|
||||||
|
defender_client = mock.MagicMock()
|
||||||
|
defender_client.audited_tenant = "audited_tenant"
|
||||||
|
defender_client.audited_domain = DOMAIN
|
||||||
|
defender_client.audit_config = {}
|
||||||
|
|
||||||
|
with (
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||||
|
return_value=set_mocked_m365_provider(),
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client",
|
||||||
|
new=defender_client,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import (
|
||||||
|
defender_antispam_policy_inbound_no_allowed_domains,
|
||||||
|
)
|
||||||
|
from prowler.providers.m365.services.defender.defender_service import (
|
||||||
|
DefenderInboundSpamPolicy,
|
||||||
|
InboundSpamRule,
|
||||||
|
)
|
||||||
|
|
||||||
|
defender_client.inbound_spam_policies = [
|
||||||
|
DefenderInboundSpamPolicy(
|
||||||
|
identity="Default",
|
||||||
|
allowed_sender_domains=[],
|
||||||
|
default=True,
|
||||||
|
),
|
||||||
|
DefenderInboundSpamPolicy(
|
||||||
|
identity="Standard Preset Security Policy1663355404982",
|
||||||
|
allowed_sender_domains=[],
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
DefenderInboundSpamPolicy(
|
||||||
|
identity="Custom1",
|
||||||
|
allowed_sender_domains=[],
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
defender_client.inbound_spam_rules = {
|
||||||
|
"Custom1": InboundSpamRule(
|
||||||
|
state="Enabled",
|
||||||
|
priority=1,
|
||||||
|
users=["user1@example.com"],
|
||||||
|
groups=None,
|
||||||
|
domains=None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 2
|
||||||
|
assert "Standard Preset Security Policy1663355404982" not in [
|
||||||
|
finding.resource_id for finding in result
|
||||||
|
]
|
||||||
|
|||||||
+74
@@ -442,3 +442,77 @@ class Test_defender_malware_policy_common_attachments_filter_enabled:
|
|||||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||||
result = check.execute()
|
result = check.execute()
|
||||||
assert len(result) == 0
|
assert len(result) == 0
|
||||||
|
|
||||||
|
def test_preset_policy_without_rule_is_skipped(self):
|
||||||
|
defender_client = mock.MagicMock()
|
||||||
|
defender_client.audited_tenant = "audited_tenant"
|
||||||
|
defender_client.audited_domain = DOMAIN
|
||||||
|
defender_client.audit_config = {}
|
||||||
|
|
||||||
|
with (
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||||
|
return_value=set_mocked_m365_provider(),
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||||
|
new=defender_client,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||||
|
defender_malware_policy_common_attachments_filter_enabled,
|
||||||
|
)
|
||||||
|
from prowler.providers.m365.services.defender.defender_service import (
|
||||||
|
MalwarePolicy,
|
||||||
|
MalwareRule,
|
||||||
|
)
|
||||||
|
|
||||||
|
defender_client.audit_config = {
|
||||||
|
"recommended_blocked_file_types": ["exe", "bat"]
|
||||||
|
}
|
||||||
|
defender_client.malware_policies = [
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Default",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=True,
|
||||||
|
),
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Standard Preset Security Policy1663355404982",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=False,
|
||||||
|
),
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Custom1",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
defender_client.malware_rules = {
|
||||||
|
"Custom1": MalwareRule(
|
||||||
|
state="Enabled",
|
||||||
|
priority=1,
|
||||||
|
users=["user1@example.com"],
|
||||||
|
groups=None,
|
||||||
|
domains=None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 2
|
||||||
|
assert "Standard Preset Security Policy1663355404982" not in [
|
||||||
|
finding.resource_id for finding in result
|
||||||
|
]
|
||||||
|
|||||||
+74
@@ -452,3 +452,77 @@ class Test_defender_malware_policy_comprehensive_attachments_filter_applied:
|
|||||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||||
result = check.execute()
|
result = check.execute()
|
||||||
assert len(result) == 0
|
assert len(result) == 0
|
||||||
|
|
||||||
|
def test_preset_policy_without_rule_is_skipped(self):
|
||||||
|
defender_client = mock.MagicMock()
|
||||||
|
defender_client.audited_tenant = "audited_tenant"
|
||||||
|
defender_client.audited_domain = DOMAIN
|
||||||
|
defender_client.audit_config = {}
|
||||||
|
|
||||||
|
with (
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||||
|
return_value=set_mocked_m365_provider(),
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||||
|
new=defender_client,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||||
|
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||||
|
)
|
||||||
|
from prowler.providers.m365.services.defender.defender_service import (
|
||||||
|
MalwarePolicy,
|
||||||
|
MalwareRule,
|
||||||
|
)
|
||||||
|
|
||||||
|
defender_client.audit_config = {
|
||||||
|
"recommended_blocked_file_types": ["exe", "bat"]
|
||||||
|
}
|
||||||
|
defender_client.malware_policies = [
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Default",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=True,
|
||||||
|
),
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Standard Preset Security Policy1663355404982",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=False,
|
||||||
|
),
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Custom1",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
defender_client.malware_rules = {
|
||||||
|
"Custom1": MalwareRule(
|
||||||
|
state="Enabled",
|
||||||
|
priority=1,
|
||||||
|
users=["user1@example.com"],
|
||||||
|
groups=None,
|
||||||
|
domains=None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 2
|
||||||
|
assert "Standard Preset Security Policy1663355404982" not in [
|
||||||
|
finding.resource_id for finding in result
|
||||||
|
]
|
||||||
|
|||||||
+76
@@ -456,3 +456,79 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled:
|
|||||||
)
|
)
|
||||||
result = check.execute()
|
result = check.execute()
|
||||||
assert len(result) == 0
|
assert len(result) == 0
|
||||||
|
|
||||||
|
def test_preset_policy_without_rule_is_skipped(self):
|
||||||
|
defender_client = mock.MagicMock()
|
||||||
|
defender_client.audited_tenant = "audited_tenant"
|
||||||
|
defender_client.audited_domain = DOMAIN
|
||||||
|
defender_client.audit_config = {}
|
||||||
|
|
||||||
|
with (
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||||
|
return_value=set_mocked_m365_provider(),
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||||
|
),
|
||||||
|
mock.patch(
|
||||||
|
"prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client",
|
||||||
|
new=defender_client,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import (
|
||||||
|
defender_malware_policy_notifications_internal_users_malware_enabled,
|
||||||
|
)
|
||||||
|
from prowler.providers.m365.services.defender.defender_service import (
|
||||||
|
MalwarePolicy,
|
||||||
|
MalwareRule,
|
||||||
|
)
|
||||||
|
|
||||||
|
defender_client.audit_config = {
|
||||||
|
"recommended_blocked_file_types": ["exe", "bat"]
|
||||||
|
}
|
||||||
|
defender_client.malware_policies = [
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Default",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=True,
|
||||||
|
),
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Standard Preset Security Policy1663355404982",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=False,
|
||||||
|
),
|
||||||
|
MalwarePolicy(
|
||||||
|
identity="Custom1",
|
||||||
|
enable_file_filter=True,
|
||||||
|
enable_internal_sender_admin_notifications=True,
|
||||||
|
internal_sender_admin_address="admin@example.com",
|
||||||
|
file_types=["exe", "bat"],
|
||||||
|
is_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
defender_client.malware_rules = {
|
||||||
|
"Custom1": MalwareRule(
|
||||||
|
state="Enabled",
|
||||||
|
priority=1,
|
||||||
|
users=["user1@example.com"],
|
||||||
|
groups=None,
|
||||||
|
domains=None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
check = (
|
||||||
|
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||||
|
)
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 2
|
||||||
|
assert "Standard Preset Security Policy1663355404982" not in [
|
||||||
|
finding.resource_id for finding in result
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user