cartography 0.102.0rc1__py3-none-any.whl → 0.103.0rc1__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 (251) hide show
  1. cartography/__main__.py +1 -2
  2. cartography/_version.py +2 -2
  3. cartography/cli.py +302 -253
  4. cartography/client/core/tx.py +39 -18
  5. cartography/config.py +4 -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/config.py +56 -20
  23. cartography/intel/aws/dynamodb.py +108 -40
  24. cartography/intel/aws/ec2/__init__.py +2 -2
  25. cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
  26. cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
  27. cartography/intel/aws/ec2/images.py +49 -20
  28. cartography/intel/aws/ec2/instances.py +234 -136
  29. cartography/intel/aws/ec2/internet_gateways.py +40 -11
  30. cartography/intel/aws/ec2/key_pairs.py +44 -20
  31. cartography/intel/aws/ec2/launch_templates.py +101 -59
  32. cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
  33. cartography/intel/aws/ec2/load_balancers.py +82 -42
  34. cartography/intel/aws/ec2/network_acls.py +89 -65
  35. cartography/intel/aws/ec2/network_interfaces.py +146 -87
  36. cartography/intel/aws/ec2/reserved_instances.py +45 -16
  37. cartography/intel/aws/ec2/route_tables.py +327 -0
  38. cartography/intel/aws/ec2/security_groups.py +71 -21
  39. cartography/intel/aws/ec2/snapshots.py +61 -22
  40. cartography/intel/aws/ec2/subnets.py +54 -18
  41. cartography/intel/aws/ec2/tgw.py +100 -34
  42. cartography/intel/aws/ec2/util.py +1 -1
  43. cartography/intel/aws/ec2/volumes.py +69 -41
  44. cartography/intel/aws/ec2/vpc.py +37 -12
  45. cartography/intel/aws/ec2/vpc_peerings.py +83 -24
  46. cartography/intel/aws/ecr.py +88 -32
  47. cartography/intel/aws/ecs.py +83 -47
  48. cartography/intel/aws/eks.py +55 -29
  49. cartography/intel/aws/elasticache.py +42 -18
  50. cartography/intel/aws/elasticsearch.py +57 -20
  51. cartography/intel/aws/emr.py +61 -23
  52. cartography/intel/aws/iam.py +401 -145
  53. cartography/intel/aws/iam_instance_profiles.py +22 -22
  54. cartography/intel/aws/identitycenter.py +71 -37
  55. cartography/intel/aws/inspector.py +159 -89
  56. cartography/intel/aws/kms.py +92 -38
  57. cartography/intel/aws/lambda_function.py +103 -34
  58. cartography/intel/aws/organizations.py +30 -10
  59. cartography/intel/aws/permission_relationships.py +133 -51
  60. cartography/intel/aws/rds.py +249 -85
  61. cartography/intel/aws/redshift.py +107 -46
  62. cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
  63. cartography/intel/aws/resources.py +53 -44
  64. cartography/intel/aws/route53.py +108 -61
  65. cartography/intel/aws/s3.py +168 -83
  66. cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
  67. cartography/intel/aws/secretsmanager.py +24 -12
  68. cartography/intel/aws/securityhub.py +20 -9
  69. cartography/intel/aws/sns.py +166 -0
  70. cartography/intel/aws/sqs.py +60 -28
  71. cartography/intel/aws/ssm.py +70 -30
  72. cartography/intel/aws/util/arns.py +7 -7
  73. cartography/intel/aws/util/common.py +31 -4
  74. cartography/intel/azure/__init__.py +78 -19
  75. cartography/intel/azure/compute.py +101 -27
  76. cartography/intel/azure/cosmosdb.py +496 -170
  77. cartography/intel/azure/sql.py +296 -105
  78. cartography/intel/azure/storage.py +322 -113
  79. cartography/intel/azure/subscription.py +39 -23
  80. cartography/intel/azure/tenant.py +13 -4
  81. cartography/intel/azure/util/credentials.py +95 -55
  82. cartography/intel/bigfix/__init__.py +2 -2
  83. cartography/intel/bigfix/computers.py +93 -65
  84. cartography/intel/create_indexes.py +3 -2
  85. cartography/intel/crowdstrike/__init__.py +11 -9
  86. cartography/intel/crowdstrike/endpoints.py +5 -1
  87. cartography/intel/crowdstrike/spotlight.py +8 -3
  88. cartography/intel/cve/__init__.py +46 -13
  89. cartography/intel/cve/feed.py +48 -12
  90. cartography/intel/digitalocean/__init__.py +22 -13
  91. cartography/intel/digitalocean/compute.py +75 -108
  92. cartography/intel/digitalocean/management.py +44 -80
  93. cartography/intel/digitalocean/platform.py +48 -43
  94. cartography/intel/dns.py +36 -10
  95. cartography/intel/duo/__init__.py +21 -16
  96. cartography/intel/duo/api_host.py +14 -9
  97. cartography/intel/duo/endpoints.py +50 -45
  98. cartography/intel/duo/groups.py +18 -14
  99. cartography/intel/duo/phones.py +37 -34
  100. cartography/intel/duo/tokens.py +26 -23
  101. cartography/intel/duo/users.py +54 -50
  102. cartography/intel/duo/web_authn_credentials.py +30 -25
  103. cartography/intel/entra/__init__.py +25 -7
  104. cartography/intel/entra/ou.py +112 -0
  105. cartography/intel/entra/users.py +69 -63
  106. cartography/intel/gcp/__init__.py +185 -49
  107. cartography/intel/gcp/compute.py +418 -231
  108. cartography/intel/gcp/crm.py +96 -43
  109. cartography/intel/gcp/dns.py +60 -19
  110. cartography/intel/gcp/gke.py +72 -38
  111. cartography/intel/gcp/iam.py +61 -41
  112. cartography/intel/gcp/storage.py +84 -55
  113. cartography/intel/github/__init__.py +13 -11
  114. cartography/intel/github/repos.py +270 -137
  115. cartography/intel/github/teams.py +170 -88
  116. cartography/intel/github/users.py +70 -39
  117. cartography/intel/github/util.py +36 -34
  118. cartography/intel/gsuite/__init__.py +47 -26
  119. cartography/intel/gsuite/api.py +73 -30
  120. cartography/intel/jamf/__init__.py +19 -1
  121. cartography/intel/jamf/computers.py +30 -7
  122. cartography/intel/jamf/util.py +7 -2
  123. cartography/intel/kandji/__init__.py +6 -3
  124. cartography/intel/kandji/devices.py +14 -8
  125. cartography/intel/kubernetes/namespaces.py +7 -4
  126. cartography/intel/kubernetes/pods.py +7 -4
  127. cartography/intel/kubernetes/services.py +8 -4
  128. cartography/intel/lastpass/__init__.py +2 -2
  129. cartography/intel/lastpass/users.py +23 -12
  130. cartography/intel/oci/__init__.py +44 -11
  131. cartography/intel/oci/iam.py +134 -38
  132. cartography/intel/oci/organizations.py +13 -6
  133. cartography/intel/oci/utils.py +43 -20
  134. cartography/intel/okta/__init__.py +66 -15
  135. cartography/intel/okta/applications.py +42 -20
  136. cartography/intel/okta/awssaml.py +93 -33
  137. cartography/intel/okta/factors.py +16 -4
  138. cartography/intel/okta/groups.py +56 -29
  139. cartography/intel/okta/organization.py +5 -1
  140. cartography/intel/okta/origins.py +6 -2
  141. cartography/intel/okta/roles.py +15 -5
  142. cartography/intel/okta/users.py +20 -8
  143. cartography/intel/okta/utils.py +6 -4
  144. cartography/intel/pagerduty/__init__.py +8 -7
  145. cartography/intel/pagerduty/escalation_policies.py +18 -6
  146. cartography/intel/pagerduty/schedules.py +12 -4
  147. cartography/intel/pagerduty/services.py +11 -4
  148. cartography/intel/pagerduty/teams.py +8 -3
  149. cartography/intel/pagerduty/users.py +3 -1
  150. cartography/intel/pagerduty/vendors.py +3 -1
  151. cartography/intel/semgrep/__init__.py +24 -6
  152. cartography/intel/semgrep/dependencies.py +50 -28
  153. cartography/intel/semgrep/deployment.py +3 -1
  154. cartography/intel/semgrep/findings.py +42 -18
  155. cartography/intel/snipeit/__init__.py +17 -3
  156. cartography/intel/snipeit/asset.py +12 -6
  157. cartography/intel/snipeit/user.py +8 -5
  158. cartography/intel/snipeit/util.py +9 -4
  159. cartography/models/aws/apigateway.py +21 -17
  160. cartography/models/aws/apigatewaycertificate.py +28 -22
  161. cartography/models/aws/apigatewayresource.py +28 -20
  162. cartography/models/aws/apigatewaystage.py +33 -25
  163. cartography/models/aws/cloudtrail/__init__.py +0 -0
  164. cartography/models/aws/cloudtrail/trail.py +61 -0
  165. cartography/models/aws/dynamodb/gsi.py +30 -22
  166. cartography/models/aws/dynamodb/tables.py +25 -17
  167. cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
  168. cartography/models/aws/ec2/images.py +36 -34
  169. cartography/models/aws/ec2/instances.py +51 -45
  170. cartography/models/aws/ec2/keypair.py +21 -16
  171. cartography/models/aws/ec2/keypair_instance.py +28 -21
  172. cartography/models/aws/ec2/launch_configurations.py +30 -26
  173. cartography/models/aws/ec2/launch_template_versions.py +48 -38
  174. cartography/models/aws/ec2/launch_templates.py +21 -17
  175. cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
  176. cartography/models/aws/ec2/load_balancers.py +47 -37
  177. cartography/models/aws/ec2/network_acl_rules.py +38 -30
  178. cartography/models/aws/ec2/network_acls.py +38 -29
  179. cartography/models/aws/ec2/networkinterface_instance.py +52 -39
  180. cartography/models/aws/ec2/networkinterfaces.py +53 -37
  181. cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
  182. cartography/models/aws/ec2/reservations.py +18 -14
  183. cartography/models/aws/ec2/route_table_associations.py +97 -0
  184. cartography/models/aws/ec2/route_tables.py +128 -0
  185. cartography/models/aws/ec2/routes.py +85 -0
  186. cartography/models/aws/ec2/securitygroup_instance.py +29 -20
  187. cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
  188. cartography/models/aws/ec2/subnet_instance.py +24 -19
  189. cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
  190. cartography/models/aws/ec2/volumes.py +47 -40
  191. cartography/models/aws/eks/clusters.py +23 -21
  192. cartography/models/aws/emr.py +32 -30
  193. cartography/models/aws/iam/instanceprofile.py +33 -24
  194. cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
  195. cartography/models/aws/identitycenter/awspermissionset.py +37 -29
  196. cartography/models/aws/identitycenter/awsssouser.py +23 -21
  197. cartography/models/aws/inspector/findings.py +77 -65
  198. cartography/models/aws/inspector/packages.py +35 -29
  199. cartography/models/aws/s3/__init__.py +0 -0
  200. cartography/models/aws/s3/account_public_access_block.py +51 -0
  201. cartography/models/aws/sns/__init__.py +0 -0
  202. cartography/models/aws/sns/topic.py +50 -0
  203. cartography/models/aws/ssm/instance_information.py +51 -39
  204. cartography/models/aws/ssm/instance_patch.py +32 -26
  205. cartography/models/bigfix/bigfix_computer.py +42 -38
  206. cartography/models/bigfix/bigfix_root.py +3 -3
  207. cartography/models/core/common.py +12 -10
  208. cartography/models/core/nodes.py +5 -2
  209. cartography/models/core/relationships.py +14 -6
  210. cartography/models/crowdstrike/hosts.py +37 -35
  211. cartography/models/cve/cve.py +34 -32
  212. cartography/models/cve/cve_feed.py +6 -6
  213. cartography/models/digitalocean/__init__.py +0 -0
  214. cartography/models/digitalocean/account.py +21 -0
  215. cartography/models/digitalocean/droplet.py +56 -0
  216. cartography/models/digitalocean/project.py +48 -0
  217. cartography/models/duo/api_host.py +3 -3
  218. cartography/models/duo/endpoint.py +43 -41
  219. cartography/models/duo/group.py +14 -14
  220. cartography/models/duo/phone.py +27 -27
  221. cartography/models/duo/token.py +16 -16
  222. cartography/models/duo/user.py +46 -44
  223. cartography/models/duo/web_authn_credential.py +27 -19
  224. cartography/models/entra/ou.py +48 -0
  225. cartography/models/entra/tenant.py +24 -18
  226. cartography/models/entra/user.py +64 -48
  227. cartography/models/gcp/iam.py +23 -23
  228. cartography/models/github/orgs.py +5 -4
  229. cartography/models/github/teams.py +37 -31
  230. cartography/models/github/users.py +34 -23
  231. cartography/models/kandji/device.py +22 -16
  232. cartography/models/kandji/tenant.py +6 -4
  233. cartography/models/lastpass/tenant.py +3 -3
  234. cartography/models/lastpass/user.py +32 -28
  235. cartography/models/semgrep/dependencies.py +36 -24
  236. cartography/models/semgrep/deployment.py +5 -5
  237. cartography/models/semgrep/findings.py +58 -42
  238. cartography/models/semgrep/locations.py +27 -21
  239. cartography/models/snipeit/asset.py +30 -21
  240. cartography/models/snipeit/tenant.py +6 -4
  241. cartography/models/snipeit/user.py +19 -12
  242. cartography/stats.py +3 -3
  243. cartography/sync.py +107 -31
  244. cartography/util.py +84 -62
  245. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/METADATA +3 -14
  246. cartography-0.103.0rc1.dist-info/RECORD +396 -0
  247. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
  248. cartography-0.102.0rc1.dist-info/RECORD +0 -377
  249. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
  250. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
  251. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
@@ -23,18 +23,23 @@ logger = logging.getLogger(__name__)
23
23
  @timeit
24
24
  @aws_handle_regions
25
25
  def get_kms_key_list(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
26
- client = boto3_session.client('kms', region_name=region)
27
- paginator = client.get_paginator('list_keys')
26
+ client = boto3_session.client("kms", region_name=region)
27
+ paginator = client.get_paginator("list_keys")
28
28
  key_list: List[Any] = []
29
29
  for page in paginator.paginate():
30
- key_list.extend(page['Keys'])
30
+ key_list.extend(page["Keys"])
31
31
 
32
32
  described_key_list = []
33
33
  for key in key_list:
34
34
  try:
35
- response = client.describe_key(KeyId=key["KeyId"])['KeyMetadata']
35
+ response = client.describe_key(KeyId=key["KeyId"])["KeyMetadata"]
36
36
  except ClientError as e:
37
- logger.warning("Failed to describe key with key id - {}. Error - {}".format(key["KeyId"], e))
37
+ logger.warning(
38
+ "Failed to describe key with key id - {}. Error - {}".format(
39
+ key["KeyId"],
40
+ e,
41
+ ),
42
+ )
38
43
  continue
39
44
 
40
45
  described_key_list.append(response)
@@ -45,17 +50,19 @@ def get_kms_key_list(boto3_session: boto3.session.Session, region: str) -> List[
45
50
  @timeit
46
51
  @aws_handle_regions
47
52
  def get_kms_key_details(
48
- boto3_session: boto3.session.Session, kms_key_data: Dict, region: str,
53
+ boto3_session: boto3.session.Session,
54
+ kms_key_data: Dict,
55
+ region: str,
49
56
  ) -> Generator[Any, Any, Any]:
50
57
  """
51
58
  Iterates over all KMS Keys.
52
59
  """
53
- client = boto3_session.client('kms', region_name=region)
60
+ client = boto3_session.client("kms", region_name=region)
54
61
  for key in kms_key_data:
55
62
  policy = get_policy(key, client)
56
63
  aliases = get_aliases(key, client)
57
64
  grants = get_grants(key, client)
58
- yield key['KeyId'], policy, aliases, grants
65
+ yield key["KeyId"], policy, aliases, grants
59
66
 
60
67
 
61
68
  @timeit
@@ -64,10 +71,10 @@ def get_policy(key: Dict, client: botocore.client.BaseClient) -> Any:
64
71
  Gets the KMS Key policy. Returns policy string or None if we are unable to retrieve it.
65
72
  """
66
73
  try:
67
- policy = client.get_key_policy(KeyId=key["KeyId"], PolicyName='default')
74
+ policy = client.get_key_policy(KeyId=key["KeyId"], PolicyName="default")
68
75
  except ClientError as e:
69
76
  policy = None
70
- if e.response['Error']['Code'] == 'AccessDeniedException':
77
+ if e.response["Error"]["Code"] == "AccessDeniedException":
71
78
  logger.warning(
72
79
  f"kms:get_key_policy on key id {key['KeyId']} failed with AccessDeniedException; continuing sync.",
73
80
  exc_info=True,
@@ -84,9 +91,9 @@ def get_aliases(key: Dict, client: botocore.client.BaseClient) -> List[Any]:
84
91
  Gets the KMS Key Aliases.
85
92
  """
86
93
  aliases: List[Any] = []
87
- paginator = client.get_paginator('list_aliases')
88
- for page in paginator.paginate(KeyId=key['KeyId']):
89
- aliases.extend(page['Aliases'])
94
+ paginator = client.get_paginator("list_aliases")
95
+ for page in paginator.paginate(KeyId=key["KeyId"]):
96
+ aliases.extend(page["Aliases"])
90
97
 
91
98
  return aliases
92
99
 
@@ -97,12 +104,12 @@ def get_grants(key: Dict, client: botocore.client.BaseClient) -> List[Any]:
97
104
  Gets the KMS Key Grants.
98
105
  """
99
106
  grants: List[Any] = []
100
- paginator = client.get_paginator('list_grants')
107
+ paginator = client.get_paginator("list_grants")
101
108
  try:
102
- for page in paginator.paginate(KeyId=key['KeyId']):
103
- grants.extend(page['Grants'])
109
+ for page in paginator.paginate(KeyId=key["KeyId"]):
110
+ grants.extend(page["Grants"])
104
111
  except ClientError as e:
105
- if e.response['Error']['Code'] == 'AccessDeniedException':
112
+ if e.response["Error"]["Code"] == "AccessDeniedException":
106
113
  logger.warning(
107
114
  f'kms:list_grants on key_id {key["KeyId"]} failed with AccessDeniedException; continuing sync.',
108
115
  exc_info=True,
@@ -113,7 +120,11 @@ def get_grants(key: Dict, client: botocore.client.BaseClient) -> List[Any]:
113
120
 
114
121
 
115
122
  @timeit
116
- def _load_kms_key_aliases(neo4j_session: neo4j.Session, aliases: List[Dict], update_tag: int) -> None:
123
+ def _load_kms_key_aliases(
124
+ neo4j_session: neo4j.Session,
125
+ aliases: List[Dict],
126
+ update_tag: int,
127
+ ) -> None:
117
128
  """
118
129
  Ingest KMS Aliases into neo4j.
119
130
  """
@@ -137,7 +148,11 @@ def _load_kms_key_aliases(neo4j_session: neo4j.Session, aliases: List[Dict], upd
137
148
 
138
149
 
139
150
  @timeit
140
- def _load_kms_key_grants(neo4j_session: neo4j.Session, grants_list: List[Dict], update_tag: int) -> None:
151
+ def _load_kms_key_grants(
152
+ neo4j_session: neo4j.Session,
153
+ grants_list: List[Dict],
154
+ update_tag: int,
155
+ ) -> None:
141
156
  """
142
157
  Ingest KMS Key Grants into neo4j.
143
158
  """
@@ -157,7 +172,7 @@ def _load_kms_key_grants(neo4j_session: neo4j.Session, grants_list: List[Dict],
157
172
  # neo4j does not accept datetime objects and values. This loop is used to convert
158
173
  # these values to string.
159
174
  for grant in grants_list:
160
- grant['CreationDate'] = str(grant['CreationDate'])
175
+ grant["CreationDate"] = str(grant["CreationDate"])
161
176
 
162
177
  neo4j_session.run(
163
178
  ingest_grants,
@@ -167,7 +182,11 @@ def _load_kms_key_grants(neo4j_session: neo4j.Session, grants_list: List[Dict],
167
182
 
168
183
 
169
184
  @timeit
170
- def _load_kms_key_policies(neo4j_session: neo4j.Session, policies: List[Dict], update_tag: int) -> None:
185
+ def _load_kms_key_policies(
186
+ neo4j_session: neo4j.Session,
187
+ policies: List[Dict],
188
+ update_tag: int,
189
+ ) -> None:
171
190
  """
172
191
  Ingest KMS Key policy results into neo4j.
173
192
  """
@@ -201,8 +220,11 @@ def _set_default_values(neo4j_session: neo4j.Session, aws_account_id: str) -> No
201
220
 
202
221
  @timeit
203
222
  def load_kms_key_details(
204
- neo4j_session: neo4j.Session, policy_alias_grants_data: List[Tuple[Any, Any, Any, Any]], region: str,
205
- aws_account_id: str, update_tag: int,
223
+ neo4j_session: neo4j.Session,
224
+ policy_alias_grants_data: List[Tuple[Any, Any, Any, Any]],
225
+ region: str,
226
+ aws_account_id: str,
227
+ update_tag: int,
206
228
  ) -> None:
207
229
  """
208
230
  Create dictionaries for all KMS key policies, aliases and grants so we can import them in a single query for each
@@ -221,9 +243,9 @@ def load_kms_key_details(
221
243
 
222
244
  # cleanup existing policy properties
223
245
  run_cleanup_job(
224
- 'aws_kms_details.json',
246
+ "aws_kms_details.json",
225
247
  neo4j_session,
226
- {'UPDATE_TAG': update_tag, 'AWS_ID': aws_account_id},
248
+ {"UPDATE_TAG": update_tag, "AWS_ID": aws_account_id},
227
249
  )
228
250
 
229
251
  _load_kms_key_policies(neo4j_session, policies, update_tag)
@@ -281,7 +303,7 @@ def parse_policy(key: str, policy: Policy) -> Optional[Dict[Any, Any]]:
281
303
  # }
282
304
  if policy is not None:
283
305
  # get just the policy element and convert to JSON because boto3 returns this as string
284
- policy = Policy(json.loads(policy['Policy']))
306
+ policy = Policy(json.loads(policy["Policy"]))
285
307
  if policy.is_internet_accessible():
286
308
  return {
287
309
  "kms_key": key,
@@ -296,7 +318,10 @@ def parse_policy(key: str, policy: Policy) -> Optional[Dict[Any, Any]]:
296
318
 
297
319
  @timeit
298
320
  def load_kms_keys(
299
- neo4j_session: neo4j.Session, data: Dict, region: str, current_aws_account_id: str,
321
+ neo4j_session: neo4j.Session,
322
+ data: Dict,
323
+ region: str,
324
+ current_aws_account_id: str,
300
325
  aws_update_tag: int,
301
326
  ) -> None:
302
327
  ingest_keys = """
@@ -322,9 +347,9 @@ def load_kms_keys(
322
347
  # neo4j does not accept datetime objects and values. This loop is used to convert
323
348
  # these values to string.
324
349
  for key in data:
325
- key['CreationDate'] = str(key['CreationDate'])
326
- key['DeletionDate'] = str(key.get('DeletionDate'))
327
- key['ValidTo'] = str(key.get('ValidTo'))
350
+ key["CreationDate"] = str(key["CreationDate"])
351
+ key["DeletionDate"] = str(key.get("DeletionDate"))
352
+ key["ValidTo"] = str(key.get("ValidTo"))
328
353
 
329
354
  neo4j_session.run(
330
355
  ingest_keys,
@@ -337,29 +362,58 @@ def load_kms_keys(
337
362
 
338
363
  @timeit
339
364
  def cleanup_kms(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
340
- run_cleanup_job('aws_import_kms_cleanup.json', neo4j_session, common_job_parameters)
365
+ run_cleanup_job("aws_import_kms_cleanup.json", neo4j_session, common_job_parameters)
341
366
 
342
367
 
343
368
  @timeit
344
369
  def sync_kms_keys(
345
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, region: str, current_aws_account_id: str,
370
+ neo4j_session: neo4j.Session,
371
+ boto3_session: boto3.session.Session,
372
+ region: str,
373
+ current_aws_account_id: str,
346
374
  aws_update_tag: int,
347
375
  ) -> None:
348
376
  kms_keys = get_kms_key_list(boto3_session, region)
349
377
 
350
- load_kms_keys(neo4j_session, kms_keys, region, current_aws_account_id, aws_update_tag)
378
+ load_kms_keys(
379
+ neo4j_session,
380
+ kms_keys,
381
+ region,
382
+ current_aws_account_id,
383
+ aws_update_tag,
384
+ )
351
385
 
352
386
  policy_alias_grants_data = get_kms_key_details(boto3_session, kms_keys, region)
353
- load_kms_key_details(neo4j_session, policy_alias_grants_data, region, current_aws_account_id, aws_update_tag)
387
+ load_kms_key_details(
388
+ neo4j_session,
389
+ policy_alias_grants_data,
390
+ region,
391
+ current_aws_account_id,
392
+ aws_update_tag,
393
+ )
354
394
 
355
395
 
356
396
  @timeit
357
397
  def sync(
358
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
359
- update_tag: int, common_job_parameters: Dict,
398
+ neo4j_session: neo4j.Session,
399
+ boto3_session: boto3.session.Session,
400
+ regions: List[str],
401
+ current_aws_account_id: str,
402
+ update_tag: int,
403
+ common_job_parameters: Dict,
360
404
  ) -> None:
361
405
  for region in regions:
362
- logger.info("Syncing KMS for region %s in account '%s'.", region, current_aws_account_id)
363
- sync_kms_keys(neo4j_session, boto3_session, region, current_aws_account_id, update_tag)
406
+ logger.info(
407
+ "Syncing KMS for region %s in account '%s'.",
408
+ region,
409
+ current_aws_account_id,
410
+ )
411
+ sync_kms_keys(
412
+ neo4j_session,
413
+ boto3_session,
414
+ region,
415
+ current_aws_account_id,
416
+ update_tag,
417
+ )
364
418
 
365
419
  cleanup_kms(neo4j_session, common_job_parameters)
@@ -21,18 +21,22 @@ def get_lambda_data(boto3_session: boto3.session.Session, region: str) -> List[D
21
21
  """
22
22
  Create an Lambda boto3 client and grab all the lambda functions.
23
23
  """
24
- client = boto3_session.client('lambda', region_name=region)
25
- paginator = client.get_paginator('list_functions')
24
+ client = boto3_session.client("lambda", region_name=region)
25
+ paginator = client.get_paginator("list_functions")
26
26
  lambda_functions = []
27
27
  for page in paginator.paginate():
28
- for each_function in page['Functions']:
28
+ for each_function in page["Functions"]:
29
29
  lambda_functions.append(each_function)
30
30
  return lambda_functions
31
31
 
32
32
 
33
33
  @timeit
34
34
  def load_lambda_functions(
35
- neo4j_session: neo4j.Session, data: List[Dict], region: str, current_aws_account_id: str, aws_update_tag: int,
35
+ neo4j_session: neo4j.Session,
36
+ data: List[Dict],
37
+ region: str,
38
+ current_aws_account_id: str,
39
+ aws_update_tag: int,
36
40
  ) -> None:
37
41
  ingest_lambda_functions = """
38
42
  UNWIND $lambda_functions_list AS lf
@@ -86,22 +90,28 @@ def load_lambda_functions(
86
90
 
87
91
  @timeit
88
92
  @aws_handle_regions
89
- def get_function_aliases(lambda_function: Dict, client: botocore.client.BaseClient) -> List[Any]:
93
+ def get_function_aliases(
94
+ lambda_function: Dict,
95
+ client: botocore.client.BaseClient,
96
+ ) -> List[Any]:
90
97
  aliases: List[Any] = []
91
- paginator = client.get_paginator('list_aliases')
92
- for page in paginator.paginate(FunctionName=lambda_function['FunctionName']):
93
- aliases.extend(page['Aliases'])
98
+ paginator = client.get_paginator("list_aliases")
99
+ for page in paginator.paginate(FunctionName=lambda_function["FunctionName"]):
100
+ aliases.extend(page["Aliases"])
94
101
 
95
102
  return aliases
96
103
 
97
104
 
98
105
  @timeit
99
106
  @aws_handle_regions
100
- def get_event_source_mappings(lambda_function: Dict, client: botocore.client.BaseClient) -> List[Any]:
107
+ def get_event_source_mappings(
108
+ lambda_function: Dict,
109
+ client: botocore.client.BaseClient,
110
+ ) -> List[Any]:
101
111
  event_source_mappings: List[Any] = []
102
- paginator = client.get_paginator('list_event_source_mappings')
103
- for page in paginator.paginate(FunctionName=lambda_function['FunctionName']):
104
- event_source_mappings.extend(page['EventSourceMappings'])
112
+ paginator = client.get_paginator("list_event_source_mappings")
113
+ for page in paginator.paginate(FunctionName=lambda_function["FunctionName"]):
114
+ event_source_mappings.extend(page["EventSourceMappings"])
105
115
 
106
116
  return event_source_mappings
107
117
 
@@ -109,22 +119,32 @@ def get_event_source_mappings(lambda_function: Dict, client: botocore.client.Bas
109
119
  @timeit
110
120
  @aws_handle_regions
111
121
  def get_lambda_function_details(
112
- boto3_session: boto3.session.Session, data: List[Dict], region: str,
122
+ boto3_session: boto3.session.Session,
123
+ data: List[Dict],
124
+ region: str,
113
125
  ) -> List[Tuple[str, List[Any], List[Any], List[Any]]]:
114
- client = boto3_session.client('lambda', region_name=region)
126
+ client = boto3_session.client("lambda", region_name=region)
115
127
  details = []
116
128
  for lambda_function in data:
117
129
  function_aliases = get_function_aliases(lambda_function, client)
118
130
  event_source_mappings = get_event_source_mappings(lambda_function, client)
119
- layers = lambda_function.get('Layers', [])
120
- details.append((lambda_function['FunctionArn'], function_aliases, event_source_mappings, layers))
131
+ layers = lambda_function.get("Layers", [])
132
+ details.append(
133
+ (
134
+ lambda_function["FunctionArn"],
135
+ function_aliases,
136
+ event_source_mappings,
137
+ layers,
138
+ ),
139
+ )
121
140
  return details
122
141
 
123
142
 
124
143
  @timeit
125
144
  def load_lambda_function_details(
126
- neo4j_session: neo4j.Session, lambda_function_details: List[Tuple[str, List[Dict], List[Dict], List[Dict]]],
127
- update_tag: int,
145
+ neo4j_session: neo4j.Session,
146
+ lambda_function_details: List[Tuple[str, List[Dict], List[Dict], List[Dict]]],
147
+ update_tag: int,
128
148
  ) -> None:
129
149
  lambda_aliases: List[Dict] = []
130
150
  lambda_event_source_mappings: List[Dict] = []
@@ -132,22 +152,30 @@ def load_lambda_function_details(
132
152
  for function_arn, aliases, event_source_mappings, layers in lambda_function_details:
133
153
  if len(aliases) > 0:
134
154
  for alias in aliases:
135
- alias['FunctionArn'] = function_arn
155
+ alias["FunctionArn"] = function_arn
136
156
  lambda_aliases.extend(aliases)
137
157
  if len(event_source_mappings) > 0:
138
158
  lambda_event_source_mappings.extend(event_source_mappings)
139
159
  if len(layers) > 0:
140
160
  for layer in layers:
141
- layer['FunctionArn'] = function_arn
161
+ layer["FunctionArn"] = function_arn
142
162
  lambda_layers.extend(layers)
143
163
 
144
164
  _load_lambda_function_aliases(neo4j_session, lambda_aliases, update_tag)
145
- _load_lambda_event_source_mappings(neo4j_session, lambda_event_source_mappings, update_tag)
165
+ _load_lambda_event_source_mappings(
166
+ neo4j_session,
167
+ lambda_event_source_mappings,
168
+ update_tag,
169
+ )
146
170
  _load_lambda_layers(neo4j_session, lambda_layers, update_tag)
147
171
 
148
172
 
149
173
  @timeit
150
- def _load_lambda_function_aliases(neo4j_session: neo4j.Session, lambda_aliases: List[Dict], update_tag: int) -> None:
174
+ def _load_lambda_function_aliases(
175
+ neo4j_session: neo4j.Session,
176
+ lambda_aliases: List[Dict],
177
+ update_tag: int,
178
+ ) -> None:
151
179
  ingest_aliases = """
152
180
  UNWIND $aliases_list AS alias
153
181
  MERGE (a:AWSLambdaFunctionAlias{id: alias.AliasArn})
@@ -173,7 +201,9 @@ def _load_lambda_function_aliases(neo4j_session: neo4j.Session, lambda_aliases:
173
201
 
174
202
  @timeit
175
203
  def _load_lambda_event_source_mappings(
176
- neo4j_session: neo4j.Session, lambda_event_source_mappings: List[Dict], update_tag: int,
204
+ neo4j_session: neo4j.Session,
205
+ lambda_event_source_mappings: List[Dict],
206
+ update_tag: int,
177
207
  ) -> None:
178
208
  ingest_esms = """
179
209
  UNWIND $esm_list AS esm
@@ -208,7 +238,11 @@ def _load_lambda_event_source_mappings(
208
238
 
209
239
 
210
240
  @timeit
211
- def _load_lambda_layers(neo4j_session: neo4j.Session, lambda_layers: List[Dict], update_tag: int) -> None:
241
+ def _load_lambda_layers(
242
+ neo4j_session: neo4j.Session,
243
+ lambda_layers: List[Dict],
244
+ update_tag: int,
245
+ ) -> None:
212
246
  ingest_layers = """
213
247
  UNWIND $layers_list AS layer
214
248
  MERGE (l:AWSLambdaLayer{id: layer.Arn})
@@ -233,29 +267,64 @@ def _load_lambda_layers(neo4j_session: neo4j.Session, lambda_layers: List[Dict],
233
267
 
234
268
  @timeit
235
269
  def cleanup_lambda(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
236
- run_cleanup_job('aws_import_lambda_cleanup.json', neo4j_session, common_job_parameters)
270
+ run_cleanup_job(
271
+ "aws_import_lambda_cleanup.json",
272
+ neo4j_session,
273
+ common_job_parameters,
274
+ )
237
275
 
238
276
 
239
277
  @timeit
240
278
  def sync_lambda_functions(
241
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str],
242
- current_aws_account_id: str, aws_update_tag: int, common_job_parameters: Dict,
279
+ neo4j_session: neo4j.Session,
280
+ boto3_session: boto3.session.Session,
281
+ regions: List[str],
282
+ current_aws_account_id: str,
283
+ aws_update_tag: int,
284
+ common_job_parameters: Dict,
243
285
  ) -> None:
244
286
  for region in regions:
245
- logger.info("Syncing Lambda for region in '%s' in account '%s'.", region, current_aws_account_id)
287
+ logger.info(
288
+ "Syncing Lambda for region in '%s' in account '%s'.",
289
+ region,
290
+ current_aws_account_id,
291
+ )
246
292
  data = get_lambda_data(boto3_session, region)
247
- load_lambda_functions(neo4j_session, data, region, current_aws_account_id, aws_update_tag)
248
- lambda_function_details = get_lambda_function_details(boto3_session, data, region)
249
- load_lambda_function_details(neo4j_session, lambda_function_details, aws_update_tag)
293
+ load_lambda_functions(
294
+ neo4j_session,
295
+ data,
296
+ region,
297
+ current_aws_account_id,
298
+ aws_update_tag,
299
+ )
300
+ lambda_function_details = get_lambda_function_details(
301
+ boto3_session,
302
+ data,
303
+ region,
304
+ )
305
+ load_lambda_function_details(
306
+ neo4j_session,
307
+ lambda_function_details,
308
+ aws_update_tag,
309
+ )
250
310
 
251
311
  cleanup_lambda(neo4j_session, common_job_parameters)
252
312
 
253
313
 
254
314
  @timeit
255
315
  def sync(
256
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str],
257
- current_aws_account_id: str, update_tag: int, common_job_parameters: Dict,
316
+ neo4j_session: neo4j.Session,
317
+ boto3_session: boto3.session.Session,
318
+ regions: List[str],
319
+ current_aws_account_id: str,
320
+ update_tag: int,
321
+ common_job_parameters: Dict,
258
322
  ) -> None:
259
323
  sync_lambda_functions(
260
- neo4j_session, boto3_session, regions, current_aws_account_id, update_tag, common_job_parameters,
324
+ neo4j_session,
325
+ boto3_session,
326
+ regions,
327
+ current_aws_account_id,
328
+ update_tag,
329
+ common_job_parameters,
261
330
  )
@@ -16,19 +16,22 @@ def get_account_from_arn(arn: str) -> str:
16
16
 
17
17
 
18
18
  def get_caller_identity(boto3_session: boto3.session.Session) -> Dict:
19
- client = boto3_session.client('sts')
19
+ client = boto3_session.client("sts")
20
20
  return client.get_caller_identity()
21
21
 
22
22
 
23
23
  def get_current_aws_account_id(boto3_session: boto3.session.Session) -> Dict:
24
- return get_caller_identity(boto3_session)['Account']
24
+ return get_caller_identity(boto3_session)["Account"]
25
25
 
26
26
 
27
27
  def get_aws_account_default(boto3_session: boto3.session.Session) -> Dict:
28
28
  try:
29
29
  return {boto3_session.profile_name: get_current_aws_account_id(boto3_session)}
30
30
  except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
31
- logger.debug("Error occurred getting default AWS account number.", exc_info=True)
31
+ logger.debug(
32
+ "Error occurred getting default AWS account number.",
33
+ exc_info=True,
34
+ )
32
35
  logger.error(
33
36
  (
34
37
  "Unable to get AWS account number, an error occurred: '%s'. Make sure your AWS credentials are "
@@ -43,13 +46,20 @@ def get_aws_account_default(boto3_session: boto3.session.Session) -> Dict:
43
46
  def get_aws_accounts_from_botocore_config(boto3_session: boto3.session.Session) -> Dict:
44
47
  d = {}
45
48
  for profile_name in boto3_session.available_profiles:
46
- if profile_name == 'default':
49
+ if profile_name == "default":
47
50
  logger.debug("Skipping AWS profile 'default'.")
48
51
  continue
49
52
  try:
50
53
  profile_boto3_session = boto3.Session(profile_name=profile_name)
51
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
52
- logger.debug("Error occurred calling boto3.Session() with profile_name '%s'.", profile_name, exc_info=True)
54
+ except (
55
+ botocore.exceptions.BotoCoreError,
56
+ botocore.exceptions.ClientError,
57
+ ) as e:
58
+ logger.debug(
59
+ "Error occurred calling boto3.Session() with profile_name '%s'.",
60
+ profile_name,
61
+ exc_info=True,
62
+ )
53
63
  logger.error(
54
64
  (
55
65
  "Unable to initialize an AWS session using profile '%s', an error occurred: '%s'. Make sure your "
@@ -62,7 +72,10 @@ def get_aws_accounts_from_botocore_config(boto3_session: boto3.session.Session)
62
72
  continue
63
73
  try:
64
74
  d[profile_name] = get_current_aws_account_id(profile_boto3_session)
65
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
75
+ except (
76
+ botocore.exceptions.BotoCoreError,
77
+ botocore.exceptions.ClientError,
78
+ ) as e:
66
79
  logger.debug(
67
80
  "Error occurred getting AWS account number with profile_name '%s'.",
68
81
  profile_name,
@@ -87,7 +100,9 @@ def get_aws_accounts_from_botocore_config(boto3_session: boto3.session.Session)
87
100
 
88
101
 
89
102
  def load_aws_accounts(
90
- neo4j_session: neo4j.Session, aws_accounts: Dict, aws_update_tag: int,
103
+ neo4j_session: neo4j.Session,
104
+ aws_accounts: Dict,
105
+ aws_update_tag: int,
91
106
  common_job_parameters: Dict,
92
107
  ) -> None:
93
108
  query = """
@@ -105,7 +120,7 @@ def load_aws_accounts(
105
120
  SET r.lastupdated = $aws_update_tag;
106
121
  """
107
122
  for account_name, account_id in aws_accounts.items():
108
- root_arn = f'arn:aws:iam::{account_id}:root'
123
+ root_arn = f"arn:aws:iam::{account_id}:root"
109
124
  neo4j_session.run(
110
125
  query,
111
126
  ACCOUNT_ID=account_id,
@@ -116,5 +131,10 @@ def load_aws_accounts(
116
131
 
117
132
 
118
133
  @timeit
119
- def sync(neo4j_session: neo4j.Session, accounts: Dict, update_tag: int, common_job_parameters: Dict) -> None:
134
+ def sync(
135
+ neo4j_session: neo4j.Session,
136
+ accounts: Dict,
137
+ update_tag: int,
138
+ common_job_parameters: Dict,
139
+ ) -> None:
120
140
  load_aws_accounts(neo4j_session, accounts, update_tag, common_job_parameters)