From e5e01e51a91b43196272ff6626d3082b43f37f3b Mon Sep 17 00:00:00 2001 From: Nacho Rivera <59198746+n4ch04@users.noreply.github.com> Date: Tue, 29 Nov 2022 13:46:38 +0100 Subject: [PATCH] feat(azure): subscription as parameter (#1526) --- lib/outputs/outputs.py | 5 +++++ providers/azure/azure_provider.py | 21 +++++++++++++++------ providers/azure/lib/audit_info/models.py | 2 +- prowler | 12 +++++++++++- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/lib/outputs/outputs.py b/lib/outputs/outputs.py index b08f7fbf..bf79fd98 100644 --- a/lib/outputs/outputs.py +++ b/lib/outputs/outputs.py @@ -468,6 +468,7 @@ def display_summary_table( entity_type = "Account" elif provider == "azure": entity_type = "Tenant Domain" + if findings: current = { "Service": "", @@ -533,6 +534,10 @@ def display_summary_table( print( f"\n{entity_type} {Fore.YELLOW}{audit_info.audited_account}{Style.RESET_ALL} Scan Results (severity columns are for fails only):" ) + if provider == "azure": + print( + f"\nSubscriptions scanned: {Fore.YELLOW}{' '.join(audit_info.subscriptions.keys())}{Style.RESET_ALL}" + ) print(tabulate(findings_table, headers="keys", tablefmt="rounded_grid")) print( f"{Style.BRIGHT}* You only see here those services that contains resources.{Style.RESET_ALL}" diff --git a/providers/azure/azure_provider.py b/providers/azure/azure_provider.py index dbd34608..9c09b918 100644 --- a/providers/azure/azure_provider.py +++ b/providers/azure/azure_provider.py @@ -7,7 +7,7 @@ from msgraph.core import GraphClient from lib.logger import logger from providers.azure.lib.audit_info.audit_info import azure_audit_info -from providers.azure.lib.audit_info.models import Azure_Identity_Info +from providers.azure.lib.audit_info.models import Azure_Audit_Info, Azure_Identity_Info class Azure_Provider: @@ -54,7 +54,7 @@ def validate_credentials( return azure_identity -def azure_provider_set_session(): +def azure_provider_set_session(subscription_ids: list) -> Azure_Audit_Info: logger.info("Setting Azure session ...") azure_identity = check_credential_env_vars() azure_audit_info.credentials = Azure_Provider().get_credentials() @@ -69,11 +69,20 @@ def azure_provider_set_session(): subscriptions_client = SubscriptionClient( credential=azure_audit_info.credentials ) - for subscription in subscriptions_client.subscriptions.list(): + if not subscription_ids: + logger.info("Scanning all the Azure subscriptions...") + for subscription in subscriptions_client.subscriptions.list(): - azure_audit_info.subscriptions.update( - {subscription.display_name: subscription.subscription_id} - ) + azure_audit_info.subscriptions.update( + {subscription.display_name: subscription.subscription_id} + ) + else: + logger.info("Scanning the subscriptions passed as argument ...") + for id in subscription_ids: + subscription = subscriptions_client.subscriptions.get( + subscription_id=id + ) + azure_audit_info.subscriptions.update({subscription.display_name: id}) except Exception as error: logger.critical( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" diff --git a/providers/azure/lib/audit_info/models.py b/providers/azure/lib/audit_info/models.py index 1aabc50e..425e819b 100644 --- a/providers/azure/lib/audit_info/models.py +++ b/providers/azure/lib/audit_info/models.py @@ -14,7 +14,7 @@ class Azure_Identity_Info(BaseModel): class Azure_Audit_Info: credentials: DefaultAzureCredential identity: Azure_Identity_Info - subscriptions: list[dict] + subscriptions: dict audited_account: str def __init__(self, credentials, identity, subscriptions): diff --git a/prowler b/prowler index c94fd985..897d524a 100755 --- a/prowler +++ b/prowler @@ -230,6 +230,12 @@ if __name__ == "__main__": action="store_true", help="Display detailed information about findings.", ) + parser.add_argument( + "--subscription-ids", + nargs="+", + default=[], + help="Azure subscription ids to be scanned by prowler", + ) # Parse Arguments args = parser.parse_args() @@ -245,6 +251,10 @@ if __name__ == "__main__": severities = args.severity compliance_framework = args.compliance output_modes = args.output_modes + + # Azure options + subscriptions = args.subscription_ids + # We treat the compliance framework as another output format if compliance_framework: output_modes.extend(compliance_framework) @@ -363,7 +373,7 @@ if __name__ == "__main__": args.organizations_role, ) elif provider == "azure": - audit_info = azure_provider_set_session() + audit_info = azure_provider_set_session(subscriptions) # Check if custom output filename was input, if not, set the default if not output_filename: