Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/GCP Public access buckets are never flagged #1596 #1597

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ <h4 class="list-group-item-heading">Information</h4>
<div class="list-group-item-text item-margin">Storage Class: <span id="cloudstorage.projects.{{@../key}}.buckets.{{@key}}.storage_class"><samp>{{storage_class}}</samp></span></div>
<div class="list-group-item-text item-margin">Logging: <span id="cloudstorage.projects.{{@../key}}.buckets.{{@key}}.logging_enabled">{{convert_bool_to_enabled logging_enabled}}</span></div>
<div class="list-group-item-text item-margin">Versioning: <span id="cloudstorage.projects.{{@../key}}.buckets.{{@key}}.versioning_enabled">{{convert_bool_to_enabled versioning_enabled}}</span></div>
<div class="list-group-item-text item-margin">Public Access Prevention: <span id="cloudstorage.projects.{{@../key}}.buckets.{{@key}}.public_access_prevention">{{public_access_prevention}}</span></div>
<div class="list-group-item-text item-margin">Public Access Prevention: <span class="cloudstorage.projects.{{@../key}}.buckets.{{@key}}.public_access_prevention"><samp>{{public_access_prevention}}</samp></span></div>
<div class="list-group-item-text item-margin">Effective Public Access Prevention: <span class="cloudstorage.projects.{{@../key}}.buckets.{{@key}}.public_access_prevention">{{convert_bool_to_enabled effective_public_access_prevention}}</span></div>
<div class="list-group-item-text item-margin">Uniform Bucket-Level Access: <span id="cloudstorage.projects.{{@../key}}.buckets.{{@key}}.uniform_bucket_level_access">{{convert_bool_to_enabled uniform_bucket_level_access}}</span></div>
</div>
<div class="list-group-item">
Expand Down
52 changes: 43 additions & 9 deletions ScoutSuite/providers/gcp/facade/cloudstorage.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,76 @@
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)
except Exception as e:
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)
1 change: 1 addition & 0 deletions ScoutSuite/providers/gcp/resources/cloudstorage/buckets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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_",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading