refactor(gcp): refactor GCP provider (#4790)

Co-authored-by: Sergio <sergio@prowler.com>
This commit is contained in:
Pedro Martín
2024-08-23 13:37:02 +02:00
committed by GitHub
parent fb449cede8
commit 05da5d1796
3 changed files with 130 additions and 39 deletions
+12 -1
View File
@@ -180,7 +180,18 @@ class Provider(ABC):
)
if not isinstance(Provider._global, provider_class):
global_provider = provider_class(arguments)
if "Gcp" in provider_class_name:
global_provider = provider_class(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
else:
global_provider = provider_class(arguments)
Provider._global = global_provider
except TypeError as error:
+39 -22
View File
@@ -38,13 +38,30 @@ class GcpProvider(Provider):
# TODO: this is not optional, enforce for all providers
audit_metadata: Audit_Metadata
def __init__(self, arguments):
def __init__(
self,
project_ids: list = None,
excluded_project_ids: list = None,
credentials_file: str = None,
impersonate_service_account: str = None,
list_project_ids: bool = False,
config_file: str = None,
fixer_config: str = None,
):
"""
GCP Provider constructor
Args:
project_ids: list
excluded_project_ids: list
credentials_file: str
impersonate_service_account: str
list_project_ids: bool
config_file: str
fixer_config: str
"""
logger.info("Instantiating GCP Provider ...")
input_project_ids = arguments.project_id
excluded_project_ids = arguments.excluded_project_id
credentials_file = arguments.credentials_file
self._impersonated_service_account = arguments.impersonate_service_account
list_project_ids = arguments.list_project_id
self._impersonated_service_account = impersonate_service_account
self._session = self.setup_session(
credentials_file, self._impersonated_service_account
@@ -56,10 +73,11 @@ class GcpProvider(Provider):
accessible_projects = self.get_projects()
if not accessible_projects:
logger.critical("No Project IDs can be accessed via Google Credentials.")
sys.exit(1)
# TODO: add custom exception once we have the GCP exceptions
raise SystemExit
if input_project_ids:
for input_project in input_project_ids:
if project_ids:
for input_project in project_ids:
for accessible_project in accessible_projects:
if self.is_project_matching(input_project, accessible_project):
self._projects[accessible_project] = accessible_projects[
@@ -88,7 +106,8 @@ class GcpProvider(Provider):
logger.critical(
"No Input Project IDs can be accessed via Google Credentials."
)
sys.exit(1)
# TODO: add custom exception once we have the GCP exceptions
raise SystemExit
if list_project_ids:
print(
@@ -105,12 +124,8 @@ class GcpProvider(Provider):
# TODO: move this to the providers, pending for AWS, GCP, AZURE and K8s
# Audit Config
self._audit_config = load_and_validate_config_file(
self._type, arguments.config_file
)
self._fixer_config = load_and_validate_config_file(
self._type, arguments.fixer_config
)
self._audit_config = load_and_validate_config_file(self._type, config_file)
self._fixer_config = load_and_validate_config_file(self._type, fixer_config)
@property
def identity(self):
@@ -241,7 +256,7 @@ class GcpProvider(Provider):
logger.critical(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
sys.exit(1)
raise error
@staticmethod
def test_connection(
@@ -272,9 +287,7 @@ class GcpProvider(Provider):
"Cloud Resource Manager API has not been used before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudresourcemanager.googleapis.com/ then retry."
)
if raise_on_exception:
raise Exception(
"Cloud Resource Manager API has not been used before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudresourcemanager.googleapis.com/ then retry."
)
raise http_error
else:
logger.critical(
f"{http_error.__class__.__name__}[{http_error.__traceback__.tb_lineno}]: {http_error}"
@@ -297,6 +310,10 @@ class GcpProvider(Provider):
f"GCP Account: {Fore.YELLOW}{self.identity.profile}{Style.RESET_ALL}",
f"GCP Project IDs: {Fore.YELLOW}{', '.join(self.project_ids)}{Style.RESET_ALL}",
]
if self.identity.profile:
report_lines.append(
f"Profile: {Fore.YELLOW}{self.identity.profile}{Style.RESET_ALL}"
)
if self.impersonated_service_account:
report_lines.append(
f"Impersonated Service Account: {Fore.YELLOW}{self.impersonated_service_account}{Style.RESET_ALL}"
@@ -357,7 +374,7 @@ class GcpProvider(Provider):
logger.critical(
"Cloud Resource Manager API has not been used before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudresourcemanager.googleapis.com/ then retry."
)
sys.exit(1)
raise http_error
else:
logger.error(
f"{http_error.__class__.__name__}[{http_error.__traceback__.tb_lineno}]: {http_error}"
@@ -366,7 +383,7 @@ class GcpProvider(Provider):
logger.critical(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
sys.exit(1)
raise error
finally:
return projects
+79 -16
View File
@@ -16,14 +16,13 @@ from tests.providers.gcp.gcp_fixtures import mock_api_client
class TestGCPProvider:
def test_gcp_provider(self):
arguments = Namespace()
arguments.project_id = []
arguments.excluded_project_id = []
arguments.list_project_id = False
arguments.credentials_file = ""
arguments.impersonate_service_account = ""
arguments.config_file = default_config_file_path
arguments.fixer_config = default_fixer_config_file_path
project_id = []
excluded_project_id = []
list_project_id = False
credentials_file = ""
impersonate_service_account = ""
config_file = default_config_file_path
fixer_config = default_fixer_config_file_path
projects = {
"test-project": GCPProject(
@@ -54,7 +53,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
project_id,
excluded_project_id,
credentials_file,
impersonate_service_account,
list_project_id,
config_file,
fixer_config,
)
assert gcp_provider.session is None
assert gcp_provider.project_ids == ["test-project"]
assert gcp_provider.projects == projects
@@ -112,7 +119,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
# This is needed since the output_options requires to get the global provider to get the audit config
with patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -194,7 +209,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
input_project = "sys-*"
project_to_match = "sys-12345678"
@@ -258,7 +281,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
assert environ["GOOGLE_APPLICATION_CREDENTIALS"] == "test_credentials_file"
assert gcp_provider.session is not None
assert gcp_provider.identity.profile == "test-service-account-email"
@@ -309,7 +340,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
assert environ["GOOGLE_APPLICATION_CREDENTIALS"] == "test_credentials_file"
assert gcp_provider.session is not None
assert (
@@ -368,7 +407,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
gcp_provider.print_credentials()
captured = capsys.readouterr()
assert "Using the GCP credentials below:" in captured.out
@@ -426,7 +473,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
gcp_provider.print_credentials()
captured = capsys.readouterr()
assert "Using the GCP credentials below:" in captured.out
@@ -492,7 +547,15 @@ class TestGCPProvider:
"prowler.providers.gcp.gcp_provider.discovery.build",
return_value=mocked_service,
):
gcp_provider = GcpProvider(arguments)
gcp_provider = GcpProvider(
arguments.project_id,
arguments.excluded_project_id,
arguments.credentials_file,
arguments.impersonate_service_account,
arguments.list_project_id,
arguments.config_file,
arguments.fixer_config,
)
gcp_provider.print_credentials()
captured = capsys.readouterr()
assert "Using the GCP credentials below:" in captured.out