diff --git a/ScoutSuite/output/data/html/partials/gcp/services.cloudstorage.projects.id.buckets.html b/ScoutSuite/output/data/html/partials/gcp/services.cloudstorage.projects.id.buckets.html index 0256d60a7..a12248917 100755 --- a/ScoutSuite/output/data/html/partials/gcp/services.cloudstorage.projects.id.buckets.html +++ b/ScoutSuite/output/data/html/partials/gcp/services.cloudstorage.projects.id.buckets.html @@ -12,7 +12,8 @@

Information

Storage Class: {{storage_class}}
Logging: {{convert_bool_to_enabled logging_enabled}}
Versioning: {{convert_bool_to_enabled versioning_enabled}}
-
Public Access Prevention: {{public_access_prevention}}
+
Public Access Prevention: {{public_access_prevention}}
+
Effective Public Access Prevention: {{convert_bool_to_enabled effective_public_access_prevention}}
Uniform Bucket-Level Access: {{convert_bool_to_enabled uniform_bucket_level_access}}
diff --git a/ScoutSuite/providers/gcp/facade/cloudstorage.py b/ScoutSuite/providers/gcp/facade/cloudstorage.py index 359d632a6..05e97620d 100755 --- a/ScoutSuite/providers/gcp/facade/cloudstorage.py +++ b/ScoutSuite/providers/gcp/facade/cloudstorage.py @@ -1,31 +1,58 @@ from google.cloud import storage +from google.cloud import orgpolicy_v2 from google.api_core.gapic_v1.client_info import ClientInfo -from ScoutSuite.core.console import print_exception +from ScoutSuite.providers.gcp.facade.basefacade import GCPBaseFacade + +from ScoutSuite.core.console import print_exception, print_warning from ScoutSuite.providers.utils import run_concurrently, get_and_set_concurrently from ScoutSuite.utils import get_user_agent -class CloudStorageFacade: +class CloudStorageFacade(GCPBaseFacade): + + def __init__(self): + super().__init__('cloudresourcemanager', 'v1') + + def _get_effective_public_access_prevention(self, project_id): + try: + resourcemanager_client = self._get_client() + request = resourcemanager_client.projects().getEffectiveOrgPolicy(resource=f"projects/{project_id}", + body={ + "constraint": f"constraints/storage.publicAccessPrevention"}) + response = request.execute() + return response.get('booleanPolicy', {}).get('enforced', False) + except Exception as e: + print_warning(f'Failed to retrieve project {project_id} storage.publicAccessPrevention constraint: {e}') + return None - def get_client(self, project_id: str): + def get_storage_client(self, project_id: str): client_info = ClientInfo(user_agent=get_user_agent()) client = storage.Client(project=project_id, client_info=client_info) return client + def get_org_policy_client(self): + client_info = ClientInfo(user_agent=get_user_agent()) + client = orgpolicy_v2.OrgPolicyClient(client_info=client_info) + return client + async def get_buckets(self, project_id: str): try: - client = self.get_client(project_id) + client = self.get_storage_client(project_id) buckets = await run_concurrently(lambda: list(client.list_buckets())) - await get_and_set_concurrently([self._get_and_set_bucket_logging, - self._get_and_set_bucket_iam_policy], buckets) + await get_and_set_concurrently([self._get_and_set_bucket_logging, + self._get_and_set_bucket_iam_policy, + self._get_and_set_public_access_prevention], + buckets, + effective_public_access_prevention=self._get_effective_public_access_prevention( + project_id)) return buckets except Exception as e: print_exception(f'Failed to retrieve storage buckets: {e}') return [] - async def _get_and_set_bucket_logging(self, bucket): + async def _get_and_set_bucket_logging(self, bucket, **kwargs): try: bucket_logging = await run_concurrently(lambda: bucket.get_logging()) setattr(bucket, 'logging', bucket_logging) @@ -33,10 +60,17 @@ async def _get_and_set_bucket_logging(self, bucket): print_exception(f'Failed to retrieve bucket logging: {e}') setattr(bucket, 'logging', None) - async def _get_and_set_bucket_iam_policy(self, bucket): + async def _get_and_set_bucket_iam_policy(self, bucket, **kwargs): try: bucket_iam_policy = await run_concurrently(lambda: bucket.get_iam_policy()) setattr(bucket, 'iam_policy', bucket_iam_policy) except Exception as e: print_exception(f'Failed to retrieve bucket IAM policy: {e}') - setattr(bucket, 'iam_policy', None) + setattr(bucket, 'iam_policy', None) + + async def _get_and_set_public_access_prevention(self, bucket, effective_public_access_prevention): + try: + setattr(bucket, 'effective_public_access_prevention', effective_public_access_prevention) + except Exception as e: + print_exception(f'Failed to set effective public access prevention for bucket {bucket}: {e}') + setattr(bucket, 'effective_public_access_prevention', None) diff --git a/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py b/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py index 8e813e6e2..4f19ba5b6 100755 --- a/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py +++ b/ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py @@ -28,6 +28,7 @@ def _parse_bucket(self, raw_bucket): bucket_dict['logging_enabled'] = raw_bucket.logging is not None bucket_dict['public_access_prevention'] = raw_bucket.iam_configuration.public_access_prevention + bucket_dict['effective_public_access_prevention'] = raw_bucket.effective_public_access_prevention iam_configuration = raw_bucket.iam_configuration.get('uniformBucketLevelAccess') or \ raw_bucket.iam_configuration.get('bucketPolicyOnly') diff --git a/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-member.json b/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-member.json index 30abee45c..e541ce11a 100755 --- a/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-member.json +++ b/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-member.json @@ -37,14 +37,9 @@ ] ], [ - "cloudstorage.projects.id.buckets.id.public_access_prevention", + "cloudstorage.projects.id.buckets.id.effective_public_access_prevention", "notEqual", - "enforced" - ], - [ - "cloudstorage.projects.id.buckets.id.public_access_prevention", - "notEqual", - "inherited" + "True" ] ], "key": "cloudstorage-bucket-_ARG_0_", diff --git a/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-no-public-access-prevention.json b/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-no-public-access-prevention.json index 34a6b16df..ba8e15351 100755 --- a/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-no-public-access-prevention.json +++ b/ScoutSuite/providers/gcp/rules/findings/cloudstorage-bucket-no-public-access-prevention.json @@ -9,15 +9,10 @@ "conditions": [ "and", [ - "cloudstorage.projects.id.buckets.id.public_access_prevention", + "cloudstorage.projects.id.buckets.id.effective_public_access_prevention", "notEqual", - "enforced" - ], - [ - "cloudstorage.projects.id.buckets.id.public_access_prevention", - "notEqual", - "inherited" + "True" ] ], - "id_suffix": "public_access_prevention" + "class_suffix": "public_access_prevention" } diff --git a/requirements.txt b/requirements.txt index d43d62487..200deafd1 100755 --- a/requirements.txt +++ b/requirements.txt @@ -23,6 +23,7 @@ google-cloud-logging>=2.2.0 google-cloud-monitoring==1.1.1 google-cloud-resource-manager>=0.28.3 google-cloud-storage>=1.13.2 +google-cloud-org-policy==1.10.0 google-cloud-kms==1.4.1 ## API Client Libraries google-api-python-client>=2.47.0