feat(azure): add Application Gateway WAF and HTTP/2 checks (#13160)

Co-authored-by: pedrooot <pedromarting3@gmail.com>
This commit is contained in:
Babafemi Bulugbeandpedrooot authored and GitHub committed 2026-10-29 10:49:38 +01:00
1 parent ca6ed48664
commit 8e83de67bc
13 files changed
+1395 -6

No files matched your search

@@ -0,0 +1,101 @@
from unittest import mock
from prowler.providers.azure.services.network.network_service import (
ApplicationGateway,
)
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_DISPLAY,
AZURE_SUBSCRIPTION_ID,
AZURE_SUBSCRIPTION_NAME,
RESOURCE_GROUP,
set_mocked_azure_provider,
)
CHECK = "network_application_gateway_http2_enabled"
CHECK_PATH = f"prowler.providers.azure.services.network.{CHECK}.{CHECK}"
GATEWAY_ID = f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP}/providers/Microsoft.Network/applicationGateways/agw1"
PREFIX = f"Application Gateway agw1 in subscription {AZURE_SUBSCRIPTION_DISPLAY}"
def run_check(gateways, lookup_failed=()):
network_client = mock.MagicMock()
network_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
network_client.application_gateways = gateways
network_client.application_gateways_lookup_failed = set(lookup_failed)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(f"{CHECK_PATH}.network_client", new=network_client),
):
from prowler.providers.azure.services.network.network_application_gateway_http2_enabled.network_application_gateway_http2_enabled import (
network_application_gateway_http2_enabled,
)
return network_application_gateway_http2_enabled().execute()
def single(http2_enabled: bool):
gateway = ApplicationGateway(
id=GATEWAY_ID, name="agw1", location="westeurope", http2_enabled=http2_enabled
)
return run_check({AZURE_SUBSCRIPTION_ID: {GATEWAY_ID: gateway}})
UNLISTED = f"Cannot evaluate HTTP/2 on the Application Gateways in subscription {AZURE_SUBSCRIPTION_DISPLAY}: they could not be listed completely. Check the scan log for the error, and verify that Microsoft.Network/applicationGateways/read (included in Reader) is granted to the scanning identity."
def assert_gateway_finding(finding, status, status_extended):
assert finding.status == status
assert finding.status_extended == status_extended
assert finding.subscription == AZURE_SUBSCRIPTION_ID
assert finding.resource_id == GATEWAY_ID
assert finding.resource_name == "agw1"
assert finding.location == "westeurope"
def assert_subscription_finding(finding):
assert finding.status == "MANUAL"
assert finding.status_extended == UNLISTED
assert finding.subscription == AZURE_SUBSCRIPTION_ID
assert finding.resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}"
assert finding.resource_name == AZURE_SUBSCRIPTION_ID
assert finding.location == "global"
class Test_network_application_gateway_http2_enabled:
def test_no_gateways(self):
assert run_check({}) == []
assert run_check({AZURE_SUBSCRIPTION_ID: {}}) == []
def test_http2_enabled(self):
result = single(True)
assert len(result) == 1
assert_gateway_finding(result[0], "PASS", f"{PREFIX} has HTTP/2 enabled.")
def test_http2_disabled(self):
result = single(False)
assert len(result) == 1
assert_gateway_finding(
result[0], "FAIL", f"{PREFIX} does not have HTTP/2 enabled."
)
def test_gateways_lookup_failed_is_manual(self):
result = run_check(
{AZURE_SUBSCRIPTION_ID: {}}, lookup_failed={AZURE_SUBSCRIPTION_ID}
)
assert len(result) == 1
assert_subscription_finding(result[0])
def test_partial_lookup_still_reports_listed_gateways(self):
gateway = ApplicationGateway(
id=GATEWAY_ID, name="agw1", location="westeurope", http2_enabled=True
)
result = run_check(
{AZURE_SUBSCRIPTION_ID: {GATEWAY_ID: gateway}},
lookup_failed={AZURE_SUBSCRIPTION_ID},
)
assert len(result) == 2
assert_subscription_finding(result[0])
assert_gateway_finding(result[1], "PASS", f"{PREFIX} has HTTP/2 enabled.")
@@ -0,0 +1,260 @@
from unittest import mock
from prowler.providers.azure.services.network.network_service import (
ApplicationGateway,
)
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_DISPLAY,
AZURE_SUBSCRIPTION_ID,
AZURE_SUBSCRIPTION_NAME,
RESOURCE_GROUP,
set_mocked_azure_provider,
)
CHECK = "network_application_gateway_waf_enabled"
CHECK_PATH = f"prowler.providers.azure.services.network.{CHECK}.{CHECK}"
GATEWAY_ID = f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP}/providers/Microsoft.Network/applicationGateways/agw1"
POLICY_ID = f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP}/providers/Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies/waf1"
PREFIX = f"Application Gateway agw1 in subscription {AZURE_SUBSCRIPTION_DISPLAY}"
GATEWAYS_UNLISTED = f"Cannot evaluate the WAF policy association of the Application Gateways in subscription {AZURE_SUBSCRIPTION_DISPLAY}: they could not be listed completely. Check the scan log for the error, and verify that Microsoft.Network/applicationGateways/read (included in Reader) is granted to the scanning identity."
POLICIES_UNLISTED = f"Cannot evaluate the WAF policy association of the Application Gateways in subscription {AZURE_SUBSCRIPTION_DISPLAY}: the WAF policies associated with them could not be listed or read completely. Check the scan log for the error, and verify that Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies/read (included in Reader) is granted to the scanning identity."
BOTH_UNLISTED = f"Cannot evaluate the WAF policy association of the Application Gateways in subscription {AZURE_SUBSCRIPTION_DISPLAY}: they could not be listed completely, and the WAF policies associated with them could not be listed or read completely. Check the scan log for the errors, and verify that Microsoft.Network/applicationGateways/read and Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies/read (both included in Reader) are granted to the scanning identity."
def build_gateway(**settings) -> ApplicationGateway:
return ApplicationGateway(
id=GATEWAY_ID, name="agw1", location="westeurope", **settings
)
def run_check(
gateways,
gateways_lookup_failed=(),
policies_lookup_failed=(),
policy_reads_failed=(),
):
network_client = mock.MagicMock()
network_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
network_client.application_gateways = gateways
network_client.application_gateways_lookup_failed = set(gateways_lookup_failed)
network_client.waf_policies_lookup_failed = set(policies_lookup_failed)
network_client.waf_policy_reads_failed = set(policy_reads_failed)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(f"{CHECK_PATH}.network_client", new=network_client),
):
from prowler.providers.azure.services.network.network_application_gateway_waf_enabled.network_application_gateway_waf_enabled import (
network_application_gateway_waf_enabled,
)
return network_application_gateway_waf_enabled().execute()
def single(gateway):
return run_check({AZURE_SUBSCRIPTION_ID: {gateway.id: gateway}})
def assert_gateway_finding(finding, status, status_extended):
assert finding.status == status
assert finding.status_extended == status_extended
assert finding.subscription == AZURE_SUBSCRIPTION_ID
assert finding.resource_id == GATEWAY_ID
assert finding.resource_name == "agw1"
assert finding.location == "westeurope"
def assert_subscription_finding(finding, status_extended):
assert finding.status == "MANUAL"
assert finding.status_extended == status_extended
assert finding.subscription == AZURE_SUBSCRIPTION_ID
assert finding.resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}"
assert finding.resource_name == AZURE_SUBSCRIPTION_ID
assert finding.location == "global"
class Test_network_application_gateway_waf_enabled:
def test_no_gateways(self):
assert run_check({}) == []
assert run_check({AZURE_SUBSCRIPTION_ID: {}}) == []
def test_enabled_waf_policy_associated(self):
result = single(
build_gateway(firewall_policy_id=POLICY_ID, firewall_policy_enabled=True)
)
assert len(result) == 1
assert_gateway_finding(
result[0], "PASS", f"{PREFIX} has an enabled WAF policy associated."
)
def test_disabled_waf_policy_associated(self):
result = single(
build_gateway(firewall_policy_id=POLICY_ID, firewall_policy_enabled=False)
)
assert len(result) == 1
assert_gateway_finding(
result[0],
"FAIL",
f"{PREFIX} has a WAF policy associated, but the policy is disabled.",
)
def test_waf_policy_state_unknown(self):
result = single(build_gateway(firewall_policy_id=POLICY_ID))
assert len(result) == 1
assert_gateway_finding(
result[0],
"MANUAL",
f"{PREFIX} has a WAF policy associated, but the state of that policy could not be determined. Check the scan log for the error.",
)
def test_legacy_waf_configuration(self):
result = single(build_gateway(waf_configuration_enabled=True))
assert len(result) == 1
assert_gateway_finding(
result[0],
"FAIL",
f"{PREFIX} uses the legacy WAF configuration instead of a WAF policy.",
)
def test_no_waf(self):
result = single(build_gateway())
assert len(result) == 1
assert_gateway_finding(
result[0], "FAIL", f"{PREFIX} has no gateway-level WAF policy associated."
)
def test_gateways_lookup_failed_is_manual(self):
result = run_check(
{AZURE_SUBSCRIPTION_ID: {}}, gateways_lookup_failed={AZURE_SUBSCRIPTION_ID}
)
assert len(result) == 1
assert_subscription_finding(result[0], GATEWAYS_UNLISTED)
def test_partial_gateways_lookup_still_reports_listed_gateways(self):
gateway = build_gateway(
firewall_policy_id=POLICY_ID, firewall_policy_enabled=True
)
result = run_check(
{AZURE_SUBSCRIPTION_ID: {GATEWAY_ID: gateway}},
gateways_lookup_failed={AZURE_SUBSCRIPTION_ID},
)
assert len(result) == 2
assert_subscription_finding(result[0], GATEWAYS_UNLISTED)
assert_gateway_finding(
result[1], "PASS", f"{PREFIX} has an enabled WAF policy associated."
)
def test_policies_lookup_failed_reports_unknown_states_once(self):
other_id = GATEWAY_ID.replace("agw1", "agw2")
gateways = {
GATEWAY_ID: build_gateway(firewall_policy_id=POLICY_ID),
other_id: ApplicationGateway(
id=other_id,
name="agw2",
location="westeurope",
firewall_policy_id=POLICY_ID,
),
}
result = run_check(
{AZURE_SUBSCRIPTION_ID: gateways},
policies_lookup_failed={AZURE_SUBSCRIPTION_ID},
)
assert len(result) == 1
assert_subscription_finding(result[0], POLICIES_UNLISTED)
def test_policies_lookup_failed_keeps_gateways_with_known_states(self):
other_id = GATEWAY_ID.replace("agw1", "agw2")
gateways = {
GATEWAY_ID: build_gateway(
firewall_policy_id=POLICY_ID, firewall_policy_enabled=False
),
other_id: ApplicationGateway(
id=other_id,
name="agw2",
location="westeurope",
firewall_policy_id=POLICY_ID.replace("waf1", "waf2"),
),
}
result = run_check(
{AZURE_SUBSCRIPTION_ID: gateways},
policies_lookup_failed={AZURE_SUBSCRIPTION_ID},
)
assert len(result) == 2
assert_subscription_finding(result[0], POLICIES_UNLISTED)
assert_gateway_finding(
result[1],
"FAIL",
f"{PREFIX} has a WAF policy associated, but the policy is disabled.",
)
def test_policies_lookup_failed_without_unknown_states_adds_nothing(self):
result = run_check(
{
AZURE_SUBSCRIPTION_ID: {
GATEWAY_ID: build_gateway(
firewall_policy_id=POLICY_ID, firewall_policy_enabled=True
)
}
},
policies_lookup_failed={AZURE_SUBSCRIPTION_ID},
)
assert len(result) == 1
assert_gateway_finding(
result[0], "PASS", f"{PREFIX} has an enabled WAF policy associated."
)
def test_failed_policy_read_reports_unknown_states_once(self):
other_id = GATEWAY_ID.replace("agw1", "agw2")
gateways = {
GATEWAY_ID: build_gateway(firewall_policy_id=POLICY_ID),
other_id: ApplicationGateway(
id=other_id,
name="agw2",
location="westeurope",
firewall_policy_id=POLICY_ID,
),
}
result = run_check(
{AZURE_SUBSCRIPTION_ID: gateways},
policy_reads_failed={POLICY_ID.casefold()},
)
assert len(result) == 1
assert_subscription_finding(result[0], POLICIES_UNLISTED)
def test_failed_policy_read_keeps_gateway_with_missing_policy(self):
other_id = GATEWAY_ID.replace("agw1", "agw2")
gateways = {
GATEWAY_ID: build_gateway(firewall_policy_id=POLICY_ID),
other_id: ApplicationGateway(
id=other_id,
name="agw2",
location="westeurope",
firewall_policy_id=POLICY_ID.replace("waf1", "waf2"),
),
}
result = run_check(
{AZURE_SUBSCRIPTION_ID: gateways},
policy_reads_failed={POLICY_ID.upper().casefold()},
)
assert len(result) == 2
assert_subscription_finding(result[0], POLICIES_UNLISTED)
assert result[1].resource_id == other_id
assert result[1].status == "MANUAL"
assert result[1].status_extended == (
f"Application Gateway agw2 in subscription {AZURE_SUBSCRIPTION_DISPLAY} has a WAF policy associated, but the state of that policy could not be determined. Check the scan log for the error."
)
def test_unlisted_gateways_and_policies_give_one_finding(self):
result = run_check(
{
AZURE_SUBSCRIPTION_ID: {
GATEWAY_ID: build_gateway(firewall_policy_id=POLICY_ID)
}
},
gateways_lookup_failed={AZURE_SUBSCRIPTION_ID},
policies_lookup_failed={AZURE_SUBSCRIPTION_ID},
)
assert len(result) == 1
assert_subscription_finding(result[0], BOTH_UNLISTED)
@@ -1,14 +1,23 @@
from unittest.mock import MagicMock, patch
from azure.mgmt.network.models import FlowLog
from azure.core.exceptions import ResourceNotFoundError
from azure.mgmt.network import models as azure_network_models
from azure.mgmt.network.models import (
ApplicationGatewaySku,
ApplicationGatewayWebApplicationFirewallConfiguration,
FlowLog,
SubResource,
)
from prowler.providers.azure.services.network.network_service import (
ApplicationGateway,
BastionHost,
Network,
NetworkWatcher,
PublicIp,
SecurityGroup,
VirtualNetwork,
WafPolicy,
)
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_ID,
@@ -83,6 +92,30 @@ def mock_network_get_virtual_networks(_):
}
def mock_network_get_waf_policies(_):
return {
AZURE_SUBSCRIPTION_ID: {
"waf_id": WafPolicy(
id="waf_id", name="waf_name", location="location", state="Enabled"
)
}
}
def mock_network_get_application_gateways(_):
return {
AZURE_SUBSCRIPTION_ID: {
"id": ApplicationGateway(
id="id",
name="name",
location="location",
firewall_policy_id="policy_id",
http2_enabled=True,
)
}
}
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_security_groups",
new=mock_network_get_security_groups,
@@ -103,6 +136,14 @@ def mock_network_get_virtual_networks(_):
"prowler.providers.azure.services.network.network_service.Network._get_virtual_networks",
new=mock_network_get_virtual_networks,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_Service:
def test_get_client(self):
network = Network(set_mocked_azure_provider())
@@ -122,6 +163,21 @@ class Test_Network_Service:
assert network.security_groups[AZURE_SUBSCRIPTION_ID][0].location == "location"
assert network.security_groups[AZURE_SUBSCRIPTION_ID][0].security_rules == []
def test_get_waf_policies(self):
network = Network(set_mocked_azure_provider())
policy = network.waf_policies[AZURE_SUBSCRIPTION_ID]["waf_id"]
assert policy.__class__.__name__ == "WafPolicy"
assert policy.name == "waf_name"
assert policy.state == "Enabled"
def test_get_application_gateways(self):
network = Network(set_mocked_azure_provider())
gateway = network.application_gateways[AZURE_SUBSCRIPTION_ID]["id"]
assert gateway.__class__.__name__ == "ApplicationGateway"
assert gateway.name == "name"
assert gateway.firewall_policy_id == "policy_id"
assert gateway.http2_enabled is True
def test_get_network_watchers(self):
network = Network(set_mocked_azure_provider())
assert (
@@ -185,6 +241,14 @@ class Test_Network_Service:
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_security_groups:
def test_get_security_groups_no_resource_groups(self):
mock_client = MagicMock()
@@ -354,6 +418,14 @@ class Test_Network_get_security_groups:
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_network_watchers:
def test_get_network_watchers_no_resource_groups(self):
mock_client = MagicMock()
@@ -458,6 +530,14 @@ class Test_Network_get_network_watchers:
assert AZURE_SUBSCRIPTION_ID in result
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_bastion_hosts:
def test_get_bastion_hosts_no_resource_groups(self):
mock_client = MagicMock()
@@ -563,6 +643,14 @@ class Test_Network_get_bastion_hosts:
assert result[AZURE_SUBSCRIPTION_ID] == []
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_public_ip_addresses:
def test_get_public_ip_addresses_no_resource_groups(self):
mock_client = MagicMock()
@@ -668,6 +756,14 @@ class Test_Network_get_public_ip_addresses:
assert result[AZURE_SUBSCRIPTION_ID] == []
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_network_watchers_extra:
def test_get_network_watchers_with_multiple_resource_groups(self):
mock_client = MagicMock()
@@ -737,6 +833,14 @@ class Test_Network_get_network_watchers_extra:
mock_client.network_watchers.list.assert_not_called()
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_bastion_hosts_extra:
def test_get_bastion_hosts_with_multiple_resource_groups(self):
mock_client = MagicMock()
@@ -806,6 +910,14 @@ class Test_Network_get_bastion_hosts_extra:
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_public_ip_addresses_extra:
def test_get_public_ip_addresses_with_multiple_resource_groups(self):
mock_client = MagicMock()
@@ -875,6 +987,14 @@ class Test_Network_get_public_ip_addresses_extra:
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_waf_policies",
new=mock_network_get_waf_policies,
)
@patch(
"prowler.providers.azure.services.network.network_service.Network._get_application_gateways",
new=mock_network_get_application_gateways,
)
class Test_Network_get_virtual_networks_extra:
def _ctx(self):
return (
@@ -1085,3 +1205,395 @@ class Test_Network_get_virtual_networks_extra:
mock_client.virtual_networks.list.assert_called_once_with(
resource_group_name="RG"
)
NETWORK = "prowler.providers.azure.services.network.network_service.Network"
GATEWAY_ID = f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP}/providers/Microsoft.Network/applicationGateways/agw1"
GATEWAY_POLICY_ID = f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP}/providers/Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies/waf1"
def build_network_with_client(mock_client, resource_groups=None):
with (
patch(f"{NETWORK}._get_security_groups", new=mock_network_get_security_groups),
patch(f"{NETWORK}._get_bastion_hosts", new=mock_network_get_bastion_hosts),
patch(
f"{NETWORK}._get_network_watchers", new=mock_network_get_network_watchers
),
patch(
f"{NETWORK}._get_public_ip_addresses",
new=mock_network_get_public_ip_addresses,
),
patch(
f"{NETWORK}._get_virtual_networks", new=mock_network_get_virtual_networks
),
patch(f"{NETWORK}._get_waf_policies", new=mock_network_get_waf_policies),
patch(
f"{NETWORK}._get_application_gateways",
new=mock_network_get_application_gateways,
),
):
network = Network(set_mocked_azure_provider())
network.clients = {AZURE_SUBSCRIPTION_ID: mock_client}
network.resource_groups = resource_groups
return network
def build_sdk_waf_policy(state, policy_id=GATEWAY_POLICY_ID, name="waf1"):
waf_policy = azure_network_models.WebApplicationFirewallPolicy(
id=policy_id,
location="westeurope",
policy_settings=azure_network_models.PolicySettings(state=state),
)
waf_policy.name = name
return waf_policy
def build_waf_policy_model(state, policy_id=GATEWAY_POLICY_ID):
return WafPolicy(id=policy_id, name="waf1", location="westeurope", state=state)
def build_sdk_application_gateway(name="agw1", policy_id=None):
gateway = azure_network_models.ApplicationGateway(
id=GATEWAY_ID.replace("agw1", name),
location="westeurope",
sku=ApplicationGatewaySku(name="WAF_v2", tier="WAF_v2"),
firewall_policy=SubResource(id=policy_id) if policy_id else None,
)
gateway.name = name
return gateway
def get_gateways(mock_client, listed_policies=(), resource_groups=None):
"""Collect gateways with the given WAF policies already listed."""
network = build_network_with_client(mock_client, resource_groups)
network.waf_policies = {
AZURE_SUBSCRIPTION_ID: {policy.id: policy for policy in listed_policies}
}
return network, network._get_application_gateways()
class Test_Network_get_waf_policies:
def test_maps_policy_state(self):
mock_client = MagicMock()
mock_client.web_application_firewall_policies.list_all.return_value = [
build_sdk_waf_policy("Enabled")
]
network = build_network_with_client(mock_client)
result = network._get_waf_policies()
assert network.waf_policies_lookup_failed == set()
policy = result[AZURE_SUBSCRIPTION_ID][GATEWAY_POLICY_ID]
assert policy.id == GATEWAY_POLICY_ID
assert policy.name == "waf1"
assert policy.location == "westeurope"
assert policy.state == "Enabled"
def test_uses_resource_group_scope(self):
mock_client = MagicMock()
mock_client.web_application_firewall_policies.list.return_value = []
network = build_network_with_client(
mock_client, {AZURE_SUBSCRIPTION_ID: [RESOURCE_GROUP]}
)
result = network._get_waf_policies()
mock_client.web_application_firewall_policies.list.assert_called_once_with(
resource_group_name=RESOURCE_GROUP
)
mock_client.web_application_firewall_policies.list_all.assert_not_called()
assert result == {AZURE_SUBSCRIPTION_ID: {}}
def test_api_error_marks_subscription_lookup_failed(self):
mock_client = MagicMock()
mock_client.web_application_firewall_policies.list_all.side_effect = Exception(
"boom"
)
network = build_network_with_client(mock_client)
result = network._get_waf_policies()
assert result == {AZURE_SUBSCRIPTION_ID: {}}
assert network.waf_policies_lookup_failed == {AZURE_SUBSCRIPTION_ID}
def test_resource_group_error_marks_subscription_lookup_failed(self):
mock_client = MagicMock()
mock_client.web_application_firewall_policies.list.side_effect = Exception(
"boom"
)
network = build_network_with_client(
mock_client, {AZURE_SUBSCRIPTION_ID: [RESOURCE_GROUP]}
)
result = network._get_waf_policies()
assert result == {AZURE_SUBSCRIPTION_ID: {}}
assert network.waf_policies_lookup_failed == {AZURE_SUBSCRIPTION_ID}
def test_missing_resource_group_is_not_a_failed_lookup(self):
mock_client = MagicMock()
mock_client.web_application_firewall_policies.list.side_effect = (
ResourceNotFoundError("gone")
)
network = build_network_with_client(
mock_client, {AZURE_SUBSCRIPTION_ID: [RESOURCE_GROUP]}
)
result = network._get_waf_policies()
assert result == {AZURE_SUBSCRIPTION_ID: {}}
assert network.waf_policies_lookup_failed == set()
def test_unmappable_policy_is_skipped_and_marks_subscription(self):
broken = azure_network_models.WebApplicationFirewallPolicy(
location="westeurope"
)
mock_client = MagicMock()
mock_client.web_application_firewall_policies.list_all.return_value = [
broken,
build_sdk_waf_policy("Enabled"),
]
network = build_network_with_client(mock_client)
result = network._get_waf_policies()
assert list(result[AZURE_SUBSCRIPTION_ID]) == [GATEWAY_POLICY_ID]
assert network.waf_policies_lookup_failed == {AZURE_SUBSCRIPTION_ID}
class Test_Network_get_application_gateways:
def test_maps_gateway_settings(self):
gateway = azure_network_models.ApplicationGateway(
id=GATEWAY_ID,
location="westeurope",
sku=ApplicationGatewaySku(name="WAF_v2", tier="WAF_v2"),
firewall_policy=SubResource(id=GATEWAY_POLICY_ID),
enable_http2=True,
)
gateway.name = "agw1"
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [gateway]
network, result = get_gateways(mock_client, [build_waf_policy_model("Enabled")])
assert network.application_gateways_lookup_failed == set()
mock_client.web_application_firewall_policies.get.assert_not_called()
mapped = result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID]
assert mapped.name == "agw1"
assert mapped.location == "westeurope"
assert mapped.firewall_policy_id == GATEWAY_POLICY_ID
assert mapped.firewall_policy_enabled is True
assert mapped.waf_configuration_enabled is False
assert mapped.http2_enabled is True
def test_maps_legacy_waf_configuration(self):
waf_configuration = ApplicationGatewayWebApplicationFirewallConfiguration(
enabled=True,
firewall_mode="Prevention",
rule_set_type="OWASP",
rule_set_version="3.2",
)
gateway = azure_network_models.ApplicationGateway(
id=GATEWAY_ID,
location="westeurope",
sku=ApplicationGatewaySku(name="WAF_v2", tier="WAF_v2"),
web_application_firewall_configuration=waf_configuration,
)
gateway.name = "agw1"
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [gateway]
_, result = get_gateways(mock_client)
mapped = result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID]
assert mapped.firewall_policy_id is None
assert mapped.firewall_policy_enabled is None
assert mapped.waf_configuration_enabled is True
assert mapped.http2_enabled is False
def test_uses_resource_group_scope(self):
mock_client = MagicMock()
mock_client.application_gateways.list.return_value = []
_, result = get_gateways(
mock_client, resource_groups={AZURE_SUBSCRIPTION_ID: [RESOURCE_GROUP]}
)
mock_client.application_gateways.list.assert_called_once_with(
resource_group_name=RESOURCE_GROUP
)
mock_client.application_gateways.list_all.assert_not_called()
assert result[AZURE_SUBSCRIPTION_ID] == {}
def test_api_error_marks_subscription_lookup_failed(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.side_effect = Exception("boom")
network, result = get_gateways(mock_client)
assert result == {AZURE_SUBSCRIPTION_ID: {}}
assert network.application_gateways_lookup_failed == {AZURE_SUBSCRIPTION_ID}
def test_resource_group_error_marks_subscription_lookup_failed(self):
mock_client = MagicMock()
mock_client.application_gateways.list.side_effect = Exception("boom")
network, result = get_gateways(
mock_client, resource_groups={AZURE_SUBSCRIPTION_ID: [RESOURCE_GROUP]}
)
assert result == {AZURE_SUBSCRIPTION_ID: {}}
assert network.application_gateways_lookup_failed == {AZURE_SUBSCRIPTION_ID}
def test_maps_disabled_waf_policy_whatever_its_casing(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=GATEWAY_POLICY_ID.upper())
]
_, result = get_gateways(mock_client, [build_waf_policy_model("disabled")])
assert (
result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID].firewall_policy_enabled is False
)
def test_unlisted_waf_policy_is_read_by_id(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=GATEWAY_POLICY_ID)
]
mock_client.web_application_firewall_policies.get.return_value = (
build_sdk_waf_policy("Enabled")
)
_, result = get_gateways(mock_client)
mock_client.web_application_firewall_policies.get.assert_called_once_with(
resource_group_name=RESOURCE_GROUP, policy_name="waf1"
)
assert result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID].firewall_policy_enabled is True
def test_waf_policy_read_error_is_recorded_and_leaves_state_unknown(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=GATEWAY_POLICY_ID)
]
mock_client.web_application_firewall_policies.get.side_effect = Exception(
"boom"
)
network, result = get_gateways(mock_client)
assert result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID].firewall_policy_enabled is None
assert network.waf_policy_reads_failed == {GATEWAY_POLICY_ID.casefold()}
assert network.application_gateways_lookup_failed == set()
def test_missing_waf_policy_is_not_a_failed_read(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=GATEWAY_POLICY_ID)
]
mock_client.web_application_firewall_policies.get.side_effect = (
ResourceNotFoundError("gone")
)
network, result = get_gateways(mock_client)
assert result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID].firewall_policy_enabled is None
assert network.waf_policy_reads_failed == set()
def test_waf_policy_in_another_subscription_is_not_read(self):
other_subscription_policy_id = GATEWAY_POLICY_ID.replace(
AZURE_SUBSCRIPTION_ID, "00000000-0000-0000-0000-000000000000"
)
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=other_subscription_policy_id)
]
network, result = get_gateways(mock_client)
mock_client.web_application_firewall_policies.get.assert_not_called()
assert result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID].firewall_policy_enabled is None
assert network.waf_policy_reads_failed == set()
def test_waf_policy_without_known_state_leaves_state_unknown(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=GATEWAY_POLICY_ID)
]
_, result = get_gateways(mock_client, [build_waf_policy_model(None)])
mock_client.web_application_firewall_policies.get.assert_not_called()
assert result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID].firewall_policy_enabled is None
def test_policy_reference_that_is_not_a_waf_policy_id_is_not_read(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=f"{GATEWAY_POLICY_ID}/extra")
]
network, result = get_gateways(mock_client)
mock_client.web_application_firewall_policies.get.assert_not_called()
assert result[AZURE_SUBSCRIPTION_ID][GATEWAY_ID].firewall_policy_enabled is None
assert network.waf_policy_reads_failed == set()
def test_shared_unlisted_waf_policy_is_read_once(self):
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
build_sdk_application_gateway(policy_id=GATEWAY_POLICY_ID),
build_sdk_application_gateway(
name="agw2", policy_id=GATEWAY_POLICY_ID.upper()
),
]
mock_client.web_application_firewall_policies.get.return_value = (
build_sdk_waf_policy("Enabled")
)
_, result = get_gateways(mock_client)
assert len(result[AZURE_SUBSCRIPTION_ID]) == 2
mock_client.web_application_firewall_policies.get.assert_called_once()
def test_unmappable_gateway_is_skipped_and_marks_subscription(self):
broken = azure_network_models.ApplicationGateway(location="westeurope")
mock_client = MagicMock()
mock_client.application_gateways.list_all.return_value = [
broken,
build_sdk_application_gateway(),
]
network, result = get_gateways(mock_client)
assert list(result[AZURE_SUBSCRIPTION_ID]) == [GATEWAY_ID]
assert network.application_gateways_lookup_failed == {AZURE_SUBSCRIPTION_ID}
def test_failed_resource_group_keeps_gateways_from_the_others(self):
mock_client = MagicMock()
mock_client.application_gateways.list.side_effect = [
[build_sdk_application_gateway()],
Exception("boom"),
]
network, result = get_gateways(
mock_client,
resource_groups={AZURE_SUBSCRIPTION_ID: [RESOURCE_GROUP, "rg2"]},
)
assert list(result[AZURE_SUBSCRIPTION_ID]) == [GATEWAY_ID]
assert network.application_gateways_lookup_failed == {AZURE_SUBSCRIPTION_ID}
def test_missing_resource_group_is_not_a_failed_lookup(self):
mock_client = MagicMock()
mock_client.application_gateways.list.side_effect = ResourceNotFoundError(
"gone"
)
network, result = get_gateways(
mock_client, resource_groups={AZURE_SUBSCRIPTION_ID: [RESOURCE_GROUP]}
)
assert result == {AZURE_SUBSCRIPTION_ID: {}}
assert network.application_gateways_lookup_failed == set()