mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
feat(azure):New check related with network flow logs (#3535)
Co-authored-by: Hugo Gálvez Ureña <hugogalvezu96@gmail.com>
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "network_flow_log_captured_sent",
|
||||
"CheckTitle": "Ensure that network flow logs are captured and fed into a central log analytics workspace.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "network",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Network",
|
||||
"Description": "Ensure that network flow logs are captured and fed into a central log analytics workspace.",
|
||||
"Risk": "Network Flow Logs provide valuable insight into the flow of traffic around your network and feed into both Azure Monitor and Azure Sentinel (if in use), permitting the generation of visual flow diagrams to aid with analyzing for lateral movement, etc.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/security/benchmark/azure/mcsb-logging-threat-detection#lt-4-enable-network-logging-for-security-investigation",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "1. Navigate to Network Watcher. 2. Select NSG flow logs. 3. Select + Create. 4. Select the desired Subscription. 5. Select + Select NSG. 6. Select a network security group. 7. Click Confirm selection. 8. Select or create a new Storage Account. 9. Input the retention in days to retain the log. 10. Click Next. 11. Under Configuration, select Version 2. 12. If rich analytics are required, select Enable Traffic Analytics, a processing interval, and a Log Analytics Workspace. 13. Select Next. 14. Optionally add Tags. 15. Select Review + create. 16. Select Create. Warning The remediation policy creates remediation deployment and names them by concatenating the subscription name and the resource group name. The MAXIMUM permitted length of a deployment name is 64 characters. Exceeding this will cause the remediation task to fail.",
|
||||
"Url": "https://docs.microsoft.com/en-us/azure/network-watcher/network-watcher-nsg-flow-logging-portal"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "The impact of configuring NSG Flow logs is primarily one of cost and configuration. If deployed, it will create storage accounts that hold minimal amounts of data on a 5-day lifecycle before feeding to Log Analytics Workspace. This will increase the amount of data stored and used by Azure Monitor."
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.network.network_client import network_client
|
||||
|
||||
|
||||
class network_flow_log_captured_sent(Check):
|
||||
def execute(self) -> Check_Report_Azure:
|
||||
findings = []
|
||||
for subscription, network_watchers in network_client.network_watchers.items():
|
||||
for network_watcher in network_watchers:
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = network_watcher.name
|
||||
report.resource_id = network_watcher.id
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription} has no flow logs"
|
||||
if network_watcher.flow_logs:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription} has flow logs disabled"
|
||||
for flow_log in network_watcher.flow_logs:
|
||||
if flow_log.enabled:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription} has flow logs that are captured and sent to Log Analytics workspace"
|
||||
break
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.network.models._models import FlowLog, RetentionPolicyParameters
|
||||
|
||||
from prowler.providers.azure.services.network.network_service import NetworkWatcher
|
||||
from tests.providers.azure.azure_fixtures import AZURE_SUBSCRIPTION
|
||||
|
||||
|
||||
class Test_network_flow_log_captured_sent:
|
||||
def test_no_network_watchers(self):
|
||||
network_client = mock.MagicMock
|
||||
network_client.network_watchers = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_captured_sent.network_flow_log_captured_sent import (
|
||||
network_flow_log_captured_sent,
|
||||
)
|
||||
|
||||
check = network_flow_log_captured_sent()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_network_network_watchers_no_flow_logs(self):
|
||||
network_client = mock.MagicMock
|
||||
network_watcher_name = "Network Watcher Name"
|
||||
network_watcher_id = str(uuid4())
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_captured_sent.network_flow_log_captured_sent import (
|
||||
network_flow_log_captured_sent,
|
||||
)
|
||||
|
||||
check = network_flow_log_captured_sent()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher {network_watcher_name} from subscription {AZURE_SUBSCRIPTION} has no flow logs"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
|
||||
def test_network_network_watchers_flow_logs_disabled(self):
|
||||
network_client = mock.MagicMock
|
||||
network_watcher_name = "Network Watcher Name"
|
||||
network_watcher_id = str(uuid4())
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[
|
||||
FlowLog(
|
||||
enabled=False,
|
||||
retention_policy=RetentionPolicyParameters(days=90),
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_captured_sent.network_flow_log_captured_sent import (
|
||||
network_flow_log_captured_sent,
|
||||
)
|
||||
|
||||
check = network_flow_log_captured_sent()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher {network_watcher_name} from subscription {AZURE_SUBSCRIPTION} has flow logs disabled"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
|
||||
def test_network_network_watchers_flow_logs_well_configured(self):
|
||||
network_client = mock.MagicMock
|
||||
network_watcher_name = "Network Watcher Name"
|
||||
network_watcher_id = str(uuid4())
|
||||
|
||||
network_client.network_watchers = {
|
||||
AZURE_SUBSCRIPTION: [
|
||||
NetworkWatcher(
|
||||
id=network_watcher_id,
|
||||
name=network_watcher_name,
|
||||
location="location",
|
||||
flow_logs=[
|
||||
FlowLog(
|
||||
enabled=True,
|
||||
retention_policy=RetentionPolicyParameters(days=90),
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.network.network_service.Network",
|
||||
new=network_client,
|
||||
) as service_client, mock.patch(
|
||||
"prowler.providers.azure.services.network.network_client.network_client",
|
||||
new=service_client,
|
||||
):
|
||||
from prowler.providers.azure.services.network.network_flow_log_captured_sent.network_flow_log_captured_sent import (
|
||||
network_flow_log_captured_sent,
|
||||
)
|
||||
|
||||
check = network_flow_log_captured_sent()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Network Watcher {network_watcher_name} from subscription {AZURE_SUBSCRIPTION} has flow logs that are captured and sent to Log Analytics workspace"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION
|
||||
assert result[0].resource_name == network_watcher_name
|
||||
assert result[0].resource_id == network_watcher_id
|
||||
Reference in New Issue
Block a user