cartography 0.102.0rc2__py3-none-any.whl → 0.103.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cartography might be problematic. Click here for more details.

Files changed (297) hide show
  1. cartography/__main__.py +1 -2
  2. cartography/_version.py +2 -2
  3. cartography/cli.py +376 -249
  4. cartography/client/core/tx.py +39 -18
  5. cartography/config.py +28 -0
  6. cartography/driftdetect/__main__.py +1 -2
  7. cartography/driftdetect/add_shortcut.py +10 -2
  8. cartography/driftdetect/cli.py +71 -75
  9. cartography/driftdetect/detect_deviations.py +7 -3
  10. cartography/driftdetect/get_states.py +20 -8
  11. cartography/driftdetect/model.py +5 -5
  12. cartography/driftdetect/serializers.py +8 -6
  13. cartography/driftdetect/storage.py +2 -2
  14. cartography/graph/cleanupbuilder.py +35 -15
  15. cartography/graph/job.py +46 -17
  16. cartography/graph/querybuilder.py +165 -80
  17. cartography/graph/statement.py +35 -26
  18. cartography/intel/analysis.py +4 -1
  19. cartography/intel/aws/__init__.py +114 -55
  20. cartography/intel/aws/apigateway.py +134 -63
  21. cartography/intel/aws/cloudtrail.py +127 -0
  22. cartography/intel/aws/cloudwatch.py +93 -0
  23. cartography/intel/aws/config.py +56 -20
  24. cartography/intel/aws/dynamodb.py +108 -40
  25. cartography/intel/aws/ec2/__init__.py +2 -2
  26. cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
  27. cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
  28. cartography/intel/aws/ec2/images.py +49 -20
  29. cartography/intel/aws/ec2/instances.py +234 -136
  30. cartography/intel/aws/ec2/internet_gateways.py +40 -11
  31. cartography/intel/aws/ec2/key_pairs.py +44 -20
  32. cartography/intel/aws/ec2/launch_templates.py +101 -59
  33. cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
  34. cartography/intel/aws/ec2/load_balancers.py +82 -42
  35. cartography/intel/aws/ec2/network_acls.py +89 -65
  36. cartography/intel/aws/ec2/network_interfaces.py +146 -87
  37. cartography/intel/aws/ec2/reserved_instances.py +45 -16
  38. cartography/intel/aws/ec2/route_tables.py +138 -98
  39. cartography/intel/aws/ec2/security_groups.py +71 -21
  40. cartography/intel/aws/ec2/snapshots.py +61 -22
  41. cartography/intel/aws/ec2/subnets.py +54 -18
  42. cartography/intel/aws/ec2/tgw.py +100 -34
  43. cartography/intel/aws/ec2/util.py +1 -1
  44. cartography/intel/aws/ec2/volumes.py +69 -41
  45. cartography/intel/aws/ec2/vpc.py +37 -12
  46. cartography/intel/aws/ec2/vpc_peerings.py +83 -24
  47. cartography/intel/aws/ecr.py +88 -32
  48. cartography/intel/aws/ecs.py +83 -47
  49. cartography/intel/aws/efs.py +93 -0
  50. cartography/intel/aws/eks.py +55 -29
  51. cartography/intel/aws/elasticache.py +42 -18
  52. cartography/intel/aws/elasticsearch.py +57 -20
  53. cartography/intel/aws/emr.py +61 -23
  54. cartography/intel/aws/iam.py +401 -145
  55. cartography/intel/aws/iam_instance_profiles.py +22 -22
  56. cartography/intel/aws/identitycenter.py +71 -37
  57. cartography/intel/aws/inspector.py +159 -89
  58. cartography/intel/aws/kms.py +92 -38
  59. cartography/intel/aws/lambda_function.py +103 -34
  60. cartography/intel/aws/organizations.py +30 -10
  61. cartography/intel/aws/permission_relationships.py +133 -51
  62. cartography/intel/aws/rds.py +249 -85
  63. cartography/intel/aws/redshift.py +107 -46
  64. cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
  65. cartography/intel/aws/resources.py +57 -46
  66. cartography/intel/aws/route53.py +108 -61
  67. cartography/intel/aws/s3.py +168 -83
  68. cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
  69. cartography/intel/aws/secretsmanager.py +24 -12
  70. cartography/intel/aws/securityhub.py +20 -9
  71. cartography/intel/aws/sns.py +166 -0
  72. cartography/intel/aws/sqs.py +60 -28
  73. cartography/intel/aws/ssm.py +70 -30
  74. cartography/intel/aws/util/arns.py +7 -7
  75. cartography/intel/aws/util/common.py +31 -4
  76. cartography/intel/azure/__init__.py +78 -19
  77. cartography/intel/azure/compute.py +101 -27
  78. cartography/intel/azure/cosmosdb.py +496 -170
  79. cartography/intel/azure/sql.py +296 -105
  80. cartography/intel/azure/storage.py +322 -113
  81. cartography/intel/azure/subscription.py +39 -23
  82. cartography/intel/azure/tenant.py +13 -4
  83. cartography/intel/azure/util/credentials.py +95 -55
  84. cartography/intel/bigfix/__init__.py +2 -2
  85. cartography/intel/bigfix/computers.py +93 -65
  86. cartography/intel/cloudflare/__init__.py +74 -0
  87. cartography/intel/cloudflare/accounts.py +57 -0
  88. cartography/intel/cloudflare/dnsrecords.py +64 -0
  89. cartography/intel/cloudflare/members.py +75 -0
  90. cartography/intel/cloudflare/roles.py +65 -0
  91. cartography/intel/cloudflare/zones.py +64 -0
  92. cartography/intel/create_indexes.py +3 -2
  93. cartography/intel/crowdstrike/__init__.py +11 -9
  94. cartography/intel/crowdstrike/endpoints.py +5 -1
  95. cartography/intel/crowdstrike/spotlight.py +8 -3
  96. cartography/intel/cve/__init__.py +46 -13
  97. cartography/intel/cve/feed.py +48 -12
  98. cartography/intel/digitalocean/__init__.py +22 -13
  99. cartography/intel/digitalocean/compute.py +75 -108
  100. cartography/intel/digitalocean/management.py +44 -80
  101. cartography/intel/digitalocean/platform.py +48 -43
  102. cartography/intel/dns.py +36 -10
  103. cartography/intel/duo/__init__.py +21 -16
  104. cartography/intel/duo/api_host.py +14 -9
  105. cartography/intel/duo/endpoints.py +50 -45
  106. cartography/intel/duo/groups.py +18 -14
  107. cartography/intel/duo/phones.py +37 -34
  108. cartography/intel/duo/tokens.py +26 -23
  109. cartography/intel/duo/users.py +54 -50
  110. cartography/intel/duo/web_authn_credentials.py +30 -25
  111. cartography/intel/entra/__init__.py +25 -7
  112. cartography/intel/entra/ou.py +112 -0
  113. cartography/intel/entra/users.py +69 -63
  114. cartography/intel/gcp/__init__.py +185 -49
  115. cartography/intel/gcp/compute.py +418 -231
  116. cartography/intel/gcp/crm.py +96 -43
  117. cartography/intel/gcp/dns.py +60 -19
  118. cartography/intel/gcp/gke.py +72 -38
  119. cartography/intel/gcp/iam.py +61 -41
  120. cartography/intel/gcp/storage.py +84 -55
  121. cartography/intel/github/__init__.py +13 -11
  122. cartography/intel/github/repos.py +270 -137
  123. cartography/intel/github/teams.py +170 -88
  124. cartography/intel/github/users.py +70 -39
  125. cartography/intel/github/util.py +36 -34
  126. cartography/intel/gsuite/__init__.py +47 -26
  127. cartography/intel/gsuite/api.py +73 -30
  128. cartography/intel/jamf/__init__.py +19 -1
  129. cartography/intel/jamf/computers.py +30 -7
  130. cartography/intel/jamf/util.py +7 -2
  131. cartography/intel/kandji/__init__.py +6 -3
  132. cartography/intel/kandji/devices.py +14 -8
  133. cartography/intel/kubernetes/namespaces.py +7 -4
  134. cartography/intel/kubernetes/pods.py +7 -4
  135. cartography/intel/kubernetes/services.py +8 -4
  136. cartography/intel/lastpass/__init__.py +2 -2
  137. cartography/intel/lastpass/users.py +23 -12
  138. cartography/intel/oci/__init__.py +44 -11
  139. cartography/intel/oci/iam.py +134 -38
  140. cartography/intel/oci/organizations.py +13 -6
  141. cartography/intel/oci/utils.py +43 -20
  142. cartography/intel/okta/__init__.py +66 -15
  143. cartography/intel/okta/applications.py +42 -20
  144. cartography/intel/okta/awssaml.py +93 -33
  145. cartography/intel/okta/factors.py +16 -4
  146. cartography/intel/okta/groups.py +56 -29
  147. cartography/intel/okta/organization.py +5 -1
  148. cartography/intel/okta/origins.py +6 -2
  149. cartography/intel/okta/roles.py +15 -5
  150. cartography/intel/okta/users.py +20 -8
  151. cartography/intel/okta/utils.py +6 -4
  152. cartography/intel/openai/__init__.py +86 -0
  153. cartography/intel/openai/adminapikeys.py +90 -0
  154. cartography/intel/openai/apikeys.py +96 -0
  155. cartography/intel/openai/projects.py +94 -0
  156. cartography/intel/openai/serviceaccounts.py +82 -0
  157. cartography/intel/openai/users.py +78 -0
  158. cartography/intel/openai/util.py +29 -0
  159. cartography/intel/pagerduty/__init__.py +8 -7
  160. cartography/intel/pagerduty/escalation_policies.py +18 -6
  161. cartography/intel/pagerduty/schedules.py +12 -4
  162. cartography/intel/pagerduty/services.py +11 -4
  163. cartography/intel/pagerduty/teams.py +8 -3
  164. cartography/intel/pagerduty/users.py +3 -1
  165. cartography/intel/pagerduty/vendors.py +3 -1
  166. cartography/intel/semgrep/__init__.py +24 -6
  167. cartography/intel/semgrep/dependencies.py +50 -28
  168. cartography/intel/semgrep/deployment.py +3 -1
  169. cartography/intel/semgrep/findings.py +42 -18
  170. cartography/intel/snipeit/__init__.py +17 -3
  171. cartography/intel/snipeit/asset.py +12 -6
  172. cartography/intel/snipeit/user.py +8 -5
  173. cartography/intel/snipeit/util.py +9 -4
  174. cartography/intel/tailscale/__init__.py +77 -0
  175. cartography/intel/tailscale/acls.py +146 -0
  176. cartography/intel/tailscale/devices.py +127 -0
  177. cartography/intel/tailscale/postureintegrations.py +81 -0
  178. cartography/intel/tailscale/tailnets.py +76 -0
  179. cartography/intel/tailscale/users.py +80 -0
  180. cartography/intel/tailscale/utils.py +132 -0
  181. cartography/models/aws/apigateway.py +21 -17
  182. cartography/models/aws/apigatewaycertificate.py +28 -22
  183. cartography/models/aws/apigatewayresource.py +28 -20
  184. cartography/models/aws/apigatewaystage.py +33 -25
  185. cartography/models/aws/cloudtrail/__init__.py +0 -0
  186. cartography/models/aws/cloudtrail/trail.py +61 -0
  187. cartography/models/aws/cloudwatch/__init__.py +0 -0
  188. cartography/models/aws/cloudwatch/loggroup.py +52 -0
  189. cartography/models/aws/dynamodb/gsi.py +30 -22
  190. cartography/models/aws/dynamodb/tables.py +25 -17
  191. cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
  192. cartography/models/aws/ec2/images.py +36 -34
  193. cartography/models/aws/ec2/instances.py +51 -45
  194. cartography/models/aws/ec2/keypair.py +21 -16
  195. cartography/models/aws/ec2/keypair_instance.py +28 -21
  196. cartography/models/aws/ec2/launch_configurations.py +30 -26
  197. cartography/models/aws/ec2/launch_template_versions.py +48 -38
  198. cartography/models/aws/ec2/launch_templates.py +21 -17
  199. cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
  200. cartography/models/aws/ec2/load_balancers.py +47 -37
  201. cartography/models/aws/ec2/network_acl_rules.py +38 -30
  202. cartography/models/aws/ec2/network_acls.py +38 -29
  203. cartography/models/aws/ec2/networkinterface_instance.py +52 -39
  204. cartography/models/aws/ec2/networkinterfaces.py +53 -37
  205. cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
  206. cartography/models/aws/ec2/reservations.py +18 -14
  207. cartography/models/aws/ec2/route_table_associations.py +44 -34
  208. cartography/models/aws/ec2/route_tables.py +50 -43
  209. cartography/models/aws/ec2/routes.py +45 -37
  210. cartography/models/aws/ec2/securitygroup_instance.py +29 -20
  211. cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
  212. cartography/models/aws/ec2/subnet_instance.py +24 -19
  213. cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
  214. cartography/models/aws/ec2/volumes.py +47 -40
  215. cartography/models/aws/efs/__init__.py +0 -0
  216. cartography/models/aws/efs/mount_target.py +52 -0
  217. cartography/models/aws/eks/clusters.py +23 -21
  218. cartography/models/aws/emr.py +32 -30
  219. cartography/models/aws/iam/instanceprofile.py +33 -24
  220. cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
  221. cartography/models/aws/identitycenter/awspermissionset.py +37 -29
  222. cartography/models/aws/identitycenter/awsssouser.py +23 -21
  223. cartography/models/aws/inspector/findings.py +77 -65
  224. cartography/models/aws/inspector/packages.py +35 -29
  225. cartography/models/aws/s3/__init__.py +0 -0
  226. cartography/models/aws/s3/account_public_access_block.py +51 -0
  227. cartography/models/aws/sns/__init__.py +0 -0
  228. cartography/models/aws/sns/topic.py +50 -0
  229. cartography/models/aws/ssm/instance_information.py +51 -39
  230. cartography/models/aws/ssm/instance_patch.py +32 -26
  231. cartography/models/bigfix/bigfix_computer.py +42 -38
  232. cartography/models/bigfix/bigfix_root.py +3 -3
  233. cartography/models/cloudflare/__init__.py +0 -0
  234. cartography/models/cloudflare/account.py +25 -0
  235. cartography/models/cloudflare/dnsrecord.py +55 -0
  236. cartography/models/cloudflare/member.py +82 -0
  237. cartography/models/cloudflare/role.py +44 -0
  238. cartography/models/cloudflare/zone.py +59 -0
  239. cartography/models/core/common.py +12 -10
  240. cartography/models/core/nodes.py +5 -2
  241. cartography/models/core/relationships.py +14 -6
  242. cartography/models/crowdstrike/hosts.py +37 -35
  243. cartography/models/cve/cve.py +34 -32
  244. cartography/models/cve/cve_feed.py +6 -6
  245. cartography/models/digitalocean/__init__.py +0 -0
  246. cartography/models/digitalocean/account.py +21 -0
  247. cartography/models/digitalocean/droplet.py +56 -0
  248. cartography/models/digitalocean/project.py +48 -0
  249. cartography/models/duo/api_host.py +3 -3
  250. cartography/models/duo/endpoint.py +43 -41
  251. cartography/models/duo/group.py +14 -14
  252. cartography/models/duo/phone.py +27 -27
  253. cartography/models/duo/token.py +16 -16
  254. cartography/models/duo/user.py +46 -44
  255. cartography/models/duo/web_authn_credential.py +27 -19
  256. cartography/models/entra/ou.py +48 -0
  257. cartography/models/entra/tenant.py +24 -18
  258. cartography/models/entra/user.py +64 -48
  259. cartography/models/gcp/iam.py +23 -23
  260. cartography/models/github/orgs.py +5 -4
  261. cartography/models/github/teams.py +37 -31
  262. cartography/models/github/users.py +34 -23
  263. cartography/models/kandji/device.py +22 -16
  264. cartography/models/kandji/tenant.py +6 -4
  265. cartography/models/lastpass/tenant.py +3 -3
  266. cartography/models/lastpass/user.py +32 -28
  267. cartography/models/openai/__init__.py +0 -0
  268. cartography/models/openai/adminapikey.py +90 -0
  269. cartography/models/openai/apikey.py +84 -0
  270. cartography/models/openai/organization.py +17 -0
  271. cartography/models/openai/project.py +70 -0
  272. cartography/models/openai/serviceaccount.py +50 -0
  273. cartography/models/openai/user.py +49 -0
  274. cartography/models/semgrep/dependencies.py +36 -24
  275. cartography/models/semgrep/deployment.py +5 -5
  276. cartography/models/semgrep/findings.py +58 -42
  277. cartography/models/semgrep/locations.py +27 -21
  278. cartography/models/snipeit/asset.py +30 -21
  279. cartography/models/snipeit/tenant.py +6 -4
  280. cartography/models/snipeit/user.py +19 -12
  281. cartography/models/tailscale/__init__.py +0 -0
  282. cartography/models/tailscale/device.py +95 -0
  283. cartography/models/tailscale/group.py +86 -0
  284. cartography/models/tailscale/postureintegration.py +58 -0
  285. cartography/models/tailscale/tag.py +102 -0
  286. cartography/models/tailscale/tailnet.py +29 -0
  287. cartography/models/tailscale/user.py +52 -0
  288. cartography/stats.py +3 -3
  289. cartography/sync.py +113 -31
  290. cartography/util.py +84 -62
  291. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/METADATA +8 -15
  292. cartography-0.103.0.dist-info/RECORD +442 -0
  293. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/WHEEL +1 -1
  294. cartography-0.102.0rc2.dist-info/RECORD +0 -381
  295. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/entry_points.txt +0 -0
  296. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/licenses/LICENSE +0 -0
  297. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,74 @@
1
+ import logging
2
+
3
+ import neo4j
4
+ from cloudflare import Cloudflare
5
+
6
+ import cartography.intel.cloudflare.accounts
7
+ import cartography.intel.cloudflare.dnsrecords
8
+ import cartography.intel.cloudflare.members
9
+ import cartography.intel.cloudflare.roles
10
+ import cartography.intel.cloudflare.zones
11
+ from cartography.config import Config
12
+ from cartography.util import timeit
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @timeit
18
+ def start_cloudflare_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
19
+ """
20
+ If this module is configured, perform ingestion of Cloudflare data. Otherwise warn and exit
21
+ :param neo4j_session: Neo4J session for database interface
22
+ :param config: A cartography.config object
23
+ :return: None
24
+ """
25
+
26
+ if not config.cloudflare_token:
27
+ logger.info(
28
+ "Cloudflare import is not configured - skipping this module. "
29
+ "See docs to configure.",
30
+ )
31
+ return
32
+
33
+ # Create client
34
+ client = Cloudflare(api_token=config.cloudflare_token)
35
+
36
+ common_job_parameters = {
37
+ "UPDATE_TAG": config.update_tag,
38
+ }
39
+
40
+ for account in cartography.intel.cloudflare.accounts.sync(
41
+ neo4j_session,
42
+ client,
43
+ common_job_parameters,
44
+ ):
45
+ account_job_parameters = common_job_parameters.copy()
46
+ account_job_parameters["account_id"] = account["id"]
47
+ cartography.intel.cloudflare.roles.sync(
48
+ neo4j_session,
49
+ client,
50
+ account_job_parameters,
51
+ account_id=account["id"],
52
+ )
53
+
54
+ cartography.intel.cloudflare.members.sync(
55
+ neo4j_session,
56
+ client,
57
+ account_job_parameters,
58
+ account_id=account["id"],
59
+ )
60
+
61
+ for zone in cartography.intel.cloudflare.zones.sync(
62
+ neo4j_session,
63
+ client,
64
+ account_job_parameters,
65
+ account_id=account["id"],
66
+ ):
67
+ zone_job_parameters = account_job_parameters.copy()
68
+ zone_job_parameters["zone_id"] = zone["id"]
69
+ cartography.intel.cloudflare.dnsrecords.sync(
70
+ neo4j_session,
71
+ client,
72
+ zone_job_parameters,
73
+ zone_id=zone["id"],
74
+ )
@@ -0,0 +1,57 @@
1
+ import logging
2
+ from typing import Any
3
+ from typing import Dict
4
+ from typing import List
5
+
6
+ import neo4j
7
+ from cloudflare import Cloudflare
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.cloudflare.account import CloudflareAccountSchema
12
+ from cartography.util import timeit
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @timeit
18
+ def sync(
19
+ neo4j_session: neo4j.Session,
20
+ client: Cloudflare,
21
+ common_job_parameters: Dict[str, Any],
22
+ ) -> List[Dict]:
23
+ accounts = get(client)
24
+ load_accounts(
25
+ neo4j_session,
26
+ accounts,
27
+ common_job_parameters["UPDATE_TAG"],
28
+ )
29
+ cleanup(neo4j_session, common_job_parameters)
30
+ return accounts
31
+
32
+
33
+ @timeit
34
+ def get(client: Cloudflare) -> List[Dict[str, Any]]:
35
+ return [account.to_dict() for account in client.accounts.list()]
36
+
37
+
38
+ def load_accounts(
39
+ neo4j_session: neo4j.Session,
40
+ data: List[Dict[str, Any]],
41
+ update_tag: int,
42
+ ) -> None:
43
+ logger.info("Loading %d Cloudflare accounts into Neo4j.", len(data))
44
+ load(
45
+ neo4j_session,
46
+ CloudflareAccountSchema(),
47
+ data,
48
+ lastupdated=update_tag,
49
+ )
50
+
51
+
52
+ def cleanup(
53
+ neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
54
+ ) -> None:
55
+ GraphJob.from_node_schema(CloudflareAccountSchema(), common_job_parameters).run(
56
+ neo4j_session
57
+ )
@@ -0,0 +1,64 @@
1
+ import logging
2
+ from typing import Any
3
+ from typing import Dict
4
+ from typing import List
5
+
6
+ import neo4j
7
+ from cloudflare import Cloudflare
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.cloudflare.dnsrecord import CloudflareDNSRecordSchema
12
+ from cartography.util import timeit
13
+
14
+ logger = logging.getLogger(__name__)
15
+ # Connect and read timeouts of 60 seconds each; see https://requests.readthedocs.io/en/master/user/advanced/#timeouts
16
+ _TIMEOUT = (60, 60)
17
+
18
+
19
+ @timeit
20
+ def sync(
21
+ neo4j_session: neo4j.Session,
22
+ client: Cloudflare,
23
+ common_job_parameters: Dict[str, Any],
24
+ zone_id: str,
25
+ ) -> None:
26
+ dnsrecords = get(client, zone_id)
27
+ load_dnsrecords(
28
+ neo4j_session,
29
+ dnsrecords,
30
+ zone_id,
31
+ common_job_parameters["UPDATE_TAG"],
32
+ )
33
+ cleanup(neo4j_session, common_job_parameters)
34
+
35
+
36
+ @timeit
37
+ def get(client: Cloudflare, zone_id: str) -> List[Dict[str, Any]]:
38
+ return [
39
+ dnsrecord.to_dict() for dnsrecord in client.dns.records.list(zone_id=zone_id)
40
+ ]
41
+
42
+
43
+ def load_dnsrecords(
44
+ neo4j_session: neo4j.Session,
45
+ data: List[Dict[str, Any]],
46
+ zone_id: str,
47
+ update_tag: int,
48
+ ) -> None:
49
+ logger.info("Loading %d Cloudflare DNSRecords into Neo4j.", len(data))
50
+ load(
51
+ neo4j_session,
52
+ CloudflareDNSRecordSchema(),
53
+ data,
54
+ lastupdated=update_tag,
55
+ zone_id=zone_id,
56
+ )
57
+
58
+
59
+ def cleanup(
60
+ neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
61
+ ) -> None:
62
+ GraphJob.from_node_schema(CloudflareDNSRecordSchema(), common_job_parameters).run(
63
+ neo4j_session
64
+ )
@@ -0,0 +1,75 @@
1
+ import logging
2
+ from typing import Any
3
+ from typing import Dict
4
+ from typing import List
5
+
6
+ import neo4j
7
+ from cloudflare import Cloudflare
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.cloudflare.member import CloudflareMemberSchema
12
+ from cartography.util import timeit
13
+
14
+ logger = logging.getLogger(__name__)
15
+ # Connect and read timeouts of 60 seconds each; see https://requests.readthedocs.io/en/master/user/advanced/#timeouts
16
+ _TIMEOUT = (60, 60)
17
+
18
+
19
+ @timeit
20
+ def sync(
21
+ neo4j_session: neo4j.Session,
22
+ client: Cloudflare,
23
+ common_job_parameters: Dict[str, Any],
24
+ account_id: str,
25
+ ) -> None:
26
+ members = get(client, account_id)
27
+ transformed_members = transform_members(members)
28
+ load_members(
29
+ neo4j_session,
30
+ transformed_members,
31
+ account_id,
32
+ common_job_parameters["UPDATE_TAG"],
33
+ )
34
+ cleanup(neo4j_session, common_job_parameters)
35
+
36
+
37
+ @timeit
38
+ def get(client: Cloudflare, account_id: str) -> List[Dict[str, Any]]:
39
+ return [
40
+ member.to_dict()
41
+ for member in client.accounts.members.list(account_id=account_id)
42
+ ]
43
+
44
+
45
+ def load_members(
46
+ neo4j_session: neo4j.Session,
47
+ data: List[Dict[str, Any]],
48
+ account_id: str,
49
+ update_tag: int,
50
+ ) -> None:
51
+ logger.info("Loading %d Cloudflare members into Neo4j.", len(data))
52
+ load(
53
+ neo4j_session,
54
+ CloudflareMemberSchema(),
55
+ data,
56
+ lastupdated=update_tag,
57
+ account_id=account_id,
58
+ )
59
+
60
+
61
+ def transform_members(data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
62
+ result: List[Dict[str, Any]] = []
63
+ for member in data:
64
+ member["roles_ids"] = [role["id"] for role in member.get("roles", [])]
65
+ member["policies_ids"] = [policy["id"] for policy in member.get("policies", [])]
66
+ result.append(member)
67
+ return result
68
+
69
+
70
+ def cleanup(
71
+ neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
72
+ ) -> None:
73
+ GraphJob.from_node_schema(CloudflareMemberSchema(), common_job_parameters).run(
74
+ neo4j_session
75
+ )
@@ -0,0 +1,65 @@
1
+ import logging
2
+ from typing import Any
3
+ from typing import Dict
4
+ from typing import List
5
+
6
+ import neo4j
7
+ from cloudflare import Cloudflare
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.cloudflare.role import CloudflareRoleSchema
12
+ from cartography.util import timeit
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @timeit
18
+ def sync(
19
+ neo4j_session: neo4j.Session,
20
+ client: Cloudflare,
21
+ common_job_parameters: Dict[str, Any],
22
+ account_id: str,
23
+ ) -> None:
24
+ roles = get(client, account_id)
25
+ load_roles(
26
+ neo4j_session,
27
+ roles,
28
+ account_id,
29
+ common_job_parameters["UPDATE_TAG"],
30
+ )
31
+ cleanup(neo4j_session, common_job_parameters)
32
+
33
+
34
+ @timeit
35
+ def get(
36
+ client: Cloudflare,
37
+ account_id: str,
38
+ ) -> List[Dict[str, Any]]:
39
+ return [
40
+ role.to_dict() for role in client.accounts.roles.list(account_id=account_id)
41
+ ]
42
+
43
+
44
+ def load_roles(
45
+ neo4j_session: neo4j.Session,
46
+ data: List[Dict[str, Any]],
47
+ account_id: str,
48
+ update_tag: int,
49
+ ) -> None:
50
+ logger.info("Loading %d Cloudflare roles into Neo4j.", len(data))
51
+ load(
52
+ neo4j_session,
53
+ CloudflareRoleSchema(),
54
+ data,
55
+ lastupdated=update_tag,
56
+ account_id=account_id,
57
+ )
58
+
59
+
60
+ def cleanup(
61
+ neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
62
+ ) -> None:
63
+ GraphJob.from_node_schema(CloudflareRoleSchema(), common_job_parameters).run(
64
+ neo4j_session
65
+ )
@@ -0,0 +1,64 @@
1
+ import logging
2
+ from typing import Any
3
+ from typing import Dict
4
+ from typing import List
5
+
6
+ import neo4j
7
+ from cloudflare import Cloudflare
8
+
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.cloudflare.zone import CloudflareZoneSchema
12
+ from cartography.util import timeit
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @timeit
18
+ def sync(
19
+ neo4j_session: neo4j.Session,
20
+ client: Cloudflare,
21
+ common_job_parameters: Dict[str, Any],
22
+ account_id: str,
23
+ ) -> List[Dict]:
24
+ zones = get(client, account_id)
25
+ load_zones(
26
+ neo4j_session,
27
+ zones,
28
+ account_id,
29
+ common_job_parameters["UPDATE_TAG"],
30
+ )
31
+ cleanup(neo4j_session, common_job_parameters)
32
+ return zones
33
+
34
+
35
+ @timeit
36
+ def get(
37
+ client: Cloudflare,
38
+ account_id: str,
39
+ ) -> List[Dict[str, Any]]:
40
+ return [zone.to_dict() for zone in client.zones.list(account=account_id)]
41
+
42
+
43
+ def load_zones(
44
+ neo4j_session: neo4j.Session,
45
+ data: List[Dict[str, Any]],
46
+ account_id: str,
47
+ update_tag: int,
48
+ ) -> None:
49
+ logger.info("Loading %d Cloudflare zones into Neo4j.", len(data))
50
+ load(
51
+ neo4j_session,
52
+ CloudflareZoneSchema(),
53
+ data,
54
+ lastupdated=update_tag,
55
+ account_id=account_id,
56
+ )
57
+
58
+
59
+ def cleanup(
60
+ neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
61
+ ) -> None:
62
+ GraphJob.from_node_schema(CloudflareZoneSchema(), common_job_parameters).run(
63
+ neo4j_session
64
+ )
@@ -5,15 +5,16 @@ import neo4j
5
5
 
6
6
  from cartography.config import Config
7
7
  from cartography.util import load_resource_binary
8
+
8
9
  logger = logging.getLogger(__name__)
9
10
 
10
11
 
11
12
  def get_index_statements() -> List[str]:
12
13
  statements = []
13
- with load_resource_binary('cartography.data', 'indexes.cypher') as f:
14
+ with load_resource_binary("cartography.data", "indexes.cypher") as f:
14
15
  for line in f.readlines():
15
16
  statements.append(
16
- line.decode('UTF-8').rstrip('\r\n'),
17
+ line.decode("UTF-8").rstrip("\r\n"),
17
18
  )
18
19
  return statements
19
20
 
@@ -20,7 +20,8 @@ stat_handler = get_stats_client(__name__)
20
20
 
21
21
  @timeit
22
22
  def start_crowdstrike_ingestion(
23
- neo4j_session: neo4j.Session, config: Config,
23
+ neo4j_session: neo4j.Session,
24
+ config: Config,
24
25
  ) -> None:
25
26
  """
26
27
  Perform ingestion of crowdstrike data.
@@ -31,10 +32,7 @@ def start_crowdstrike_ingestion(
31
32
  common_job_parameters = {
32
33
  "UPDATE_TAG": config.update_tag,
33
34
  }
34
- if (
35
- not config.crowdstrike_client_id or
36
- not config.crowdstrike_client_secret
37
- ):
35
+ if not config.crowdstrike_client_id or not config.crowdstrike_client_secret:
38
36
  logger.error("crowdstrike config not found")
39
37
  return
40
38
 
@@ -60,18 +58,22 @@ def start_crowdstrike_ingestion(
60
58
  group_id = config.crowdstrike_api_url
61
59
  merge_module_sync_metadata(
62
60
  neo4j_session,
63
- group_type='crowdstrike',
61
+ group_type="crowdstrike",
64
62
  group_id=group_id,
65
- synced_type='crowdstrike',
63
+ synced_type="crowdstrike",
66
64
  update_tag=config.update_tag,
67
65
  stat_handler=stat_handler,
68
66
  )
69
67
 
70
68
 
71
69
  @timeit
72
- def cleanup(neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]) -> None:
70
+ def cleanup(
71
+ neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]
72
+ ) -> None:
73
73
  logger.info("Running Crowdstrike cleanup")
74
- GraphJob.from_node_schema(CrowdstrikeHostSchema(), common_job_parameters).run(neo4j_session)
74
+ GraphJob.from_node_schema(CrowdstrikeHostSchema(), common_job_parameters).run(
75
+ neo4j_session
76
+ )
75
77
 
76
78
  # Cleanup other crowdstrike assets not handled by the data model
77
79
  run_cleanup_job(
@@ -44,7 +44,11 @@ def load_host_data(
44
44
  )
45
45
 
46
46
 
47
- def get_host_ids(client: Hosts, crowdstrikeapi_filter: str = '', crowdstrikeapi_limit: int = 5000) -> List[List[str]]:
47
+ def get_host_ids(
48
+ client: Hosts,
49
+ crowdstrikeapi_filter: str = "",
50
+ crowdstrikeapi_limit: int = 5000,
51
+ ) -> List[List[str]]:
48
52
  ids = []
49
53
  parameters = {"filter": crowdstrikeapi_filter, "limit": crowdstrikeapi_limit}
50
54
  response = client.QueryDevicesByFilter(parameters=parameters)
@@ -25,7 +25,9 @@ def sync_vulnerabilities(
25
25
 
26
26
 
27
27
  def load_vulnerability_data(
28
- neo4j_session: neo4j.Session, data: List[Dict], update_tag: int,
28
+ neo4j_session: neo4j.Session,
29
+ data: List[Dict],
30
+ update_tag: int,
29
31
  ) -> None:
30
32
  """
31
33
  Transform and load scan information
@@ -111,7 +113,9 @@ def _load_cves(neo4j_session: neo4j.Session, data: List[Dict], update_tag: int)
111
113
  )
112
114
 
113
115
 
114
- def get_spotlight_vulnerability_ids(client: Spotlight_Vulnerabilities) -> List[List[str]]:
116
+ def get_spotlight_vulnerability_ids(
117
+ client: Spotlight_Vulnerabilities,
118
+ ) -> List[List[str]]:
115
119
  ids = []
116
120
  parameters = {"filter": 'status:!"closed"', "limit": 400}
117
121
  response = client.queryVulnerabilities(parameters=parameters)
@@ -135,7 +139,8 @@ def get_spotlight_vulnerability_ids(client: Spotlight_Vulnerabilities) -> List[L
135
139
 
136
140
 
137
141
  def get_spotlight_vulnerabilities(
138
- client: Spotlight_Vulnerabilities, ids: List[str],
142
+ client: Spotlight_Vulnerabilities,
143
+ ids: List[str],
139
144
  ) -> List[Dict]:
140
145
  response = client.getVulnerabilities(ids=",".join(ids))
141
146
  body = response.get("body", {})
@@ -38,21 +38,33 @@ def _sync_year_archives(
38
38
  ) -> None:
39
39
  existing_years = feed.get_cve_sync_metadata(neo4j_session)
40
40
  current_year = datetime.now().year
41
- logger.info(f"Syncing CVE data for year archives. Existing years: {existing_years}. Current year: {current_year}")
41
+ logger.info(
42
+ f"Syncing CVE data for year archives. Existing years: {existing_years}. Current year: {current_year}",
43
+ )
42
44
  for year in range(1999, current_year + 1):
43
45
  if year in existing_years:
44
46
  continue
45
47
  logger.info(f"Syncing CVE data for year {year}")
46
- cves = feed.get_published_cves_per_year(http_session, config.nist_cve_url, str(year), cve_api_key)
48
+ cves = feed.get_published_cves_per_year(
49
+ http_session,
50
+ config.nist_cve_url,
51
+ str(year),
52
+ cve_api_key,
53
+ )
47
54
  feed_metadata = feed.transform_cve_feed(cves)
48
55
  feed.load_cve_feed(neo4j_session, [feed_metadata], config.update_tag)
49
56
  published_cves = feed.transform_cves(cves)
50
- feed.load_cves(neo4j_session, published_cves, feed_metadata['FEED_ID'], config.update_tag)
57
+ feed.load_cves(
58
+ neo4j_session,
59
+ published_cves,
60
+ feed_metadata["FEED_ID"],
61
+ config.update_tag,
62
+ )
51
63
  merge_module_sync_metadata(
52
64
  neo4j_session,
53
- group_type='CVE',
65
+ group_type="CVE",
54
66
  group_id=year,
55
- synced_type='year',
67
+ synced_type="year",
56
68
  update_tag=config.update_tag,
57
69
  stat_handler=stat_handler,
58
70
  )
@@ -66,16 +78,26 @@ def _sync_modified_data(
66
78
  ) -> None:
67
79
  logger.info("Syncing CVE data for modified data")
68
80
  last_modified_date = feed.get_last_modified_cve_date(neo4j_session)
69
- cves = feed.get_modified_cves(http_session, config.nist_cve_url, last_modified_date, cve_api_key)
81
+ cves = feed.get_modified_cves(
82
+ http_session,
83
+ config.nist_cve_url,
84
+ last_modified_date,
85
+ cve_api_key,
86
+ )
70
87
  feed_metadata = feed.transform_cve_feed(cves)
71
88
  feed.load_cve_feed(neo4j_session, [feed_metadata], config.update_tag)
72
89
  modified_cves = feed.transform_cves(cves)
73
- feed.load_cves(neo4j_session, modified_cves, feed_metadata['FEED_ID'], config.update_tag)
90
+ feed.load_cves(
91
+ neo4j_session,
92
+ modified_cves,
93
+ feed_metadata["FEED_ID"],
94
+ config.update_tag,
95
+ )
74
96
  merge_module_sync_metadata(
75
97
  neo4j_session,
76
- group_type='CVE',
77
- group_id=feed_metadata['timestamp'][:4],
78
- synced_type='modified',
98
+ group_type="CVE",
99
+ group_id=feed_metadata["timestamp"][:4],
100
+ synced_type="modified",
79
101
  update_tag=config.update_tag,
80
102
  stat_handler=stat_handler,
81
103
  )
@@ -83,7 +105,8 @@ def _sync_modified_data(
83
105
 
84
106
  @timeit
85
107
  def start_cve_ingestion(
86
- neo4j_session: neo4j.Session, config: Config,
108
+ neo4j_session: neo4j.Session,
109
+ config: Config,
87
110
  ) -> None:
88
111
  """
89
112
  Perform ingestion of CVE data from NIST APIs.
@@ -95,6 +118,16 @@ def start_cve_ingestion(
95
118
  return
96
119
  cve_api_key: str | None = config.cve_api_key if config.cve_api_key else None
97
120
  with _retryable_session() as http_session:
98
- _sync_year_archives(http_session, neo4j_session=neo4j_session, config=config, cve_api_key=cve_api_key)
99
- _sync_modified_data(http_session, neo4j_session=neo4j_session, config=config, cve_api_key=cve_api_key)
121
+ _sync_year_archives(
122
+ http_session,
123
+ neo4j_session=neo4j_session,
124
+ config=config,
125
+ cve_api_key=cve_api_key,
126
+ )
127
+ _sync_modified_data(
128
+ http_session,
129
+ neo4j_session=neo4j_session,
130
+ config=config,
131
+ cve_api_key=cve_api_key,
132
+ )
100
133
  # CVEs are never deleted, so we don't need to run a cleanup job