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:
Hugo966
2024-03-14 12:48:58 +01:00
committed by GitHub
parent ed60958014
commit e6efb2b716
4 changed files with 212 additions and 0 deletions
@@ -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."
}
@@ -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
@@ -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