Skip to content

Commit 943102e

Browse files
authored
Merge pull request #261 from sudiptob2/feat/260/cloud-domains-crawler
Feat/260/cloud domains crawler
2 parents 606bd06 + 0860128 commit 943102e

11 files changed

+137
-8
lines changed

example_config

+3
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,8 @@
9292
},
9393
"datastore_kinds": {
9494
"fetch": true
95+
},
96+
"registered_domains": {
97+
"fetch": true
9598
}
9699
}

src/gcp_scanner/client/client_factory.py

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from gcp_scanner.client.compute_client import ComputeClient
2323
from gcp_scanner.client.datastore_client import DatastoreClient
2424
from gcp_scanner.client.dns_client import DNSClient
25+
from gcp_scanner.client.domains_client import DomainsClient
2526
from gcp_scanner.client.filestore_client import FilestoreClient
2627
from gcp_scanner.client.firestore_client import FirestoreClient
2728
from gcp_scanner.client.iam_client import IAMClient
@@ -47,6 +48,7 @@ class ClientFactory:
4748
"cloudresourcemanager": CloudResourceManagerClient,
4849
"compute": ComputeClient,
4950
"datastore": DatastoreClient,
51+
"domains": DomainsClient,
5052
"dns": DNSClient,
5153
"firestore": FirestoreClient,
5254
"file": FilestoreClient,
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from googleapiclient import discovery
16+
from httplib2 import Credentials
17+
18+
from .interface_client import IClient
19+
20+
21+
class DomainsClient(IClient):
22+
"""Cloud DomainsClient class."""
23+
24+
def get_service(self, credentials: Credentials) -> discovery.Resource:
25+
"""Get discovery service for cloud domains resource.
26+
27+
Args:
28+
credentials: An google.oauth2.credentials.Credentials object.
29+
30+
Returns:
31+
An object of discovery.Resource
32+
"""
33+
return discovery.build(
34+
"domains",
35+
"v1",
36+
credentials=credentials,
37+
cache_discovery=False,
38+
)

src/gcp_scanner/crawler/crawler_factory.py

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from gcp_scanner.crawler.datastore_crawler import DatastoreCrawler
3232
from gcp_scanner.crawler.dns_managed_zones_crawler import DNSManagedZonesCrawler
3333
from gcp_scanner.crawler.dns_policies_crawler import DNSPoliciesCrawler
34+
from gcp_scanner.crawler.domains_crawler import DomainsCrawler
3435
from gcp_scanner.crawler.endpoints_crawler import EndpointsCrawler
3536
from gcp_scanner.crawler.filestore_instances_crawler import FilestoreInstancesCrawler
3637
from gcp_scanner.crawler.firestore_collections_crawler import FirestoreCollectionsCrawler
@@ -66,6 +67,7 @@
6667
"project_info": CloudResourceManagerProjectInfoCrawler,
6768
"project_list": CloudResourceManagerProjectListCrawler,
6869
"pubsub_subs": PubSubSubscriptionsCrawler,
70+
"registered_domains": DomainsCrawler,
6971
"services": ServiceUsageCrawler,
7072
"service_accounts": ServiceAccountsCrawler,
7173
"sourcerepos": CloudSourceRepoCrawler,
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import logging
15+
import sys
16+
from typing import List, Dict, Any, Union
17+
18+
from googleapiclient import discovery
19+
20+
from gcp_scanner.crawler.interface_crawler import ICrawler
21+
22+
23+
class DomainsCrawler(ICrawler):
24+
"""Handle crawling of cloud domains data."""
25+
26+
def crawl(self, project_name: str, service: discovery.Resource,
27+
config: Dict[str, Union[bool, str]] = None) -> List[Dict[str, Any]]:
28+
"""Retrieve a list of cloud domains available in the project.
29+
30+
Args:
31+
project_name: The name of the project to query information about.
32+
service: A resource object for interacting with the GCP API.
33+
config: Configuration options for the crawler (Optional).
34+
35+
Returns:
36+
A list of resource objects representing the crawled data.
37+
"""
38+
logging.info("Retrieving list of registered cloud domains names")
39+
registered_domains_list = list()
40+
parent = f"projects/{project_name}/locations/-"
41+
try:
42+
request = service.projects().locations().registrations().list(parent=parent)
43+
while request is not None:
44+
response = request.execute()
45+
if response.get("registrations", None) is not None:
46+
registered_domains_list.extend([registration['name'] for registration in response.get("registrations")])
47+
request = service.projects().locations().registrations().list_next(
48+
previous_request=request,
49+
previous_response=response,
50+
)
51+
except Exception:
52+
logging.info("Failed to enumerate cloud domains in the %s", project_name)
53+
logging.info(sys.exc_info())
54+
55+
return registered_domains_list

src/gcp_scanner/scanner.py

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
'managed_zones': 'dns',
8383
'project_info': 'cloudresourcemanager',
8484
'pubsub_subs': 'pubsub',
85+
'registered_domains': 'domains',
8586
'services': 'serviceusage',
8687
'service_accounts': 'iam',
8788
'sourcerepos': 'sourcerepo',

src/gcp_scanner/test_acceptance.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from . import scanner
2424

25-
RESOURCE_COUNT = 31
25+
RESOURCE_COUNT = 32
2626
RESULTS_JSON_COUNT = 1
2727
PROJECT_INFO_COUNT = 5
2828
IAM_POLICY_COUNT = 12
@@ -35,7 +35,7 @@
3535
FIREWALL_RULES_COUNT = 4
3636
APP_SERVICES_COUNT = 2
3737
STORAGE_BUCKETS_COUNT = 5
38-
MANAGED_ZONES_COUNT = 1
38+
MANAGED_ZONES_COUNT = 2
3939
GKE_CLUSTERS_COUNT = 0
4040
GKE_IMAGES_COUNT = 4
4141
SQL_INSTANCES_COUNT = 1
@@ -47,7 +47,7 @@
4747
CLOUD_FUNCTIONS = 1
4848
ENDPOINTS_COUNT = 0
4949
KMS_COUNT = 1
50-
SERVICES_COUNT = 39
50+
SERVICES_COUNT = 40
5151
SERVICE_ACCOUNTS_COUNT = 2
5252

5353

src/gcp_scanner/test_unit.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from .client.compute_client import ComputeClient
4343
from .client.datastore_client import DatastoreClient
4444
from .client.dns_client import DNSClient
45+
from .client.domains_client import DomainsClient
4546
from .client.filestore_client import FilestoreClient
4647
from .client.firestore_client import FirestoreClient
4748
from .client.iam_client import IAMClient
@@ -72,6 +73,7 @@
7273
from .crawler.datastore_crawler import DatastoreCrawler
7374
from .crawler.dns_managed_zones_crawler import DNSManagedZonesCrawler
7475
from .crawler.dns_policies_crawler import DNSPoliciesCrawler
76+
from .crawler.domains_crawler import DomainsCrawler
7577
from .crawler.endpoints_crawler import EndpointsCrawler
7678
from .crawler.filestore_instances_crawler import FilestoreInstancesCrawler
7779
from .crawler.firestore_collections_crawler import FirestoreCollectionsCrawler
@@ -820,7 +822,20 @@ def test_datastore_kinds(self):
820822
ClientFactory.get_client("datastore").get_service(self.credentials),
821823
),
822824
"datastore_kinds",
823-
False,
825+
)
826+
)
827+
828+
def test_cloud_domains(self):
829+
"""Test Cloud Domains."""
830+
self.assertTrue(
831+
verify(
832+
CrawlerFactory.create_crawler(
833+
"registered_domains",
834+
).crawl(
835+
PROJECT_NAME,
836+
ClientFactory.get_client("domains").get_service(self.credentials),
837+
),
838+
"registered_domains",
824839
)
825840
)
826841

@@ -923,6 +938,11 @@ def test_get_client_datastore(self):
923938
client = ClientFactory.get_client("datastore")
924939
self.assertIsInstance(client, DatastoreClient)
925940

941+
def test_get_client_domains(self):
942+
"""Test get_client method with 'domains' name."""
943+
client = ClientFactory.get_client("domains")
944+
self.assertIsInstance(client, DomainsClient)
945+
926946
def test_get_client_invalid(self):
927947
"""Test get_client method with invalid name."""
928948
with self.assertLogs(level=logging.ERROR) as log:
@@ -1079,6 +1099,11 @@ def test_create_crawler_datastore_kinds(self):
10791099
crawler = CrawlerFactory.create_crawler("datastore_kinds")
10801100
self.assertIsInstance(crawler, DatastoreCrawler)
10811101

1102+
def test_create_crawler_registered_domains(self):
1103+
"""Test create_crawler method with 'registered_domains' name."""
1104+
crawler = CrawlerFactory.create_crawler("registered_domains")
1105+
self.assertIsInstance(crawler, DomainsCrawler)
1106+
10821107
def test_create_crawler_invalid(self):
10831108
"""Test create_crawler method with invalid name."""
10841109
with self.assertLogs(level=logging.ERROR) as log:

test/datastore_kinds

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"kinds": [
3-
"Person",
4-
"Pet",
5-
"Toy",
3+
CHECK "Person",
4+
CHECK "Pet",
5+
CHECK "Toy",
66
"__Stat_Kind_IsRootEntity__",
77
"__Stat_Kind__",
88
"__Stat_PropertyName_Kind__",

test/registered_domains

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[
2+
CHECK "projects/test-gcp-scanner-2/locations/global/registrations/gcpscanner.com"
3+
]

test/services

+1-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ CHECK services/cloudbuild.googleapis.com",
466466
"parent": "projects/413204024550"
467467
},
468468
{
469-
CHECK services/clouddebugger.googleapis.com",
469+
services/clouddebugger.googleapis.com", //ignore for the time being
470470
"config": {
471471
"name": "clouddebugger.googleapis.com",
472472
"title": "Cloud Debugger API",

0 commit comments

Comments
 (0)