mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(azure regions): support non default azure region (#3013)
Co-authored-by: Pepe Fagoaga <pepe@verica.io>
This commit is contained in:
16
docs/tutorials/azure/use-non-default-cloud.md
Normal file
16
docs/tutorials/azure/use-non-default-cloud.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Use non default Azure regions
|
||||||
|
|
||||||
|
Microsoft provides clouds for compliance with regional laws, which are available for your use.
|
||||||
|
By default, Prowler uses `AzureCloud` cloud which is the comercial one. (you can list all the available with `az cloud list --output table`).
|
||||||
|
|
||||||
|
At the time of writing this documentation the available Azure Clouds from different regions are the following:
|
||||||
|
- AzureCloud
|
||||||
|
- AzureChinaCloud
|
||||||
|
- AzureUSGovernment
|
||||||
|
- AzureGermanCloud
|
||||||
|
|
||||||
|
If you want to change the default one you must include the flag `--azure-region`, i.e.:
|
||||||
|
|
||||||
|
```console
|
||||||
|
prowler azure --az-cli-auth --azure-region AzureChinaCloud
|
||||||
|
```
|
||||||
@@ -56,6 +56,7 @@ nav:
|
|||||||
- Boto3 Configuration: tutorials/aws/boto3-configuration.md
|
- Boto3 Configuration: tutorials/aws/boto3-configuration.md
|
||||||
- Azure:
|
- Azure:
|
||||||
- Authentication: tutorials/azure/authentication.md
|
- Authentication: tutorials/azure/authentication.md
|
||||||
|
- Non default clouds: tutorials/azure/use-non-default-cloud.md
|
||||||
- Subscriptions: tutorials/azure/subscriptions.md
|
- Subscriptions: tutorials/azure/subscriptions.md
|
||||||
- Google Cloud:
|
- Google Cloud:
|
||||||
- Authentication: tutorials/gcp/authentication.md
|
- Authentication: tutorials/gcp/authentication.md
|
||||||
|
|||||||
35
poetry.lock
generated
35
poetry.lock
generated
@@ -11,6 +11,23 @@ files = [
|
|||||||
{file = "about_time-4.2.1-py3-none-any.whl", hash = "sha256:8bbf4c75fe13cbd3d72f49a03b02c5c7dca32169b6d49117c257e7eb3eaee341"},
|
{file = "about_time-4.2.1-py3-none-any.whl", hash = "sha256:8bbf4c75fe13cbd3d72f49a03b02c5c7dca32169b6d49117c257e7eb3eaee341"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adal"
|
||||||
|
version = "1.2.7"
|
||||||
|
description = "Note: This library is already replaced by MSAL Python, available here: https://pypi.org/project/msal/ .ADAL Python remains available here as a legacy. The ADAL for Python library makes it easy for python application to authenticate to Azure Active Directory (AAD) in order to access AAD protected web resources."
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "adal-1.2.7-py2.py3-none-any.whl", hash = "sha256:2a7451ed7441ddbc57703042204a3e30ef747478eea022c70f789fc7f084bc3d"},
|
||||||
|
{file = "adal-1.2.7.tar.gz", hash = "sha256:d74f45b81317454d96e982fd1c50e6fb5c99ac2223728aea8764433a39f566f1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cryptography = ">=1.1.0"
|
||||||
|
PyJWT = ">=1.0.0,<3"
|
||||||
|
python-dateutil = ">=2.1.0,<3"
|
||||||
|
requests = ">=2.0.0,<3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alive-progress"
|
name = "alive-progress"
|
||||||
version = "3.1.5"
|
version = "3.1.5"
|
||||||
@@ -1537,6 +1554,22 @@ requests-oauthlib = ">=0.5.0"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
async = ["aiodns", "aiohttp (>=3.0)"]
|
async = ["aiodns", "aiohttp (>=3.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "msrestazure"
|
||||||
|
version = "0.6.4"
|
||||||
|
description = "AutoRest swagger generator Python client runtime. Azure-specific module."
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "msrestazure-0.6.4-py2.py3-none-any.whl", hash = "sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9"},
|
||||||
|
{file = "msrestazure-0.6.4.tar.gz", hash = "sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
adal = ">=0.6.0,<2.0.0"
|
||||||
|
msrest = ">=0.6.0,<2.0.0"
|
||||||
|
six = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mypy-extensions"
|
name = "mypy-extensions"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -2889,4 +2922,4 @@ docs = ["mkdocs", "mkdocs-material"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "18f9e44d555478c5d70cec7f39fc18263c54567a14ee0b100faf14f4d0cb8946"
|
content-hash = "594dc3dc4952b294042203c3338b6959fed04eb6eb181796a4ae8c27cde5bf32"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from msgraph.core import GraphClient
|
|||||||
|
|
||||||
from prowler.lib.logger import logger
|
from prowler.lib.logger import logger
|
||||||
from prowler.providers.azure.lib.audit_info.models import Azure_Identity_Info
|
from prowler.providers.azure.lib.audit_info.models import Azure_Identity_Info
|
||||||
|
from prowler.providers.azure.lib.regions.regions import get_regions_config
|
||||||
|
|
||||||
|
|
||||||
class Azure_Provider:
|
class Azure_Provider:
|
||||||
@@ -18,12 +19,14 @@ class Azure_Provider:
|
|||||||
managed_entity_auth: bool,
|
managed_entity_auth: bool,
|
||||||
subscription_ids: list,
|
subscription_ids: list,
|
||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
|
region: str,
|
||||||
):
|
):
|
||||||
logger.info("Instantiating Azure Provider ...")
|
logger.info("Instantiating Azure Provider ...")
|
||||||
self.credentials = self.__set_credentials__(
|
self.region_config = self.__get_region_config__(region)
|
||||||
|
self.credentials = self.__get_credentials__(
|
||||||
az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
|
az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
|
||||||
)
|
)
|
||||||
self.identity = self.__set_identity_info__(
|
self.identity = self.__get_identity_info__(
|
||||||
self.credentials,
|
self.credentials,
|
||||||
az_cli_auth,
|
az_cli_auth,
|
||||||
sp_env_auth,
|
sp_env_auth,
|
||||||
@@ -32,7 +35,10 @@ class Azure_Provider:
|
|||||||
subscription_ids,
|
subscription_ids,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __set_credentials__(
|
def __get_region_config__(self, region):
|
||||||
|
return get_regions_config(region)
|
||||||
|
|
||||||
|
def __get_credentials__(
|
||||||
self, az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
|
self, az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
|
||||||
):
|
):
|
||||||
# Browser auth creds cannot be set with DefaultAzureCredentials()
|
# Browser auth creds cannot be set with DefaultAzureCredentials()
|
||||||
@@ -52,6 +58,8 @@ class Azure_Provider:
|
|||||||
exclude_shared_token_cache_credential=True,
|
exclude_shared_token_cache_credential=True,
|
||||||
# Azure Auth using PowerShell is not supported
|
# Azure Auth using PowerShell is not supported
|
||||||
exclude_powershell_credential=True,
|
exclude_powershell_credential=True,
|
||||||
|
# set Authority of a Microsoft Entra endpoint
|
||||||
|
authority=self.region_config["authority"],
|
||||||
)
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.critical("Failed to retrieve azure credentials")
|
logger.critical("Failed to retrieve azure credentials")
|
||||||
@@ -61,7 +69,6 @@ class Azure_Provider:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
print(tenant_id)
|
|
||||||
credentials = InteractiveBrowserCredential(tenant_id=tenant_id)
|
credentials = InteractiveBrowserCredential(tenant_id=tenant_id)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.critical("Failed to retrieve azure credentials")
|
logger.critical("Failed to retrieve azure credentials")
|
||||||
@@ -83,7 +90,7 @@ class Azure_Provider:
|
|||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def __set_identity_info__(
|
def __get_identity_info__(
|
||||||
self,
|
self,
|
||||||
credentials,
|
credentials,
|
||||||
az_cli_auth,
|
az_cli_auth,
|
||||||
@@ -153,7 +160,11 @@ class Azure_Provider:
|
|||||||
logger.info(
|
logger.info(
|
||||||
"Trying to subscriptions and tenant ids to populate identity structure ..."
|
"Trying to subscriptions and tenant ids to populate identity structure ..."
|
||||||
)
|
)
|
||||||
subscriptions_client = SubscriptionClient(credential=credentials)
|
subscriptions_client = SubscriptionClient(
|
||||||
|
credential=credentials,
|
||||||
|
base_url=self.region_config["base_url"],
|
||||||
|
credential_scopes=self.region_config["credential_scopes"],
|
||||||
|
)
|
||||||
if not subscription_ids:
|
if not subscription_ids:
|
||||||
logger.info("Scanning all the Azure subscriptions...")
|
logger.info("Scanning all the Azure subscriptions...")
|
||||||
for subscription in subscriptions_client.subscriptions.list():
|
for subscription in subscriptions_client.subscriptions.list():
|
||||||
@@ -195,3 +206,6 @@ class Azure_Provider:
|
|||||||
|
|
||||||
def get_identity(self):
|
def get_identity(self):
|
||||||
return self.identity
|
return self.identity
|
||||||
|
|
||||||
|
def get_region_config(self):
|
||||||
|
return self.region_config
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
from argparse import ArgumentTypeError
|
||||||
|
|
||||||
|
|
||||||
def init_parser(self):
|
def init_parser(self):
|
||||||
"""Init the Azure Provider CLI parser"""
|
"""Init the Azure Provider CLI parser"""
|
||||||
azure_parser = self.subparsers.add_parser(
|
azure_parser = self.subparsers.add_parser(
|
||||||
@@ -40,3 +43,27 @@ def init_parser(self):
|
|||||||
default=None,
|
default=None,
|
||||||
help="Azure Tenant ID to be used with --browser-auth option",
|
help="Azure Tenant ID to be used with --browser-auth option",
|
||||||
)
|
)
|
||||||
|
# Regions
|
||||||
|
azure_regions_subparser = azure_parser.add_argument_group("Regions")
|
||||||
|
azure_regions_subparser.add_argument(
|
||||||
|
"--azure-region",
|
||||||
|
nargs="?",
|
||||||
|
default="AzureCloud",
|
||||||
|
type=validate_azure_region,
|
||||||
|
help="Azure region from `az cloud list --output table`, by default AzureCloud",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_azure_region(region):
|
||||||
|
"""validate_azure_region validates if the region passed as argument is valid"""
|
||||||
|
regions_allowed = [
|
||||||
|
"AzureChinaCloud",
|
||||||
|
"AzureUSGovernment",
|
||||||
|
"AzureGermanCloud",
|
||||||
|
"AzureCloud",
|
||||||
|
]
|
||||||
|
if region not in regions_allowed:
|
||||||
|
raise ArgumentTypeError(
|
||||||
|
f"Region {region} not allowed, allowed regions are {' '.join(regions_allowed)}"
|
||||||
|
)
|
||||||
|
return region
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from prowler.providers.azure.lib.audit_info.models import (
|
from prowler.providers.azure.lib.audit_info.models import (
|
||||||
Azure_Audit_Info,
|
Azure_Audit_Info,
|
||||||
Azure_Identity_Info,
|
Azure_Identity_Info,
|
||||||
|
Azure_Region_Config,
|
||||||
)
|
)
|
||||||
|
|
||||||
azure_audit_info = Azure_Audit_Info(
|
azure_audit_info = Azure_Audit_Info(
|
||||||
@@ -9,4 +10,5 @@ azure_audit_info = Azure_Audit_Info(
|
|||||||
audit_resources=None,
|
audit_resources=None,
|
||||||
audit_metadata=None,
|
audit_metadata=None,
|
||||||
audit_config=None,
|
audit_config=None,
|
||||||
|
azure_region_config=Azure_Region_Config(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ class Azure_Identity_Info(BaseModel):
|
|||||||
subscriptions: dict = {}
|
subscriptions: dict = {}
|
||||||
|
|
||||||
|
|
||||||
|
class Azure_Region_Config(BaseModel):
|
||||||
|
name: str = ""
|
||||||
|
authority: str = None
|
||||||
|
base_url: str = ""
|
||||||
|
credential_scopes: list = []
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Azure_Audit_Info:
|
class Azure_Audit_Info:
|
||||||
credentials: DefaultAzureCredential
|
credentials: DefaultAzureCredential
|
||||||
@@ -20,12 +27,20 @@ class Azure_Audit_Info:
|
|||||||
audit_resources: Optional[Any]
|
audit_resources: Optional[Any]
|
||||||
audit_metadata: Optional[Any]
|
audit_metadata: Optional[Any]
|
||||||
audit_config: dict
|
audit_config: dict
|
||||||
|
azure_region_config: Azure_Region_Config
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, credentials, identity, audit_metadata, audit_resources, audit_config
|
self,
|
||||||
|
credentials,
|
||||||
|
identity,
|
||||||
|
audit_metadata,
|
||||||
|
audit_resources,
|
||||||
|
audit_config,
|
||||||
|
azure_region_config,
|
||||||
):
|
):
|
||||||
self.credentials = credentials
|
self.credentials = credentials
|
||||||
self.identity = identity
|
self.identity = identity
|
||||||
self.audit_metadata = audit_metadata
|
self.audit_metadata = audit_metadata
|
||||||
self.audit_resources = audit_resources
|
self.audit_resources = audit_resources
|
||||||
self.audit_config = audit_config
|
self.audit_config = audit_config
|
||||||
|
self.azure_region_config = azure_region_config
|
||||||
|
|||||||
0
prowler/providers/azure/lib/regions/__init__.py
Normal file
0
prowler/providers/azure/lib/regions/__init__.py
Normal file
38
prowler/providers/azure/lib/regions/regions.py
Normal file
38
prowler/providers/azure/lib/regions/regions.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from azure.identity import AzureAuthorityHosts
|
||||||
|
from msrestazure.azure_cloud import (
|
||||||
|
AZURE_CHINA_CLOUD,
|
||||||
|
AZURE_GERMAN_CLOUD,
|
||||||
|
AZURE_US_GOV_CLOUD,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_regions_config(region):
|
||||||
|
allowed_regions = {
|
||||||
|
"AzureCloud": {
|
||||||
|
"authority": None,
|
||||||
|
"base_url": "https://management.azure.com",
|
||||||
|
"credential_scopes": ["https://management.azure.com/.default"],
|
||||||
|
},
|
||||||
|
"AzureChinaCloud": {
|
||||||
|
"authority": AzureAuthorityHosts.AZURE_CHINA,
|
||||||
|
"base_url": AZURE_CHINA_CLOUD.endpoints.resource_manager,
|
||||||
|
"credential_scopes": [
|
||||||
|
AZURE_CHINA_CLOUD.endpoints.resource_manager + "/.default"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"AzureUSGovernment": {
|
||||||
|
"authority": AzureAuthorityHosts.AZURE_GOVERNMENT,
|
||||||
|
"base_url": AZURE_US_GOV_CLOUD.endpoints.resource_manager,
|
||||||
|
"credential_scopes": [
|
||||||
|
AZURE_US_GOV_CLOUD.endpoints.resource_manager + "/.default"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"AzureGermanCloud": {
|
||||||
|
"authority": AzureAuthorityHosts.AZURE_GERMANY,
|
||||||
|
"base_url": AZURE_GERMAN_CLOUD.endpoints.resource_manager,
|
||||||
|
"credential_scopes": [
|
||||||
|
AZURE_GERMAN_CLOUD.endpoints.resource_manager + "/.default"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return allowed_regions[region]
|
||||||
@@ -9,17 +9,27 @@ class AzureService:
|
|||||||
audit_info: Azure_Audit_Info,
|
audit_info: Azure_Audit_Info,
|
||||||
):
|
):
|
||||||
self.clients = self.__set_clients__(
|
self.clients = self.__set_clients__(
|
||||||
audit_info.identity.subscriptions, audit_info.credentials, service
|
audit_info.identity.subscriptions,
|
||||||
|
audit_info.credentials,
|
||||||
|
service,
|
||||||
|
audit_info.azure_region_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.subscriptions = audit_info.identity.subscriptions
|
self.subscriptions = audit_info.identity.subscriptions
|
||||||
|
|
||||||
def __set_clients__(self, subscriptions, credentials, service):
|
def __set_clients__(self, subscriptions, credentials, service, region_config):
|
||||||
clients = {}
|
clients = {}
|
||||||
try:
|
try:
|
||||||
for display_name, id in subscriptions.items():
|
for display_name, id in subscriptions.items():
|
||||||
clients.update(
|
clients.update(
|
||||||
{display_name: service(credential=credentials, subscription_id=id)}
|
{
|
||||||
|
display_name: service(
|
||||||
|
credential=credentials,
|
||||||
|
subscription_id=id,
|
||||||
|
base_url=region_config.base_url,
|
||||||
|
credential_scopes=region_config.credential_scopes,
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ from prowler.providers.aws.lib.resource_api_tagging.resource_api_tagging import
|
|||||||
)
|
)
|
||||||
from prowler.providers.azure.azure_provider import Azure_Provider
|
from prowler.providers.azure.azure_provider import Azure_Provider
|
||||||
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
|
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
|
||||||
from prowler.providers.azure.lib.audit_info.models import Azure_Audit_Info
|
from prowler.providers.azure.lib.audit_info.models import (
|
||||||
|
Azure_Audit_Info,
|
||||||
|
Azure_Region_Config,
|
||||||
|
)
|
||||||
from prowler.providers.gcp.gcp_provider import GCP_Provider
|
from prowler.providers.gcp.gcp_provider import GCP_Provider
|
||||||
from prowler.providers.gcp.lib.audit_info.audit_info import gcp_audit_info
|
from prowler.providers.gcp.lib.audit_info.audit_info import gcp_audit_info
|
||||||
from prowler.providers.gcp.lib.audit_info.models import GCP_Audit_Info
|
from prowler.providers.gcp.lib.audit_info.models import GCP_Audit_Info
|
||||||
@@ -63,7 +66,7 @@ GCP Account: {Fore.YELLOW}[{profile}]{Style.RESET_ALL} GCP Project IDs: {Fore.Y
|
|||||||
report = f"""
|
report = f"""
|
||||||
This report is being generated using the identity below:
|
This report is being generated using the identity below:
|
||||||
|
|
||||||
Azure Tenant IDs: {Fore.YELLOW}[{" ".join(audit_info.identity.tenant_ids)}]{Style.RESET_ALL} Azure Tenant Domain: {Fore.YELLOW}[{audit_info.identity.domain}]{Style.RESET_ALL}
|
Azure Tenant IDs: {Fore.YELLOW}[{" ".join(audit_info.identity.tenant_ids)}]{Style.RESET_ALL} Azure Tenant Domain: {Fore.YELLOW}[{audit_info.identity.domain}]{Style.RESET_ALL} Azure Region: {Fore.YELLOW}[{audit_info.azure_region_config.name}]{Style.RESET_ALL}
|
||||||
Azure Subscriptions: {Fore.YELLOW}{printed_subscriptions}{Style.RESET_ALL}
|
Azure Subscriptions: {Fore.YELLOW}{printed_subscriptions}{Style.RESET_ALL}
|
||||||
Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RESET_ALL} Azure Identity ID: {Fore.YELLOW}[{audit_info.identity.identity_id}]{Style.RESET_ALL}
|
Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RESET_ALL} Azure Identity ID: {Fore.YELLOW}[{audit_info.identity.identity_id}]{Style.RESET_ALL}
|
||||||
"""
|
"""
|
||||||
@@ -282,6 +285,10 @@ Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RE
|
|||||||
browser_auth = arguments.get("browser_auth")
|
browser_auth = arguments.get("browser_auth")
|
||||||
managed_entity_auth = arguments.get("managed_entity_auth")
|
managed_entity_auth = arguments.get("managed_entity_auth")
|
||||||
tenant_id = arguments.get("tenant_id")
|
tenant_id = arguments.get("tenant_id")
|
||||||
|
|
||||||
|
logger.info("Checking if region is different than default one")
|
||||||
|
region = arguments.get("azure_region")
|
||||||
|
|
||||||
if (
|
if (
|
||||||
not az_cli_auth
|
not az_cli_auth
|
||||||
and not sp_env_auth
|
and not sp_env_auth
|
||||||
@@ -303,9 +310,17 @@ Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RE
|
|||||||
managed_entity_auth,
|
managed_entity_auth,
|
||||||
subscription_ids,
|
subscription_ids,
|
||||||
tenant_id,
|
tenant_id,
|
||||||
|
region,
|
||||||
)
|
)
|
||||||
azure_audit_info.credentials = azure_provider.get_credentials()
|
azure_audit_info.credentials = azure_provider.get_credentials()
|
||||||
azure_audit_info.identity = azure_provider.get_identity()
|
azure_audit_info.identity = azure_provider.get_identity()
|
||||||
|
region_config = azure_provider.get_region_config()
|
||||||
|
azure_audit_info.azure_region_config = Azure_Region_Config(
|
||||||
|
name=region,
|
||||||
|
authority=region_config["authority"],
|
||||||
|
base_url=region_config["base_url"],
|
||||||
|
credential_scopes=region_config["credential_scopes"],
|
||||||
|
)
|
||||||
|
|
||||||
if not arguments.get("only_logs"):
|
if not arguments.get("only_logs"):
|
||||||
self.print_azure_credentials(azure_audit_info)
|
self.print_azure_credentials(azure_audit_info)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ google-auth-httplib2 = "^0.1.0"
|
|||||||
mkdocs = {version = "1.5.3", optional = true}
|
mkdocs = {version = "1.5.3", optional = true}
|
||||||
mkdocs-material = {version = "9.4.8", optional = true}
|
mkdocs-material = {version = "9.4.8", optional = true}
|
||||||
msgraph-core = "0.2.2"
|
msgraph-core = "0.2.2"
|
||||||
|
msrestazure = "^0.6.4"
|
||||||
pydantic = "1.10.13"
|
pydantic = "1.10.13"
|
||||||
python = "^3.9"
|
python = "^3.9"
|
||||||
schema = "0.7.5"
|
schema = "0.7.5"
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
from argparse import ArgumentTypeError
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from mock import patch
|
from mock import patch
|
||||||
|
|
||||||
from prowler.lib.cli.parser import ProwlerArgumentParser
|
from prowler.lib.cli.parser import ProwlerArgumentParser
|
||||||
|
from prowler.providers.azure.lib.arguments.arguments import validate_azure_region
|
||||||
|
|
||||||
prowler_command = "prowler"
|
prowler_command = "prowler"
|
||||||
|
|
||||||
@@ -1050,6 +1052,14 @@ class Test_Parser:
|
|||||||
assert parsed.subscription_ids[0] == subscription_1
|
assert parsed.subscription_ids[0] == subscription_1
|
||||||
assert parsed.subscription_ids[1] == subscription_2
|
assert parsed.subscription_ids[1] == subscription_2
|
||||||
|
|
||||||
|
def test_parser_azure_region(self):
|
||||||
|
argument = "--azure-region"
|
||||||
|
region = "AzureChinaCloud"
|
||||||
|
command = [prowler_command, "azure", argument, region]
|
||||||
|
parsed = self.parser.parse(command)
|
||||||
|
assert parsed.provider == "azure"
|
||||||
|
assert parsed.azure_region == region
|
||||||
|
|
||||||
# Test AWS flags with Azure provider
|
# Test AWS flags with Azure provider
|
||||||
def test_parser_azure_with_aws_flag(self, capsys):
|
def test_parser_azure_with_aws_flag(self, capsys):
|
||||||
command = [prowler_command, "azure", "-p"]
|
command = [prowler_command, "azure", "-p"]
|
||||||
@@ -1092,3 +1102,33 @@ class Test_Parser:
|
|||||||
assert len(parsed.project_ids) == 2
|
assert len(parsed.project_ids) == 2
|
||||||
assert parsed.project_ids[0] == project_1
|
assert parsed.project_ids[0] == project_1
|
||||||
assert parsed.project_ids[1] == project_2
|
assert parsed.project_ids[1] == project_2
|
||||||
|
|
||||||
|
def test_validate_azure_region_valid_regions(self):
|
||||||
|
expected_regions = [
|
||||||
|
"AzureChinaCloud",
|
||||||
|
"AzureUSGovernment",
|
||||||
|
"AzureGermanCloud",
|
||||||
|
"AzureCloud",
|
||||||
|
]
|
||||||
|
input_regions = [
|
||||||
|
"AzureChinaCloud",
|
||||||
|
"AzureUSGovernment",
|
||||||
|
"AzureGermanCloud",
|
||||||
|
"AzureCloud",
|
||||||
|
]
|
||||||
|
for region in input_regions:
|
||||||
|
assert validate_azure_region(region) in expected_regions
|
||||||
|
|
||||||
|
def test_validate_azure_region_invalid_regions(self):
|
||||||
|
expected_regions = [
|
||||||
|
"AzureChinaCloud",
|
||||||
|
"AzureUSGovernment",
|
||||||
|
"AzureGermanCloud",
|
||||||
|
"AzureCloud",
|
||||||
|
]
|
||||||
|
invalid_region = "non-valid-region"
|
||||||
|
with pytest.raises(
|
||||||
|
ArgumentTypeError,
|
||||||
|
match=f"Region {invalid_region} not allowed, allowed regions are {' '.join(expected_regions)}",
|
||||||
|
):
|
||||||
|
validate_azure_region(invalid_region)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info
|
|||||||
from prowler.providers.azure.lib.audit_info.models import (
|
from prowler.providers.azure.lib.audit_info.models import (
|
||||||
Azure_Audit_Info,
|
Azure_Audit_Info,
|
||||||
Azure_Identity_Info,
|
Azure_Identity_Info,
|
||||||
|
Azure_Region_Config,
|
||||||
)
|
)
|
||||||
from prowler.providers.common.models import Audit_Metadata
|
from prowler.providers.common.models import Audit_Metadata
|
||||||
from prowler.providers.gcp.lib.audit_info.models import GCP_Audit_Info
|
from prowler.providers.gcp.lib.audit_info.models import GCP_Audit_Info
|
||||||
@@ -76,6 +77,7 @@ class Test_Slack_Integration:
|
|||||||
audit_resources=None,
|
audit_resources=None,
|
||||||
audit_metadata=None,
|
audit_metadata=None,
|
||||||
audit_config=None,
|
audit_config=None,
|
||||||
|
azure_region_config=Azure_Region_Config(),
|
||||||
)
|
)
|
||||||
assert create_message_identity("aws", aws_audit_info) == (
|
assert create_message_identity("aws", aws_audit_info) == (
|
||||||
f"AWS Account *{aws_audit_info.audited_account}*",
|
f"AWS Account *{aws_audit_info.audited_account}*",
|
||||||
|
|||||||
50
tests/providers/azure/lib/regions/regions_test.py
Normal file
50
tests/providers/azure/lib/regions/regions_test.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
from azure.identity import AzureAuthorityHosts
|
||||||
|
from msrestazure.azure_cloud import (
|
||||||
|
AZURE_CHINA_CLOUD,
|
||||||
|
AZURE_GERMAN_CLOUD,
|
||||||
|
AZURE_US_GOV_CLOUD,
|
||||||
|
)
|
||||||
|
|
||||||
|
from prowler.providers.azure.lib.regions.regions import get_regions_config
|
||||||
|
|
||||||
|
|
||||||
|
class Test_azure_regions:
|
||||||
|
def test_get_regions_config(self):
|
||||||
|
allowed_regions = [
|
||||||
|
"AzureCloud",
|
||||||
|
"AzureChinaCloud",
|
||||||
|
"AzureUSGovernment",
|
||||||
|
"AzureGermanCloud",
|
||||||
|
]
|
||||||
|
expected_output = {
|
||||||
|
"AzureCloud": {
|
||||||
|
"authority": None,
|
||||||
|
"base_url": "https://management.azure.com",
|
||||||
|
"credential_scopes": ["https://management.azure.com/.default"],
|
||||||
|
},
|
||||||
|
"AzureChinaCloud": {
|
||||||
|
"authority": AzureAuthorityHosts.AZURE_CHINA,
|
||||||
|
"base_url": AZURE_CHINA_CLOUD.endpoints.resource_manager,
|
||||||
|
"credential_scopes": [
|
||||||
|
AZURE_CHINA_CLOUD.endpoints.resource_manager + "/.default"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"AzureUSGovernment": {
|
||||||
|
"authority": AzureAuthorityHosts.AZURE_GOVERNMENT,
|
||||||
|
"base_url": AZURE_US_GOV_CLOUD.endpoints.resource_manager,
|
||||||
|
"credential_scopes": [
|
||||||
|
AZURE_US_GOV_CLOUD.endpoints.resource_manager + "/.default"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"AzureGermanCloud": {
|
||||||
|
"authority": AzureAuthorityHosts.AZURE_GERMANY,
|
||||||
|
"base_url": AZURE_GERMAN_CLOUD.endpoints.resource_manager,
|
||||||
|
"credential_scopes": [
|
||||||
|
AZURE_GERMAN_CLOUD.endpoints.resource_manager + "/.default"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for region in allowed_regions:
|
||||||
|
region_config = get_regions_config(region)
|
||||||
|
assert region_config == expected_output[region]
|
||||||
@@ -11,6 +11,7 @@ from prowler.providers.azure.azure_provider import Azure_Provider
|
|||||||
from prowler.providers.azure.lib.audit_info.models import (
|
from prowler.providers.azure.lib.audit_info.models import (
|
||||||
Azure_Audit_Info,
|
Azure_Audit_Info,
|
||||||
Azure_Identity_Info,
|
Azure_Identity_Info,
|
||||||
|
Azure_Region_Config,
|
||||||
)
|
)
|
||||||
from prowler.providers.common.audit_info import (
|
from prowler.providers.common.audit_info import (
|
||||||
Audit_Info,
|
Audit_Info,
|
||||||
@@ -31,6 +32,7 @@ mock_azure_audit_info = Azure_Audit_Info(
|
|||||||
audit_metadata=None,
|
audit_metadata=None,
|
||||||
audit_resources=None,
|
audit_resources=None,
|
||||||
audit_config=None,
|
audit_config=None,
|
||||||
|
azure_region_config=Azure_Region_Config(),
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_set_audit_info = Audit_Info()
|
mock_set_audit_info = Audit_Info()
|
||||||
@@ -132,8 +134,8 @@ class Test_Set_Audit_Info:
|
|||||||
"prowler.providers.common.audit_info.azure_audit_info",
|
"prowler.providers.common.audit_info.azure_audit_info",
|
||||||
new=mock_azure_audit_info,
|
new=mock_azure_audit_info,
|
||||||
)
|
)
|
||||||
@patch.object(Azure_Provider, "__set_credentials__", new=mock_set_azure_credentials)
|
@patch.object(Azure_Provider, "__get_credentials__", new=mock_set_azure_credentials)
|
||||||
@patch.object(Azure_Provider, "__set_identity_info__", new=mock_set_identity_info)
|
@patch.object(Azure_Provider, "__get_identity_info__", new=mock_set_identity_info)
|
||||||
def test_set_audit_info_azure(self):
|
def test_set_audit_info_azure(self):
|
||||||
provider = "azure"
|
provider = "azure"
|
||||||
arguments = {
|
arguments = {
|
||||||
@@ -150,6 +152,7 @@ class Test_Set_Audit_Info:
|
|||||||
"browser_auth": None,
|
"browser_auth": None,
|
||||||
"managed_entity_auth": None,
|
"managed_entity_auth": None,
|
||||||
"config_file": default_config_file_path,
|
"config_file": default_config_file_path,
|
||||||
|
"azure_region": "AzureCloud",
|
||||||
}
|
}
|
||||||
|
|
||||||
audit_info = set_provider_audit_info(provider, arguments)
|
audit_info = set_provider_audit_info(provider, arguments)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from prowler.providers.aws.lib.audit_info.audit_info import AWS_Audit_Info
|
|||||||
from prowler.providers.azure.lib.audit_info.audit_info import (
|
from prowler.providers.azure.lib.audit_info.audit_info import (
|
||||||
Azure_Audit_Info,
|
Azure_Audit_Info,
|
||||||
Azure_Identity_Info,
|
Azure_Identity_Info,
|
||||||
|
Azure_Region_Config,
|
||||||
)
|
)
|
||||||
from prowler.providers.common.models import Audit_Metadata
|
from prowler.providers.common.models import Audit_Metadata
|
||||||
from prowler.providers.common.outputs import (
|
from prowler.providers.common.outputs import (
|
||||||
@@ -33,6 +34,7 @@ class Test_Common_Output_Options:
|
|||||||
audit_metadata=None,
|
audit_metadata=None,
|
||||||
audit_resources=None,
|
audit_resources=None,
|
||||||
audit_config=None,
|
audit_config=None,
|
||||||
|
azure_region_config=Azure_Region_Config(),
|
||||||
)
|
)
|
||||||
return audit_info
|
return audit_info
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user