From a8211e901367bcc4820697fadf63d849cbfc718d Mon Sep 17 00:00:00 2001 From: pedrooot Date: Fri, 14 Mar 2025 11:16:47 +0100 Subject: [PATCH] fix(azure): handle credentials scopes for Graph --- prowler/providers/azure/azure_provider.py | 13 ++++++++++--- prowler/providers/azure/lib/regions/regions.py | 13 +++++++++++-- prowler/providers/azure/lib/service/service.py | 9 ++++++++- prowler/providers/azure/models.py | 1 + tests/providers/azure/azure_provider_test.py | 1 + tests/providers/azure/lib/regions/regions_test.py | 10 ++++++++++ 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/prowler/providers/azure/azure_provider.py b/prowler/providers/azure/azure_provider.py index 64377ca07e..8d97bc647d 100644 --- a/prowler/providers/azure/azure_provider.py +++ b/prowler/providers/azure/azure_provider.py @@ -406,6 +406,7 @@ class AzureProvider(Provider): authority=config["authority"], base_url=config["base_url"], credential_scopes=config["credential_scopes"], + graph_credential_scopes=config["graph_credential_scopes"], ) except ArgumentTypeError as validation_error: logger.error( @@ -891,7 +892,10 @@ class AzureProvider(Provider): logger.info( "Trying to retrieve tenant domain from AAD to populate identity structure ..." ) - client = GraphServiceClient(credentials=credentials) + client = GraphServiceClient( + credentials=credentials, + scopes=self.region_config.graph_credential_scopes, + ) domain_result = await client.domains.get() if getattr(domain_result, "value"): @@ -930,9 +934,12 @@ class AzureProvider(Provider): identity.identity_type = "User" try: logger.info( - "Trying to retrieve user information from AAD to populate identity structure ..." + "Trying to retrieve user information from Microsoft Graph to populate identity structure ..." + ) + client = GraphServiceClient( + credentials=credentials, + scopes=self.region_config.graph_credential_scopes, ) - client = GraphServiceClient(credentials=credentials) me = await client.me.get() if me: diff --git a/prowler/providers/azure/lib/regions/regions.py b/prowler/providers/azure/lib/regions/regions.py index 6b88ab5561..15226be299 100644 --- a/prowler/providers/azure/lib/regions/regions.py +++ b/prowler/providers/azure/lib/regions/regions.py @@ -1,8 +1,14 @@ from azure.identity import AzureAuthorityHosts -AZURE_CHINA_CLOUD = "https://management.chinacloudapi.cn" -AZURE_US_GOV_CLOUD = "https://management.usgovcloudapi.net" AZURE_GENERIC_CLOUD = "https://management.azure.com" +AZURE_GRAPH_GLOBAL = "https://graph.microsoft.com/.default" + +AZURE_US_GOV_CLOUD = "https://management.usgovcloudapi.net" +AZURE_GRAPH_GOV_US_L4 = "https://graph.microsoft.us/.default" +AZURE_GRAPH_GOV_US_L5 = "https://dod-graph.microsoft.us/.default" + +AZURE_CHINA_CLOUD = "https://management.chinacloudapi.cn" +AZURE_GRAPH_CHINA = "https://microsoftgraph.chinacloudapi.cn/.default" def get_regions_config(region): @@ -11,16 +17,19 @@ def get_regions_config(region): "authority": None, "base_url": AZURE_GENERIC_CLOUD, "credential_scopes": [AZURE_GENERIC_CLOUD + "/.default"], + "graph_credential_scopes": [AZURE_GRAPH_GLOBAL], }, "AzureChinaCloud": { "authority": AzureAuthorityHosts.AZURE_CHINA, "base_url": AZURE_CHINA_CLOUD, "credential_scopes": [AZURE_CHINA_CLOUD + "/.default"], + "graph_credential_scopes": [AZURE_GRAPH_CHINA], }, "AzureUSGovernment": { "authority": AzureAuthorityHosts.AZURE_GOVERNMENT, "base_url": AZURE_US_GOV_CLOUD, "credential_scopes": [AZURE_US_GOV_CLOUD + "/.default"], + "graph_credential_scopes": [AZURE_GRAPH_GOV_US_L4, AZURE_GRAPH_GOV_US_L5], }, } return allowed_regions[region] diff --git a/prowler/providers/azure/lib/service/service.py b/prowler/providers/azure/lib/service/service.py index 83ed9031f4..99fe03ea35 100644 --- a/prowler/providers/azure/lib/service/service.py +++ b/prowler/providers/azure/lib/service/service.py @@ -24,7 +24,14 @@ class AzureService: clients = {} try: if "GraphServiceClient" in str(service): - clients.update({identity.tenant_domain: service(credentials=session)}) + clients.update( + { + identity.tenant_domain: service( + credentials=session, + scopes=region_config.graph_credential_scopes, + ) + } + ) else: for display_name, id in identity.subscriptions.items(): clients.update( diff --git a/prowler/providers/azure/models.py b/prowler/providers/azure/models.py index cf0cd4be9b..c469238c83 100644 --- a/prowler/providers/azure/models.py +++ b/prowler/providers/azure/models.py @@ -18,6 +18,7 @@ class AzureRegionConfig(BaseModel): authority: str = None base_url: str = "" credential_scopes: list = [] + graph_credential_scopes: list = [] class AzureSubscription(BaseModel): diff --git a/tests/providers/azure/azure_provider_test.py b/tests/providers/azure/azure_provider_test.py index e5e93bad6b..fcd165b151 100644 --- a/tests/providers/azure/azure_provider_test.py +++ b/tests/providers/azure/azure_provider_test.py @@ -69,6 +69,7 @@ class TestAzureProvider: authority=None, base_url="https://management.azure.com", credential_scopes=["https://management.azure.com/.default"], + graph_credential_scopes=["https://graph.microsoft.com/.default"], ) assert isinstance(azure_provider.session, DefaultAzureCredential) assert azure_provider.identity == AzureIdentityInfo( diff --git a/tests/providers/azure/lib/regions/regions_test.py b/tests/providers/azure/lib/regions/regions_test.py index 2f8fdd6053..06e5d973c9 100644 --- a/tests/providers/azure/lib/regions/regions_test.py +++ b/tests/providers/azure/lib/regions/regions_test.py @@ -3,6 +3,10 @@ from azure.identity import AzureAuthorityHosts from prowler.providers.azure.lib.regions.regions import ( AZURE_CHINA_CLOUD, AZURE_GENERIC_CLOUD, + AZURE_GRAPH_CHINA, + AZURE_GRAPH_GLOBAL, + AZURE_GRAPH_GOV_US_L4, + AZURE_GRAPH_GOV_US_L5, AZURE_US_GOV_CLOUD, get_regions_config, ) @@ -20,16 +24,22 @@ class Test_azure_regions: "authority": None, "base_url": AZURE_GENERIC_CLOUD, "credential_scopes": [AZURE_GENERIC_CLOUD + "/.default"], + "graph_credential_scopes": [AZURE_GRAPH_GLOBAL], }, "AzureChinaCloud": { "authority": AzureAuthorityHosts.AZURE_CHINA, "base_url": AZURE_CHINA_CLOUD, "credential_scopes": [AZURE_CHINA_CLOUD + "/.default"], + "graph_credential_scopes": [AZURE_GRAPH_CHINA], }, "AzureUSGovernment": { "authority": AzureAuthorityHosts.AZURE_GOVERNMENT, "base_url": AZURE_US_GOV_CLOUD, "credential_scopes": [AZURE_US_GOV_CLOUD + "/.default"], + "graph_credential_scopes": [ + AZURE_GRAPH_GOV_US_L4, + AZURE_GRAPH_GOV_US_L5, + ], }, }