Skip to content

Commit

Permalink
Google Cloud Config and App Profile Audit Capability (#1676)
Browse files Browse the repository at this point in the history
Missing:

* 2.12.1
* 2.14.7
* 3.1.1 (Asset inventory in my test environment is enabled with or without the API enabled)
* 3.9.11
* 3.10.5
  • Loading branch information
liyun-li authored Nov 19, 2024
1 parent bb0c983 commit 8f93db3
Show file tree
Hide file tree
Showing 72 changed files with 1,368 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,23 @@ <h4 class="list-group-item-heading">Information</h4>
<div class="list-group-item-text item-margin">Public IP Address: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.public_ip"><samp>{{value_or_none public_ip}}</samp></span></div>
<div class="list-group-item-text item-margin">Private IP Address: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.private_ip"><samp>{{value_or_none private_ip}}</samp></span></div>
<div class="list-group-item-text item-margin">Local Infile Flag is Off: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.local_infile_off"><samp>{{value_or_none local_infile_off}}</samp></span></div>
<div class="list-group-item-text item-margin">Skip Show Database is On: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.skip_show_database_on"><samp>{{value_or_none skip_show_database_on}}</samp></span></div>
<div class="list-group-item-text item-margin">Cross db Ownership Chaining Flag is Off: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.cross_db_ownership_chaining_off"><samp>{{value_or_none cross_db_ownership_chaining_off}}</samp></span></div>
<div class="list-group-item-text item-margin">Contained Database Authentication Flag is Off: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.contained_database_authentication_off"><samp>{{value_or_none contained_database_authentication_off}}</samp></span></div>

<div class="list-group-item-text item-margin">Log Checkpoints Flag is On: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_checkpoints_on"><samp>{{value_or_none log_checkpoints_on}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Connections Flag is On: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_connections_on"><samp>{{value_or_none log_connections_on}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Disconnections Flag is On: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_disconnections_on"><samp>{{value_or_none log_disconnections_on}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Lock Waits Flag is On: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_lock_waits_on"><samp>{{value_or_none log_lock_waits_on}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Min Messages Flag set Appropriately: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_min_messages"><samp>{{value_or_none log_min_messages}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Min Messages Flag: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_min_messages"><samp>{{value_or_none log_min_messages}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Min Error Statement Flag: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_min_error_statement"><samp>{{value_or_none log_min_error_statement}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Temp Files Flag set to 0: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_temp_files_0"><samp>{{value_or_none log_temp_files_0}}</samp></span></div>
<div class="list-group-item-text item-margin">Log Min Duration Statement Flag set to -1: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.log_min_duration_statement_-1"><samp>{{value_or_none log_min_duration_statement_-1}}</samp></span></div>
<div class="list-group-item-text item-margin">cloudsql.enable_pgaudit Flag set to On: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.cloudsql_enable_pgaudit"><samp>{{value_or_none cloudsql_enable_pgaudit}}</samp></span></div>
<div class="list-group-item-text item-margin">Remote Access is On: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.remote_access_on"><samp>{{value_or_none remote_access_on}}</samp></span></div>
<div class="list-group-item-text item-margin">User options flag is specified: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.user_options_specified"><samp>{{value_or_none user_options_specified}}</samp></span></div>
<div class="list-group-item-text item-margin">3625 trace flag is disabled: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.3625_off"><samp>{{value_or_none 3625_off}}</samp></span></div>
<div class="list-group-item-text item-margin">External scripts are enabled: <span id="cloudsql.projects.{{@../key}}.instances.{{@key}}.external_scripts_enabled"><samp>{{value_or_none external_scripts_enabled}}</samp></span></div>

{{#if authorized_networks}}
<div class="list-group-item-text item-margin">Authorized Networks:</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- Compute Engine sslpolicies partial -->
<script id="services.computeengine.projects.id.sslpolicies.partial" type="text/x-handlebars-template">
<div id="resource-name" class="list-group-item active">
<h4 class="list-group-item-heading">{{name}}</h4>

</div>
<div class="list-group-item">
<div class="list-group-item-text">Profile: <span id="computeengine.projects.{{@../key}}.sslpolicies.{{@key}}.profile">{{profile}}</span></div>
<div class="list-group-item-text">Minimum TLS Version: <span id="computeengine.projects.{{@../key}}.sslpolicies.{{@key}}.minTlsVersion">{{minTlsVersion}}</span></div>
<div class="list-group-item-text">Fingerprint: <span id="computeengine.projects.{{@../key}}.sslpolicies.{{@key}}.fingerprint">{{fingerprint}}</span></div>
</div>
</script>

<script>
Handlebars.registerPartial("services.computeengine.projects.id.sslpolicies", $("#services\\.computeengine\\.projects\\.id\\.sslpolicies\\.partial").html());
</script>

<!-- Single computeengine sslpolicy template -->
<script id="single_computeengine_sslpolicy-template" type="text/x-handlebars-template">
{{> modal-template template='services.computeengine.projects.id.sslpolicies'}}
</script>
<script>
var single_computeengine_sslpolicy_template = Handlebars.compile($("#single_computeengine_sslpolicy-template").html());
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

<!-- Cloud Resources Manager audit_configs' partial -->
<script id="services.iam.projects.id.audit_configs.partial" type="text/x-handlebars-template">
<div id="resource-name" class="list-group-item active">
<h4 class="list-group-item-heading">{{service}}</h4>
</div>
<div class="list-group-item">
{{#each auditLogConfigs}}
<h5 class="list-group-item-heading">{{logType}}</h5>
<h6>Exempted Members</h6>
<ul id="iam.projects.{{@../../key}}.audit_configs.{{@../key}}.auditLogConfigs.{{@key}}.exemptedMembers">
{{#each exemptedMembers}}
<li><samp>{{this}}</samp></li>
{{else}}
<li><samp>None</samp></li>
{{/each}}
</ul>
{{/each}}
</div>
</script>

<script>
Handlebars.registerPartial("services.iam.projects.id.audit_configs", $("#services\\.iam\\.projects\\.id\\.audit_configs\\.partial").html());
</script>

<!-- Single iam audit_config template -->
<script id="single_iam_audit_config-template" type="text/x-handlebars-template">
{{> modal-template template='services.iam.projects.id.audit_configs'}}
</script>
<script>
var single_iam_audit_config_template = Handlebars.compile($("#single_iam_audit_config-template").html());
</script>
7 changes: 5 additions & 2 deletions ScoutSuite/output/data/inc-scoutsuite/scoutsuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,8 @@ function makeTitle(title) {
console.log('Error: received title ' + title + ' (string expected).')
return title.toString()
}

console.log(title)

const uppercaseTitles = [
'acm', 'aks', 'ec2', 'ecr', 'ecs', 'efs', 'eks', 'gke', 'iam', 'kms', 'rbac',
Expand All @@ -1253,7 +1255,6 @@ function makeTitle(title) {
'stackdriverlogging': 'Stackdriver Logging',
'stackdrivermonitoring': 'Stackdriver Monitoring',
'computeengine': 'Compute Engine',
'kubernetesengine': 'Kubernetes Engine',
'cloudmemorystore': 'Cloud Memorystore',
'aad': 'Azure Active Directory',
'storageaccounts': 'Storage Accounts',
Expand All @@ -1267,11 +1268,13 @@ function makeTitle(title) {
'loadbalancer': 'Load Balancer',
'actiontrail': 'ActionTrail',
'objectstorage': 'Object Storage',
'essentialcontacts': 'Essential Contacts',
'sslpolicies': 'SSL Policies',

// Azure and Kubernetes
'loggingmonitoring': 'Azure Monitor',

// Kubernetes
// Google Cloud and Kubernetes
'kubernetesengine': 'GKE'
}

Expand Down
6 changes: 6 additions & 0 deletions ScoutSuite/providers/gcp/facade/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from ScoutSuite.providers.gcp.facade.basefacade import GCPBaseFacade
from ScoutSuite.providers.gcp.facade.cloudresourcemanager import CloudResourceManagerFacade
from ScoutSuite.providers.gcp.facade.cloudsql import CloudSQLFacade
from ScoutSuite.providers.gcp.facade.essentialcontacts import EssentialContactsFacade
from ScoutSuite.providers.gcp.facade.memorystoreredis import MemoryStoreRedisFacade
from ScoutSuite.providers.gcp.facade.cloudstorage import CloudStorageFacade
from ScoutSuite.providers.gcp.facade.gce import GCEFacade
Expand Down Expand Up @@ -43,6 +44,7 @@ def __init__(self,
self.dns = DNSFacade()
self.stackdriverlogging = StackdriverLoggingFacade()
self.stackdrivermonitoring = StackdriverMonitoringFacade()
self.essentialcontacts = EssentialContactsFacade()

# lock to minimize concurrent calls to get_services()
self.projects_services_lock = False
Expand Down Expand Up @@ -228,6 +230,10 @@ async def is_api_enabled(self, project_id, service):
endpoint = 'redis'
elif service == 'DNS':
endpoint = 'dns'
elif service == 'EssentialContacts':
endpoint = 'essentialcontacts'
elif service == 'AssetInventory':
endpoint = 'cloudasset'
else:
print_warning(f"Could not validate the state of the {format_service_name(service.lower())} API "
f"for project \"{project_id}\" (unknown endpoint), including it in the execution")
Expand Down
12 changes: 10 additions & 2 deletions ScoutSuite/providers/gcp/facade/cloudresourcemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ async def get_member_bindings(self, project_id: str):
except Exception as e:
print_exception(f'Failed to retrieve project IAM policy bindings: {e}')
return []



async def get_audit_configs(self, project_id: str):
try:
cloudresourcemanager_client = self._get_client()
response = await run_concurrently(
lambda: cloudresourcemanager_client.projects().getIamPolicy(resource=project_id).execute()
)
return response.get('auditConfigs', [])
except Exception as e:
print_exception(f'Failed to retrieve project IAM policy audit configs: {e}')
return []
14 changes: 12 additions & 2 deletions ScoutSuite/providers/gcp/facade/dns.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class DNSFacade(GCPBaseFacade):
def __init__(self):
super().__init__('dns', 'v1')
super().__init__("dns", "v1")

async def get_zones(self, project_id):
try:
Expand All @@ -15,5 +15,15 @@ async def get_zones(self, project_id):
lambda: dns_client.managedZones().list(project=project_id).execute()
)
except Exception as e:
print_exception(f'Failed to retrieve zones: {e}')
print_exception(f"Failed to retrieve zones: {e}")
return {}

async def get_policies(self, project_id):
try:
dns_client = self._get_client()
return await run_concurrently(
lambda: dns_client.policies().list(project=project_id).execute()
)
except Exception as e:
print_exception(f"Failed to retrieve DNS policies: {e}")
return {}
18 changes: 18 additions & 0 deletions ScoutSuite/providers/gcp/facade/essentialcontacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from ScoutSuite.core.console import print_exception
from ScoutSuite.providers.gcp.facade.basefacade import GCPBaseFacade
from ScoutSuite.providers.gcp.facade.utils import GCPFacadeUtils

class EssentialContactsFacade(GCPBaseFacade):
def __init__(self):
super().__init__('essentialcontacts', 'v1') # API Client

async def get_contacts(self, project_id: str):
try:
essentialcontacts_client = self._get_client()
contacts = essentialcontacts_client.projects().contacts()
request = contacts.list(parent=f"projects/{project_id}")
results = await GCPFacadeUtils.get_all('contacts', request, contacts)
return results
except Exception as e:
print_exception(f'Failed to list Essential Contacts: {e}')
return []
2 changes: 1 addition & 1 deletion ScoutSuite/providers/gcp/facade/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async def get_functions_v1(self, project_id: str):
return await self._get_functions_version("v1", project_id)

async def get_functions_v2(self, project_id: str):
return await self._get_functions_version("v2alpha", project_id)
return await self._get_functions_version("v2", project_id)

async def _get_functions_version(self, api_version: str, project_id: str):
try:
Expand Down
10 changes: 10 additions & 0 deletions ScoutSuite/providers/gcp/facade/gce.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,13 @@ async def get_global_forwarding_rules(self, project_id):
except Exception as e:
print_exception(f'Failed to retrieve forwarding_rules: {e}')
return []

async def get_sslpolicies(self, project_id):
try:
gce_client = self._get_client()
sslpolicies = gce_client.sslPolicies()
request = sslpolicies.list(project=project_id)
return await GCPFacadeUtils.get_all('items', request, sslpolicies)
except Exception as e:
print_exception(f'Failed to retrieve SSL policies: {e}')
return []
16 changes: 16 additions & 0 deletions ScoutSuite/providers/gcp/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
"bindings_separation_duties": {
"cols": 2,
"path": "services.iam.projects.id.bindings_separation_duties"
},
"audit_configs": {
"cols": 2,
"path": "services.iam.projects.id.audit_configs"
}
}
},
Expand All @@ -35,6 +39,14 @@
"path": "services.kms.projects.id.keyrings"
}
}
},
"essentialcontacts": {
"resources": {
"contacts": {
"cols": 2,
"path": "services.iam.essentialcontacts.id.contacts"
}
}
}
},
"compute": {
Expand Down Expand Up @@ -67,6 +79,10 @@
"global_forwarding_rules": {
"cols": 2,
"path": "services.computeengine.projects.id.global_forwarding_rules"
},
"sslpolicies": {
"cols": 2,
"path": "services.computeengine.projects.id.sslpolicies"
}
}
},
Expand Down
Loading

0 comments on commit 8f93db3

Please sign in to comment.