mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat(containerregistry): add new check containerregistry_not_publicly_accessible (#5291)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
This commit is contained in:
committed by
GitHub
parent
4181ca56be
commit
9f2de7d2f9
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "containerregistry_not_publicly_accessible",
|
||||
"CheckTitle": "Restrict public network access to the Container Registry",
|
||||
"CheckType": [],
|
||||
"ServiceName": "containerregistry",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "ContainerRegistry",
|
||||
"Description": "Ensure that public network access to the Azure Container Registry is restricted.",
|
||||
"Risk": "Public accessibility exposes the Container Registry to potential attacks, unauthorized usage, and data breaches. Restricting access minimizes the surface area for attacks and ensures that only authorized networks can access the registry.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-access-selected-networks",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az acr update --name <registry-name> --default-action Deny",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Ensure that the necessary virtual network configurations or IP rules are in place to allow access from required services once public access is restricted. Review the network access settings regularly to maintain a secure environment. To restrict public network access to your Azure Container Registry: 1. Navigate to your Container Registry in the Azure Portal. 2. Under 'Settings'->'Networking', configure the 'Public network access' settings to 'Disabled'. 3. Set up virtual network service endpoints or private endpoints as needed for secure access. 4. Review and adjust IP access rules as necessary.",
|
||||
"Url": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-access-selected-networks"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "This feature is only available for Premium SKU registries."
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.containerregistry.containerregistry_client import (
|
||||
containerregistry_client,
|
||||
)
|
||||
|
||||
|
||||
class containerregistry_not_publicly_accessible(Check):
|
||||
def execute(self) -> list[Check_Report_Azure]:
|
||||
findings = []
|
||||
|
||||
for subscription, registries in containerregistry_client.registries.items():
|
||||
for registry_id, container_registry_info in registries.items():
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = container_registry_info.name
|
||||
report.resource_id = registry_id
|
||||
report.location = container_registry_info.location
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Container Registry {container_registry_info.name} from subscription {subscription} allows unrestricted network access."
|
||||
|
||||
if (
|
||||
getattr(
|
||||
container_registry_info.network_rule_set, "default_action", ""
|
||||
).lower()
|
||||
== "deny"
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Container Registry {container_registry_info.name} from subscription {subscription} does not allow unrestricted network access."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -1,6 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from azure.mgmt.containerregistry import ContainerRegistryManagementClient
|
||||
from azure.mgmt.containerregistry.models import NetworkRuleSet
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.azure.azure_provider import AzureProvider
|
||||
@@ -39,11 +40,14 @@ class ContainerRegistry(AzureService):
|
||||
admin_user_enabled=getattr(
|
||||
registry, "admin_user_enabled", False
|
||||
),
|
||||
network_rule_set=getattr(
|
||||
registry, "network_rule_set", None
|
||||
),
|
||||
monitor_diagnostic_settings=self._get_registry_monitor_settings(
|
||||
registry.name, resource_group, subscription
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -85,4 +89,5 @@ class ContainerRegistryInfo:
|
||||
login_server: str
|
||||
public_network_access: str
|
||||
admin_user_enabled: bool
|
||||
monitor_diagnostic_settings: list[DiagnosticSetting] = None
|
||||
network_rule_set: NetworkRuleSet
|
||||
monitor_diagnostic_settings: list[DiagnosticSetting]
|
||||
|
||||
+5
@@ -57,6 +57,8 @@ class TestContainerRegistryAdminUserDisabled:
|
||||
login_server="mock_login_server.azurecr.io",
|
||||
public_network_access="Enabled",
|
||||
admin_user_enabled=True,
|
||||
network_rule_set=None,
|
||||
monitor_diagnostic_settings=[],
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -111,11 +113,14 @@ class TestContainerRegistryAdminUserDisabled:
|
||||
login_server="mock_login_server.azurecr.io",
|
||||
public_network_access="Enabled",
|
||||
admin_user_enabled=False,
|
||||
network_rule_set=None,
|
||||
monitor_diagnostic_settings=[],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
check = containerregistry_admin_user_disabled()
|
||||
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
from unittest import mock
|
||||
from unittest.mock import MagicMock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.containerregistry.models import NetworkRuleSet
|
||||
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_containerregistry_not_publicly_accessible:
|
||||
def test_no_container_registries(self):
|
||||
containerregistry_client = MagicMock()
|
||||
containerregistry_client.registries = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
), mock.patch(
|
||||
"prowler.providers.azure.services.containerregistry.containerregistry_not_publicly_accessible.containerregistry_not_publicly_accessible.containerregistry_client",
|
||||
new=containerregistry_client,
|
||||
):
|
||||
from prowler.providers.azure.services.containerregistry.containerregistry_not_publicly_accessible.containerregistry_not_publicly_accessible import (
|
||||
containerregistry_not_publicly_accessible,
|
||||
)
|
||||
|
||||
check = containerregistry_not_publicly_accessible()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_container_registry_network_access_unrestricted(self):
|
||||
containerregistry_client = MagicMock()
|
||||
registry_id = str(uuid4())
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
), mock.patch(
|
||||
"prowler.providers.azure.services.containerregistry.containerregistry_not_publicly_accessible.containerregistry_not_publicly_accessible.containerregistry_client",
|
||||
new=containerregistry_client,
|
||||
):
|
||||
from prowler.providers.azure.services.containerregistry.containerregistry_not_publicly_accessible.containerregistry_not_publicly_accessible import (
|
||||
containerregistry_not_publicly_accessible,
|
||||
)
|
||||
from prowler.providers.azure.services.containerregistry.containerregistry_service import (
|
||||
ContainerRegistryInfo,
|
||||
)
|
||||
|
||||
containerregistry_client.registries = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
registry_id: ContainerRegistryInfo(
|
||||
id=registry_id,
|
||||
name="mock_registry",
|
||||
location="westeurope",
|
||||
resource_group="mock_resource_group",
|
||||
sku="Basic",
|
||||
login_server="mock_login_server.azurecr.io",
|
||||
public_network_access="Enabled",
|
||||
admin_user_enabled=True,
|
||||
network_rule_set=NetworkRuleSet(default_action="Allow"),
|
||||
monitor_diagnostic_settings=[
|
||||
{
|
||||
"id": "id1/id1",
|
||||
"logs": [
|
||||
{
|
||||
"category": "ContainerLogs",
|
||||
"enabled": True,
|
||||
},
|
||||
{
|
||||
"category": "AdminLogs",
|
||||
"enabled": False,
|
||||
},
|
||||
],
|
||||
"storage_account_name": "mock_storage_account",
|
||||
"storage_account_id": "mock_storage_account_id",
|
||||
"name": "mock_diagnostic_setting",
|
||||
}
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
check = containerregistry_not_publicly_accessible()
|
||||
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Container Registry {containerregistry_client.registries[AZURE_SUBSCRIPTION_ID][registry_id].name} from subscription {AZURE_SUBSCRIPTION_ID} allows unrestricted network access."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "mock_registry"
|
||||
assert (
|
||||
result[0].resource_id
|
||||
== containerregistry_client.registries[AZURE_SUBSCRIPTION_ID][
|
||||
registry_id
|
||||
].id
|
||||
)
|
||||
assert result[0].location == "westeurope"
|
||||
|
||||
def test_container_registry_network_access_restricted(self):
|
||||
containerregistry_client = mock.MagicMock()
|
||||
containerregistry_client.registries = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
), mock.patch(
|
||||
"prowler.providers.azure.services.containerregistry.containerregistry_not_publicly_accessible.containerregistry_not_publicly_accessible.containerregistry_client",
|
||||
new=containerregistry_client,
|
||||
):
|
||||
from prowler.providers.azure.services.containerregistry.containerregistry_not_publicly_accessible.containerregistry_not_publicly_accessible import (
|
||||
containerregistry_not_publicly_accessible,
|
||||
)
|
||||
from prowler.providers.azure.services.containerregistry.containerregistry_service import (
|
||||
ContainerRegistryInfo,
|
||||
)
|
||||
|
||||
registry_id = "mock_registry_id"
|
||||
|
||||
containerregistry_client.registries = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
registry_id: ContainerRegistryInfo(
|
||||
id=registry_id,
|
||||
name="mock_registry",
|
||||
location="westeurope",
|
||||
resource_group="mock_resource_group",
|
||||
sku="Basic",
|
||||
login_server="mock_login_server.azurecr.io",
|
||||
public_network_access="Enabled",
|
||||
admin_user_enabled=False,
|
||||
network_rule_set=NetworkRuleSet(default_action="Deny"),
|
||||
monitor_diagnostic_settings=[
|
||||
{
|
||||
"id": "id1/id1",
|
||||
"logs": [
|
||||
{
|
||||
"category": "ContainerLogs",
|
||||
"enabled": True,
|
||||
},
|
||||
{
|
||||
"category": "AdminLogs",
|
||||
"enabled": False,
|
||||
},
|
||||
],
|
||||
"storage_account_name": "mock_storage_account",
|
||||
"storage_account_id": "mock_storage_account_id",
|
||||
"name": "mock_diagnostic_setting",
|
||||
}
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
check = containerregistry_not_publicly_accessible()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Container Registry {containerregistry_client.registries[AZURE_SUBSCRIPTION_ID][registry_id].name} from subscription {AZURE_SUBSCRIPTION_ID} does not allow unrestricted network access."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == "mock_registry"
|
||||
assert (
|
||||
result[0].resource_id
|
||||
== containerregistry_client.registries[AZURE_SUBSCRIPTION_ID][
|
||||
registry_id
|
||||
].id
|
||||
)
|
||||
assert result[0].location == "westeurope"
|
||||
@@ -34,6 +34,7 @@ class TestContainerRegistryService:
|
||||
login_server="mock_login_server.azurecr.io",
|
||||
public_network_access="Enabled",
|
||||
admin_user_enabled=True,
|
||||
network_rule_set=None,
|
||||
monitor_diagnostic_settings=[
|
||||
{
|
||||
"id": "id1/id1",
|
||||
|
||||
Reference in New Issue
Block a user