chore(azure): working version executing checks (#3472)

Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
This commit is contained in:
Pepe Fagoaga
2024-03-01 11:33:01 +01:00
committed by GitHub
parent fc03dd37f1
commit b48b3a5e2e
36 changed files with 272 additions and 454 deletions
+3
View File
@@ -185,10 +185,13 @@ def prowler():
checks_to_execute = sorted(checks_to_execute)
# Parse Mute List
mutelist_file = ""
if hasattr(args, "mutelist_file"):
mutelist_file = global_provider.get_mutelist(args.mutelist_file)
# Set output options based on the selected provider
# TODO: this is going to be removed an include in the Provider as a new common object
audit_output_options = set_provider_output_options(
provider, args, global_provider.identity, mutelist_file, bulk_checks_metadata
)
+1 -1
View File
@@ -41,7 +41,6 @@ from prowler.providers.common.provider import Provider
class AwsProvider(Provider):
provider: str = "aws"
session: AWSSession = AWSSession(
session=None, session_config=None, original_session=None
)
@@ -85,6 +84,7 @@ class AwsProvider(Provider):
def __init__(self, arguments: Namespace):
logger.info("Setting AWS provider ...")
self.provider = "aws"
# Parse input arguments
# Assume Role Options
input_role = getattr(arguments, "role", None)
@@ -1,4 +1,4 @@
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
from prowler.providers.aws.services.cognito.cognito_service import CognitoIDP
from prowler.providers.common.common import get_global_provider
cognito_idp_client = CognitoIDP(current_audit_info)
cognito_idp_client = CognitoIDP(get_global_provider())
@@ -10,8 +10,8 @@ from prowler.providers.aws.lib.service.service import AWSService
################## CognitoIDP
class CognitoIDP(AWSService):
def __init__(self, audit_info):
super().__init__("cognito-idp", audit_info)
def __init__(self, provider):
super().__init__("cognito-idp", provider)
self.user_pools = {}
self.__threading_call__(self.__list_user_pools__)
self.__describe_user_pools__()
+95 -39
View File
@@ -1,52 +1,117 @@
import asyncio
import sys
from os import getenv
from typing import Any, Optional
import requests
from azure.identity import DefaultAzureCredential, InteractiveBrowserCredential
from azure.mgmt.subscription import SubscriptionClient
from colorama import Fore, Style
from msgraph import GraphServiceClient
from prowler.lib.logger import logger
from prowler.providers.azure.lib.audit_info.models import AzureIdentityInfo
from prowler.providers.azure.lib.regions.regions import get_regions_config
from prowler.providers.azure.models import AzureIdentityInfo, AzureRegionConfig
from prowler.providers.common.provider import Provider
class Azure_Provider:
def __init__(
self,
az_cli_auth: bool,
sp_env_auth: bool,
browser_auth: bool,
managed_entity_auth: bool,
subscription_ids: list,
tenant_id: str,
region: str,
):
logger.info("Instantiating Azure Provider ...")
self.region_config = self.__get_region_config__(region)
self.credentials = self.__get_credentials__(
class AzureProvider(Provider):
session: DefaultAzureCredential
identity: AzureIdentityInfo
audit_resources: Optional[Any]
audit_metadata: Optional[Any]
audit_config: dict
region_config: AzureRegionConfig
def __init__(self, arguments):
logger.info("Setting Azure provider ...")
self.provider = "azure"
subscription_ids = arguments.subscription_ids
logger.info("Checking if any credentials mode is set ...")
az_cli_auth = arguments.az_cli_auth
sp_env_auth = arguments.sp_env_auth
browser_auth = arguments.browser_auth
managed_entity_auth = arguments.managed_identity_auth
tenant_id = arguments.tenant_id
logger.info("Checking if region is different than default one")
region = arguments.azure_region
self.validate_arguments(
az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
)
self.identity = self.__get_identity_info__(
self.credentials,
self.region_config = self.setup_region_config(region)
self.session = self.setup_session(
az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
)
self.identity = self.setup_identity(
az_cli_auth,
sp_env_auth,
browser_auth,
managed_entity_auth,
subscription_ids,
)
if not arguments.only_logs:
self.print_credentials()
def __get_region_config__(self, region):
return get_regions_config(region)
# TODO: should we keep this here or within the identity?
self.locations = self.get_locations(self.session, self.region_config)
# TODO: move this to the providers, pending for AWS, GCP, AZURE and K8s
self.audit_config = {}
def __get_credentials__(
def validate_arguments(
self, az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
):
if (
not az_cli_auth
and not sp_env_auth
and not browser_auth
and not managed_entity_auth
):
raise SystemExit(
"Azure provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth | --managed-identity-auth]"
)
elif browser_auth and not tenant_id:
raise SystemExit(
"Azure Tenant ID (--tenant-id) is required for browser authentication mode"
)
# There is no need to handle that since it won't get here
elif not browser_auth and tenant_id:
raise SystemExit(
"Azure Tenant ID (--tenant-id) is required only for browser authentication mode"
)
def setup_region_config(self, region):
config = get_regions_config(region)
return AzureRegionConfig(
name=region,
authority=config["authority"],
base_url=config["base_url"],
credential_scopes=config["credential_scopes"],
)
def print_credentials(self):
printed_subscriptions = []
for key, value in self.identity.subscriptions.items():
intermediate = key + ": " + value
printed_subscriptions.append(intermediate)
report = f"""
This report is being generated using the identity below:
Azure Tenant IDs: {Fore.YELLOW}[{" ".join(self.identity.tenant_ids)}]{Style.RESET_ALL} Azure Tenant Domain: {Fore.YELLOW}[{self.identity.domain}]{Style.RESET_ALL} Azure Region: {Fore.YELLOW}[{self.region_config.name}]{Style.RESET_ALL}
Azure Subscriptions: {Fore.YELLOW}{printed_subscriptions}{Style.RESET_ALL}
Azure Identity Type: {Fore.YELLOW}[{self.identity.identity_type}]{Style.RESET_ALL} Azure Identity ID: {Fore.YELLOW}[{self.identity.identity_id}]{Style.RESET_ALL}
"""
print(report)
# TODO: setup_session or setup_credentials?
def setup_session(
self, az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
):
# Browser auth creds cannot be set with DefaultAzureCredentials()
if not browser_auth:
if sp_env_auth:
self.__check_sp_creds_env_vars__()
self.__check_service_principal_creds_env_vars__()
try:
# Since the input vars come as True when it is wanted to be used, we need to inverse it since
# DefaultAzureCredential sets the auth method excluding the others
@@ -61,7 +126,7 @@ class Azure_Provider:
# Azure Auth using PowerShell is not supported
exclude_powershell_credential=True,
# set Authority of a Microsoft Entra endpoint
authority=self.region_config["authority"],
authority=self.region_config.authority,
)
except Exception as error:
logger.critical("Failed to retrieve azure credentials")
@@ -81,7 +146,7 @@ class Azure_Provider:
return credentials
def __check_sp_creds_env_vars__(self):
def __check_service_principal_creds_env_vars__(self):
logger.info(
"Azure provider: checking service principal environment variables ..."
)
@@ -92,15 +157,16 @@ class Azure_Provider:
)
sys.exit(1)
def __get_identity_info__(
def setup_identity(
self,
credentials,
az_cli_auth,
sp_env_auth,
browser_auth,
managed_entity_auth,
subscription_ids,
):
credentials = self.session
# TODO: fill this object with real values not default and set to none
identity = AzureIdentityInfo()
# If credentials comes from service principal or browser, if the required permissions are assigned
@@ -153,7 +219,6 @@ class Azure_Provider:
)
asyncio.run(get_azure_identity())
# Managed identities only can be assigned resource, resource group and subscription scope permissions
elif managed_entity_auth:
identity.identity_id = "Default Managed Identity ID"
@@ -167,8 +232,8 @@ class Azure_Provider:
)
subscriptions_client = SubscriptionClient(
credential=credentials,
base_url=self.region_config["base_url"],
credential_scopes=self.region_config["credential_scopes"],
base_url=self.region_config.base_url,
credential_scopes=self.region_config.credential_scopes,
)
if not subscription_ids:
logger.info("Scanning all the Azure subscriptions...")
@@ -206,22 +271,13 @@ class Azure_Provider:
return identity
def get_credentials(self):
return self.credentials
def get_identity(self):
return self.identity
def get_region_config(self):
return self.region_config
def get_locations(self, credentials, region_config):
locations = None
if credentials and region_config:
subscriptions_client = SubscriptionClient(
credential=credentials,
base_url=region_config["base_url"],
credential_scopes=region_config["credential_scopes"],
base_url=region_config.base_url,
credential_scopes=region_config.credential_scopes,
)
list_subscriptions = subscriptions_client.subscriptions.list()
list_subscriptions_ids = [
@@ -1,270 +0,0 @@
import sys
from os import getenv
from typing import Any, Optional
from azure.identity import DefaultAzureCredential, InteractiveBrowserCredential
from azure.mgmt.subscription import SubscriptionClient
from colorama import Fore, Style
from msgraph.core import GraphClient
from pydantic import BaseModel
from prowler.lib.logger import logger
from prowler.providers.azure.lib.regions.regions import get_regions_config
from prowler.providers.common.provider import Provider
class AzureIdentityInfo(BaseModel):
identity_id: str = ""
identity_type: str = ""
tenant_ids: list[str] = []
domain: str = "Unknown tenant domain (missing AAD permissions)"
subscriptions: dict = {}
class AzureRegionConfig(BaseModel):
name: str = ""
authority: str = None
base_url: str = ""
credential_scopes: list = []
class AzureProvider(Provider):
session: DefaultAzureCredential
identity: AzureIdentityInfo
audit_resources: Optional[Any]
audit_metadata: Optional[Any]
audit_config: dict
region_config: AzureRegionConfig
def __init__(self, arguments):
logger.info("Setting Azure provider ...")
subscription_ids = arguments.subscription_ids
logger.info("Checking if any credentials mode is set ...")
az_cli_auth = arguments.az_cli_auth
sp_env_auth = arguments.sp_env_auth
browser_auth = arguments.browser_auth
managed_entity_auth = arguments.managed_identity_auth
tenant_id = arguments.tenant_id
logger.info("Checking if region is different than default one")
region = arguments.azure_region
self.validate_arguments(
az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
)
self.region_config = self.setup_region_config(region)
self.session = self.setup_session(
az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
)
self.identity = self.setup_identity(
az_cli_auth,
sp_env_auth,
browser_auth,
managed_entity_auth,
subscription_ids,
)
if not arguments.only_logs:
self.print_credentials()
def validate_arguments(
self, az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
):
if (
not az_cli_auth
and not sp_env_auth
and not browser_auth
and not managed_entity_auth
):
raise Exception(
"Azure provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth | --managed-identity-auth]"
)
if (not browser_auth and tenant_id) or (browser_auth and not tenant_id):
raise Exception(
"Azure Tenant ID (--tenant-id) is required only for browser authentication mode"
)
def setup_region_config(self, region):
config = get_regions_config(region)
return AzureRegionConfig(
name=region,
authority=config["authority"],
base_url=config["base_url"],
credential_scopes=config["credential_scopes"],
)
def print_credentials(self):
printed_subscriptions = []
for key, value in self.identity.subscriptions.items():
intermediate = key + " : " + value
printed_subscriptions.append(intermediate)
report = f"""
This report is being generated using the identity below:
Azure Tenant IDs: {Fore.YELLOW}[{" ".join(self.identity.tenant_ids)}]{Style.RESET_ALL} Azure Tenant Domain: {Fore.YELLOW}[{self.identity.domain}]{Style.RESET_ALL} Azure Region: {Fore.YELLOW}[{self.region_config.name}]{Style.RESET_ALL}
Azure Subscriptions: {Fore.YELLOW}{printed_subscriptions}{Style.RESET_ALL}
Azure Identity Type: {Fore.YELLOW}[{self.identity.identity_type}]{Style.RESET_ALL} Azure Identity ID: {Fore.YELLOW}[{self.identity.identity_id}]{Style.RESET_ALL}
"""
print(report)
def setup_session(
self, az_cli_auth, sp_env_auth, browser_auth, managed_entity_auth, tenant_id
):
# Browser auth creds cannot be set with DefaultAzureCredentials()
if not browser_auth:
if sp_env_auth:
self.__check_service_principal_creds_env_vars__()
try:
# Since the input vars come as True when it is wanted to be used, we need to inverse it since
# DefaultAzureCredential sets the auth method excluding the others
credentials = DefaultAzureCredential(
exclude_environment_credential=not sp_env_auth,
exclude_cli_credential=not az_cli_auth,
exclude_managed_identity_credential=not managed_entity_auth,
# Azure Auth using Visual Studio is not supported
exclude_visual_studio_code_credential=True,
# Azure Auth using Shared Token Cache is not supported
exclude_shared_token_cache_credential=True,
# Azure Auth using PowerShell is not supported
exclude_powershell_credential=True,
# set Authority of a Microsoft Entra endpoint
authority=self.region_config.authority,
)
except Exception as error:
logger.critical("Failed to retrieve azure credentials")
logger.critical(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
sys.exit(1)
else:
try:
credentials = InteractiveBrowserCredential(tenant_id=tenant_id)
except Exception as error:
logger.critical("Failed to retrieve azure credentials")
logger.critical(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
sys.exit(1)
return credentials
def __check_service_principal_creds_env_vars__(self):
logger.info(
"Azure provider: checking service principal environment variables ..."
)
for env_var in ["AZURE_CLIENT_ID", "AZURE_TENANT_ID", "AZURE_CLIENT_SECRET"]:
if not getenv(env_var):
logger.critical(
f"Azure provider: Missing environment variable {env_var} needed to autenticate against Azure"
)
sys.exit(1)
def setup_identity(
self,
az_cli_auth,
sp_env_auth,
browser_auth,
managed_entity_auth,
subscription_ids,
):
credentials = self.session
identity = AzureIdentityInfo()
# If credentials comes from service principal or browser, if the required permissions are assigned
# the identity can access AAD and retrieve the tenant domain name.
# With cli also should be possible but right now it does not work, azure python package issue is coming
# At the time of writting this with az cli creds is not working, despite that is included
if sp_env_auth or browser_auth or az_cli_auth:
# Trying to recover tenant domain info
try:
logger.info(
"Trying to retrieve tenant domain from AAD to populate identity structure ..."
)
client = GraphClient(credential=credentials)
domain_result = client.get("/domains").json()
if "value" in domain_result:
if "id" in domain_result["value"][0]:
identity.domain = domain_result["value"][0]["id"]
except Exception as error:
logger.error(
"Provided identity does not have permissions to access AAD to retrieve tenant domain"
)
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
# since that exception is not considered as critical, we keep filling another identity fields
if sp_env_auth:
# The id of the sp can be retrieved from environment variables
identity.identity_id = getenv("AZURE_CLIENT_ID")
identity.identity_type = "Service Principal"
# Same here, if user can access AAD, some fields are retrieved if not, default value, for az cli
# should work but it doesn't, pending issue
else:
identity.identity_id = "Unknown user id (Missing AAD permissions)"
identity.identity_type = "User"
try:
logger.info(
"Trying to retrieve user information from AAD to populate identity structure ..."
)
client = GraphClient(credential=credentials)
user_name = client.get("/me").json()
if "userPrincipalName" in user_name:
identity.identity_id = user_name
except Exception as error:
logger.error(
"Provided identity does not have permissions to access AAD to retrieve user's metadata"
)
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
# Managed identities only can be assigned resource, resource group and subscription scope permissions
elif managed_entity_auth:
identity.identity_id = "Default Managed Identity ID"
identity.identity_type = "Managed Identity"
# Pending extracting info from managed identity
# once we have populated the id, type, and domain fields, time to retrieve the subscriptions and finally the tenants
try:
logger.info(
"Trying to subscriptions and tenant ids to populate identity structure ..."
)
subscriptions_client = SubscriptionClient(
credential=credentials,
base_url=self.region_config.base_url,
credential_scopes=self.region_config.credential_scopes,
)
if not subscription_ids:
logger.info("Scanning all the Azure subscriptions...")
for subscription in subscriptions_client.subscriptions.list():
identity.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
)
identity.subscriptions.update({subscription.display_name: id})
# If there are no subscriptions listed -> checks are not going to be run against any resource
if not identity.subscriptions:
logger.critical(
"It was not possible to retrieve any subscriptions, please check your permission assignments"
)
sys.exit(1)
tenants = subscriptions_client.tenants.list()
for tenant in tenants:
identity.tenant_ids.append(tenant.tenant_id)
# This error is critical, since it implies something is wrong with the credentials provided
except Exception as error:
logger.critical(
"Error with credentials provided getting subscriptions and tenants to scan"
)
logger.critical(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
sys.exit(1)
return identity
@@ -1,5 +1,5 @@
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider_new import AzureProvider
from prowler.providers.azure.azure_provider import AzureProvider
class AzureService:
@@ -16,9 +16,7 @@ class AzureService:
)
self.subscriptions = provider.identity.subscriptions
# TODO: review locations
self.locations = provider.locations
self.audit_config = provider.audit_config
def __set_clients__(self, subscriptions, session, service, region_config):
+17
View File
@@ -0,0 +1,17 @@
from pydantic import BaseModel
class AzureIdentityInfo(BaseModel):
identity_id: str = ""
identity_type: str = ""
tenant_ids: list[str] = []
domain: str = "Unknown tenant domain (missing AAD permissions)"
subscriptions: dict = {}
locations: dict = {}
class AzureRegionConfig(BaseModel):
name: str = ""
authority: str = None
base_url: str = ""
credential_scopes: list = []
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.app.app_service import App
from prowler.providers.common.common import get_global_provider
app_client = App(azure_audit_info)
app_client = App(get_global_provider())
@@ -4,14 +4,14 @@ from azure.mgmt.web import WebSiteManagementClient
from azure.mgmt.web.models import ManagedServiceIdentity, SiteConfigResource
from prowler.lib.logger import logger
from prowler.providers.azure.lib.audit_info.models import Azure_Audit_Info
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## App
class App(AzureService):
def __init__(self, audit_info: Azure_Audit_Info):
super().__init__(WebSiteManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(WebSiteManagementClient, provider)
self.apps = self.__get_apps__()
def __get_apps__(self):
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.appinsights.appinsights_service import AppInsights
from prowler.providers.common.common import get_global_provider
appinsights_client = AppInsights(azure_audit_info)
appinsights_client = AppInsights(get_global_provider())
@@ -3,14 +3,14 @@ from dataclasses import dataclass
from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient
from prowler.lib.logger import logger
from prowler.providers.azure.lib.audit_info.models import Azure_Audit_Info
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## AppInsights
class AppInsights(AzureService):
def __init__(self, audit_info: Azure_Audit_Info):
super().__init__(ApplicationInsightsManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(ApplicationInsightsManagementClient, provider)
self.components = self.__get_components__()
def __get_components__(self):
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.cosmosdb.cosmosdb_service import CosmosDB
from prowler.providers.common.common import get_global_provider
cosmosdb_client = CosmosDB(azure_audit_info)
cosmosdb_client = CosmosDB(get_global_provider())
@@ -4,12 +4,13 @@ from azure.mgmt.cosmosdb import CosmosDBManagementClient
from azure.mgmt.cosmosdb.models import PrivateEndpointConnection
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
class CosmosDB(AzureService):
def __init__(self, audit_info):
super().__init__(CosmosDBManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(CosmosDBManagementClient, provider)
self.accounts = self.__get_accounts__()
def __get_accounts__(self):
@@ -5,12 +5,13 @@ from azure.mgmt.security import SecurityCenter
from pydantic import BaseModel
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## Defender
class Defender(AzureService):
def __init__(self, provider):
def __init__(self, provider: AzureProvider):
super().__init__(SecurityCenter, provider)
self.pricings = self.__get_pricings__()
@@ -4,12 +4,13 @@ from azure.mgmt.authorization import AuthorizationManagementClient
from azure.mgmt.authorization.v2022_04_01.models import Permission
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## IAM
class IAM(AzureService):
def __init__(self, provider):
def __init__(self, provider: AzureProvider):
super().__init__(AuthorizationManagementClient, provider)
self.roles, self.custom_roles = self.__get_roles__()
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.keyvault.keyvault_service import KeyVault
from prowler.providers.common.common import get_global_provider
keyvault_client = KeyVault(azure_audit_info)
keyvault_client = KeyVault(get_global_provider())
@@ -10,16 +10,18 @@ from azure.mgmt.keyvault.v2023_07_01.models import (
)
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## Storage
class KeyVault(AzureService):
def __init__(self, audit_info):
super().__init__(KeyVaultManagementClient, audit_info)
self.key_vaults = self.__get_key_vaults__(audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(KeyVaultManagementClient, provider)
# TODO: review this credentials assignment
self.key_vaults = self.__get_key_vaults__(provider)
def __get_key_vaults__(self, audit_info):
def __get_key_vaults__(self, provider):
logger.info("KeyVault - Getting key_vaults...")
key_vaults = {}
for subscription, client in self.clients.items():
@@ -33,7 +35,7 @@ class KeyVault(AzureService):
resource_group, keyvault_name
).properties
keys = self.__get_keys__(
subscription, resource_group, keyvault_name, audit_info
subscription, resource_group, keyvault_name, provider
)
secrets = self.__get_secrets__(
subscription, resource_group, keyvault_name
@@ -55,7 +57,7 @@ class KeyVault(AzureService):
)
return key_vaults
def __get_keys__(self, subscription, resource_group, keyvault_name, audit_info):
def __get_keys__(self, subscription, resource_group, keyvault_name, provider):
logger.info(f"KeyVault - Getting keys for {keyvault_name}...")
keys = []
try:
@@ -79,7 +81,8 @@ class KeyVault(AzureService):
try:
key_client = KeyClient(
vault_url=f"https://{keyvault_name}.vault.azure.net/",
credential=audit_info.credentials,
# TODO: review the following line
credential=provider.session,
)
properties = key_client.list_properties_of_keys()
for prop in properties:
@@ -88,6 +91,7 @@ class KeyVault(AzureService):
if key.name == prop.name:
key.rotation_policy = policy
# TODO: handle different errors here since we are catching all HTTP Errors here
except HttpResponseError:
logger.error(
f"Subscription name: {subscription} -- has no access policy configured for keyvault {keyvault_name}"
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.monitor.monitor_service import Monitor
from prowler.providers.common.common import get_global_provider
monitor_client = Monitor(azure_audit_info)
monitor_client = Monitor(get_global_provider())
@@ -4,13 +4,14 @@ from azure.mgmt.monitor import MonitorManagementClient
from azure.mgmt.monitor.models import LogSettings
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## Monitor
class Monitor(AzureService):
def __init__(self, audit_info):
super().__init__(MonitorManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(MonitorManagementClient, provider)
self.diagnostics_settings = self.__get_diagnostics_settings__()
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.mysql.mysql_service import MySQL
from prowler.providers.common.common import get_global_provider
mysql_client = MySQL(azure_audit_info)
mysql_client = MySQL(get_global_provider())
@@ -3,13 +3,14 @@ from dataclasses import dataclass
from azure.mgmt.rdbms.mysql_flexibleservers import MySQLManagementClient
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## MySQL
class MySQL(AzureService):
def __init__(self, audit_info):
super().__init__(MySQLManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(MySQLManagementClient, provider)
self.flexible_servers = self.__get_flexible_servers__()
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.network.network_service import Network
from prowler.providers.common.common import get_global_provider
network_client = Network(azure_audit_info)
network_client = Network(get_global_provider())
@@ -3,13 +3,14 @@ from dataclasses import dataclass
from azure.mgmt.network import NetworkManagementClient
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## SQLServer
class Network(AzureService):
def __init__(self, audit_info):
super().__init__(NetworkManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(NetworkManagementClient, provider)
self.security_groups = self.__get_security_groups__()
self.bastion_hosts = self.__get_bastion_hosts__()
self.network_watchers = self.__get_network_watchers__()
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.policy.policy_service import Policy
from prowler.providers.common.common import get_global_provider
policy_client = Policy(azure_audit_info)
policy_client = Policy(get_global_provider())
@@ -3,14 +3,14 @@ from dataclasses import dataclass
from azure.mgmt.resource.policy import PolicyClient
from prowler.lib.logger import logger
from prowler.providers.azure.lib.audit_info.models import Azure_Audit_Info
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## Policy
class Policy(AzureService):
def __init__(self, audit_info: Azure_Audit_Info):
super().__init__(PolicyClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(PolicyClient, provider)
self.policy_assigments = self.__get_policy_assigments__()
def __get_policy_assigments__(self):
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.postgresql.postgresql_service import PostgreSQL
from prowler.providers.common.common import get_global_provider
postgresql_client = PostgreSQL(azure_audit_info)
postgresql_client = PostgreSQL(get_global_provider())
@@ -3,12 +3,13 @@ from dataclasses import dataclass
from azure.mgmt.rdbms.postgresql_flexibleservers import PostgreSQLManagementClient
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
class PostgreSQL(AzureService):
def __init__(self, audit_info):
super().__init__(PostgreSQLManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(PostgreSQLManagementClient, provider)
self.flexible_servers = self.__get_flexible_servers__()
def __get_flexible_servers__(self):
@@ -12,12 +12,13 @@ from azure.mgmt.sql.models import (
)
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## SQLServer
class SQLServer(AzureService):
def __init__(self, provider):
def __init__(self, provider: AzureProvider):
super().__init__(SqlManagementClient, provider)
self.sql_servers = self.__get_sql_servers__()
@@ -8,12 +8,13 @@ from azure.mgmt.storage.v2022_09_01.models import (
)
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## Storage
class Storage(AzureService):
def __init__(self, provider):
def __init__(self, provider: AzureProvider):
super().__init__(StorageManagementClient, provider)
self.storage_accounts = self.__get_storage_accounts__()
self.__get_blob_properties__()
@@ -1,4 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.vm.vm_service import VirtualMachines
from prowler.providers.common.common import get_global_provider
vm_client = VirtualMachines(azure_audit_info)
vm_client = VirtualMachines(get_global_provider())
@@ -4,14 +4,14 @@ from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.compute.models import StorageProfile
from prowler.lib.logger import logger
from prowler.providers.azure.lib.audit_info.models import Azure_Audit_Info
from prowler.providers.azure.azure_provider import AzureProvider
from prowler.providers.azure.lib.service.service import AzureService
########################## VirtualMachines
class VirtualMachines(AzureService):
def __init__(self, audit_info: Azure_Audit_Info):
super().__init__(ComputeManagementClient, audit_info)
def __init__(self, provider: AzureProvider):
super().__init__(ComputeManagementClient, provider)
self.virtual_machines = self.__get_virtual_machines__()
self.disks = self.__get_disks__()
+65 -71
View File
@@ -4,13 +4,6 @@ from colorama import Fore, Style
from prowler.config.config import load_and_validate_config_file
from prowler.lib.logger import logger
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.models import (
Azure_Audit_Info,
AzureRegionConfig,
)
from prowler.providers.azure.lib.exception.exception import AzureException
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.models import GCP_Audit_Info
@@ -48,19 +41,19 @@ Kubernetes Cluster: {Fore.YELLOW}[{cluster_name}]{Style.RESET_ALL} User: {Fore.
"""
print(report)
def print_azure_credentials(self, audit_info: Azure_Audit_Info):
printed_subscriptions = []
for key, value in audit_info.identity.subscriptions.items():
intermediate = f"{key} : {value}"
printed_subscriptions.append(intermediate)
report = f"""
This report is being generated using the identity below:
# def print_azure_credentials(self, audit_info: Azure_Audit_Info):
# printed_subscriptions = []
# for key, value in audit_info.identity.subscriptions.items():
# intermediate = f"{key} : {value}"
# printed_subscriptions.append(intermediate)
# report = f"""
# 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 Region: {Fore.YELLOW}[{audit_info.azure_region_config.name}]{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}
"""
print(report)
# 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 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}
# """
# print(report)
# TODO: remove if not needed, but not now :)
# def set_aws_audit_info(self, arguments) -> AWS_Audit_Info:
@@ -303,64 +296,64 @@ Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RE
# f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
# )
# sys.exit(1)
# TODO: remove if not needed, but not now :)
# def set_azure_audit_info(self, arguments) -> Azure_Audit_Info:
# """
# set_azure_audit_info returns the Azure_Audit_Info
# """
# logger.info("Setting Azure session ...")
# subscription_ids = arguments.get("subscription_ids")
def set_azure_audit_info(self, arguments) -> Azure_Audit_Info:
"""
set_azure_audit_info returns the Azure_Audit_Info
"""
logger.info("Setting Azure session ...")
subscription_ids = arguments.get("subscription_ids")
# logger.info("Checking if any credentials mode is set ...")
# az_cli_auth = arguments.get("az_cli_auth")
# sp_env_auth = arguments.get("sp_env_auth")
# browser_auth = arguments.get("browser_auth")
# managed_entity_auth = arguments.get("managed_entity_auth")
# tenant_id = arguments.get("tenant_id")
logger.info("Checking if any credentials mode is set ...")
az_cli_auth = arguments.get("az_cli_auth")
sp_env_auth = arguments.get("sp_env_auth")
browser_auth = arguments.get("browser_auth")
managed_entity_auth = arguments.get("managed_entity_auth")
tenant_id = arguments.get("tenant_id")
# logger.info("Checking if region is different than default one")
# region = arguments.get("azure_region")
logger.info("Checking if region is different than default one")
region = arguments.get("azure_region")
# if (
# not az_cli_auth
# and not sp_env_auth
# and not browser_auth
# and not managed_entity_auth
# ):
# raise AzureException(
# "Azure provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth | --managed-identity-auth]"
# )
# if (not browser_auth and tenant_id) or (browser_auth and not tenant_id):
# raise AzureException(
# "Azure Tenant ID (--tenant-id) is required only for browser authentication mode"
# )
if (
not az_cli_auth
and not sp_env_auth
and not browser_auth
and not managed_entity_auth
):
raise AzureException(
"Azure provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth | --managed-identity-auth]"
)
if (not browser_auth and tenant_id) or (browser_auth and not tenant_id):
raise AzureException(
"Azure Tenant ID (--tenant-id) is required only for browser authentication mode"
)
# azure_provider = Azure_Provider(
# az_cli_auth,
# sp_env_auth,
# browser_auth,
# managed_entity_auth,
# subscription_ids,
# tenant_id,
# region,
# )
# azure_audit_info.credentials = azure_provider.get_credentials()
# azure_audit_info.identity = azure_provider.get_identity()
# region_config = azure_provider.get_region_config()
# azure_audit_info.azure_region_config = AzureRegionConfig(
# name=region,
# authority=region_config["authority"],
# base_url=region_config["base_url"],
# credential_scopes=region_config["credential_scopes"],
# )
# azure_audit_info.locations = azure_provider.get_locations(
# azure_audit_info.credentials, region_config
# )
azure_provider = Azure_Provider(
az_cli_auth,
sp_env_auth,
browser_auth,
managed_entity_auth,
subscription_ids,
tenant_id,
region,
)
azure_audit_info.credentials = azure_provider.get_credentials()
azure_audit_info.identity = azure_provider.get_identity()
region_config = azure_provider.get_region_config()
azure_audit_info.azure_region_config = AzureRegionConfig(
name=region,
authority=region_config["authority"],
base_url=region_config["base_url"],
credential_scopes=region_config["credential_scopes"],
)
azure_audit_info.locations = azure_provider.get_locations(
azure_audit_info.credentials, region_config
)
# if not arguments.get("only_logs"):
# self.print_azure_credentials(get_global_provider())
if not arguments.get("only_logs"):
self.print_azure_credentials(azure_audit_info)
return azure_audit_info
# return azure_audit_info
def set_gcp_audit_info(self, arguments) -> GCP_Audit_Info:
"""
@@ -417,6 +410,7 @@ def set_provider_audit_info(provider: str, arguments: dict):
provider_audit_info = getattr(Audit_Info(), provider_set_audit_info)(arguments)
# Set the audit configuration from the config file
# TODO: move this to the providers
provider_audit_info.audit_config = load_and_validate_config_file(
provider, arguments["config_file"]
)
+12 -12
View File
@@ -4,7 +4,7 @@ from dataclasses import dataclass
from os import makedirs
from os.path import isdir
from prowler.config.config import change_config_var, output_file_timestamp
from prowler.config.config import output_file_timestamp
from prowler.lib.logger import logger
@@ -76,28 +76,28 @@ class Provider_Output_Options:
class Azure_Output_Options(Provider_Output_Options):
def __init__(self, arguments, audit_info, mutelist_file, bulk_checks_metadata):
def __init__(self, arguments, identity, mutelist_file, bulk_checks_metadata):
# First call Provider_Output_Options init
super().__init__(arguments, mutelist_file, bulk_checks_metadata)
# Confire Shodan API
if arguments.shodan:
audit_info = change_config_var(
"shodan_api_key", arguments.shodan, audit_info
)
# TODO: review shodan for the new AWS provider
# if arguments.shodan:
# audit_info = change_config_var(
# "shodan_api_key", arguments.shodan, audit_info
# )
# Check if custom output filename was input, if not, set the default
if (
not hasattr(arguments, "output_filename")
or arguments.output_filename is None
):
if (
audit_info.identity.domain
!= "Unknown tenant domain (missing AAD permissions)"
):
self.output_filename = f"prowler-output-{audit_info.identity.domain}-{output_file_timestamp}"
if identity.domain != "Unknown tenant domain (missing AAD permissions)":
self.output_filename = (
f"prowler-output-{identity.domain}-{output_file_timestamp}"
)
else:
self.output_filename = f"prowler-output-{'-'.join(audit_info.identity.tenant_ids)}-{output_file_timestamp}"
self.output_filename = f"prowler-output-{'-'.join(identity.tenant_ids)}-{output_file_timestamp}"
else:
self.output_filename = arguments.output_filename
+7
View File
@@ -12,3 +12,10 @@ class Provider(ABC):
def validate_arguments(self):
pass
def get_checks_to_execute_by_audit_resources(self):
"""
get_checks_to_execute_by_audit_resources returns a set of checks based on the input resources to scan.
This is a fallback that returns None if the service has not implemented this function.
"""
@@ -6,7 +6,7 @@ from prowler.providers.gcp.lib.service.service import GCPService
################## GKE
class GKE(GCPService):
def __init__(self, audit_info):
def __init__(self, provider):
super().__init__("container", audit_info, api_version="v1beta1")
self.locations = []
self.__get_locations__()