illumio-pylo 0.2.5__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.
Files changed (73) hide show
  1. illumio_pylo/API/APIConnector.py +1308 -0
  2. illumio_pylo/API/AuditLog.py +42 -0
  3. illumio_pylo/API/ClusterHealth.py +136 -0
  4. illumio_pylo/API/CredentialsManager.py +286 -0
  5. illumio_pylo/API/Explorer.py +1077 -0
  6. illumio_pylo/API/JsonPayloadTypes.py +240 -0
  7. illumio_pylo/API/RuleSearchQuery.py +128 -0
  8. illumio_pylo/API/__init__.py +0 -0
  9. illumio_pylo/AgentStore.py +139 -0
  10. illumio_pylo/Exception.py +44 -0
  11. illumio_pylo/Helpers/__init__.py +3 -0
  12. illumio_pylo/Helpers/exports.py +508 -0
  13. illumio_pylo/Helpers/functions.py +166 -0
  14. illumio_pylo/IPList.py +135 -0
  15. illumio_pylo/IPMap.py +285 -0
  16. illumio_pylo/Label.py +25 -0
  17. illumio_pylo/LabelCommon.py +48 -0
  18. illumio_pylo/LabelGroup.py +68 -0
  19. illumio_pylo/LabelStore.py +403 -0
  20. illumio_pylo/LabeledObject.py +25 -0
  21. illumio_pylo/Organization.py +258 -0
  22. illumio_pylo/Query.py +331 -0
  23. illumio_pylo/ReferenceTracker.py +41 -0
  24. illumio_pylo/Rule.py +671 -0
  25. illumio_pylo/Ruleset.py +306 -0
  26. illumio_pylo/RulesetStore.py +101 -0
  27. illumio_pylo/SecurityPrincipal.py +62 -0
  28. illumio_pylo/Service.py +256 -0
  29. illumio_pylo/SoftwareVersion.py +125 -0
  30. illumio_pylo/VirtualService.py +17 -0
  31. illumio_pylo/VirtualServiceStore.py +75 -0
  32. illumio_pylo/Workload.py +506 -0
  33. illumio_pylo/WorkloadStore.py +289 -0
  34. illumio_pylo/__init__.py +82 -0
  35. illumio_pylo/cli/NativeParsers.py +96 -0
  36. illumio_pylo/cli/__init__.py +134 -0
  37. illumio_pylo/cli/__main__.py +10 -0
  38. illumio_pylo/cli/commands/__init__.py +32 -0
  39. illumio_pylo/cli/commands/credential_manager.py +168 -0
  40. illumio_pylo/cli/commands/iplist_import_from_file.py +185 -0
  41. illumio_pylo/cli/commands/misc.py +7 -0
  42. illumio_pylo/cli/commands/ruleset_export.py +129 -0
  43. illumio_pylo/cli/commands/update_pce_objects_cache.py +44 -0
  44. illumio_pylo/cli/commands/ven_duplicate_remover.py +366 -0
  45. illumio_pylo/cli/commands/ven_idle_to_visibility.py +287 -0
  46. illumio_pylo/cli/commands/ven_upgrader.py +226 -0
  47. illumio_pylo/cli/commands/workload_export.py +251 -0
  48. illumio_pylo/cli/commands/workload_import.py +423 -0
  49. illumio_pylo/cli/commands/workload_relabeler.py +510 -0
  50. illumio_pylo/cli/commands/workload_reset_names_to_null.py +83 -0
  51. illumio_pylo/cli/commands/workload_used_in_rule_finder.py +80 -0
  52. illumio_pylo/docs/Doxygen +1757 -0
  53. illumio_pylo/tmp.py +104 -0
  54. illumio_pylo/utilities/__init__.py +0 -0
  55. illumio_pylo/utilities/cli.py +10 -0
  56. illumio_pylo/utilities/credentials.example.json +20 -0
  57. illumio_pylo/utilities/explorer_report_exporter.py +86 -0
  58. illumio_pylo/utilities/health_monitoring.py +102 -0
  59. illumio_pylo/utilities/iplist_analyzer.py +148 -0
  60. illumio_pylo/utilities/iplists_stats_duplicates_unused_finder.py +75 -0
  61. illumio_pylo/utilities/resources/iplists-import-example.csv +3 -0
  62. illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
  63. illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +3 -0
  64. illumio_pylo/utilities/resources/workloads-import-example.csv +2 -0
  65. illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
  66. illumio_pylo/utilities/ven_compatibility_report_export.py +240 -0
  67. illumio_pylo/utilities/ven_idle_to_illumination.py +344 -0
  68. illumio_pylo/utilities/ven_reassign_pce.py +183 -0
  69. illumio_pylo-0.2.5.dist-info/LICENSE +176 -0
  70. illumio_pylo-0.2.5.dist-info/METADATA +197 -0
  71. illumio_pylo-0.2.5.dist-info/RECORD +73 -0
  72. illumio_pylo-0.2.5.dist-info/WHEEL +5 -0
  73. illumio_pylo-0.2.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1077 @@
1
+ import sys
2
+ from typing import Optional, List, Dict, Literal, TypeVar, Generic, Union
3
+ from datetime import datetime, timedelta
4
+
5
+ import illumio_pylo as pylo
6
+ from .JsonPayloadTypes import RuleCoverageQueryEntryJsonStructure
7
+ from illumio_pylo.API.APIConnector import APIConnector
8
+
9
+ class ExplorerResult:
10
+ _draft_mode_policy_decision: Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]
11
+ destination_workload_labels_href: List[str]
12
+ source_workload_labels_href: List[str]
13
+
14
+ def __init__(self, data):
15
+ self.raw_json = data
16
+ self.num_connections = data['num_connections']
17
+
18
+ self.policy_decision_string = data['policy_decision']
19
+ self._draft_mode_policy_decision = None
20
+
21
+ self.source_ip_fqdn: Optional[str] = None
22
+ self.destination_ip_fqdn: Optional[str] = None
23
+
24
+ src = data['src']
25
+ self.source_ip: str = src['ip']
26
+ self._source_iplists = src.get('ip_lists')
27
+ self._source_iplists_href: List[str] = []
28
+ if self._source_iplists is not None:
29
+ for href in self._source_iplists:
30
+ self._source_iplists_href.append(href['href'])
31
+
32
+ self.source_workload_href: Optional[str] = None
33
+ workload_data = src.get('workload')
34
+ if workload_data is not None:
35
+ self.source_workload_href: Optional[str] = workload_data.get('href')
36
+ if self.source_workload_href is None:
37
+ raise pylo.PyloApiUnexpectedSyntax("Explorer API has return a record referring to a Workload with no HREF given:", data)
38
+
39
+ self.source_workload_labels_href: Optional[List[str]] = []
40
+ workload_labels_data = workload_data.get('labels')
41
+ if workload_labels_data is not None:
42
+ for label_data in workload_labels_data:
43
+ self.source_workload_labels_href.append(label_data.get('href'))
44
+
45
+ dst = data['dst']
46
+ self.destination_ip: str = dst['ip']
47
+ self.destination_ip_fqdn = dst.get('fqdn')
48
+ self._destination_iplists = dst.get('ip_lists')
49
+ self._destination_iplists_href: List[str] = []
50
+ if self._destination_iplists is not None:
51
+ for href in self._destination_iplists:
52
+ self._destination_iplists_href.append(href['href'])
53
+
54
+ self.destination_workload_href: Optional[str] = None
55
+ workload_data = dst.get('workload')
56
+ if workload_data is not None:
57
+ self.destination_workload_href = workload_data.get('href')
58
+ if self.destination_workload_href is None:
59
+ raise pylo.PyloApiUnexpectedSyntax("Explorer API has return a record referring to a Workload with no HREF given:", data)
60
+
61
+ self.destination_workload_labels_href: Optional[List[str]] = []
62
+ workload_labels_data = workload_data.get('labels')
63
+ if workload_labels_data is not None:
64
+ for label_data in workload_labels_data:
65
+ self.destination_workload_labels_href.append(label_data.get('href'))
66
+
67
+ service_json = data['service']
68
+ self.service_json = service_json
69
+
70
+ self.service_protocol: int = service_json['proto']
71
+ self.service_port: Optional[int] = service_json.get('port')
72
+ self.process_name: Optional[str] = service_json.get('process_name')
73
+ self.username: Optional[str] = service_json.get('user_name')
74
+
75
+ self.first_detected: str = data['timestamp_range']['first_detected']
76
+ self.last_detected: str = data['timestamp_range']['last_detected']
77
+
78
+ self._cast_type: Optional[str] = data.get('transmission')
79
+
80
+ def service_to_str(self, protocol_first=True):
81
+ if protocol_first:
82
+ if self.service_port is None or self.service_port == 0:
83
+ return 'proto/{}'.format(self.service_protocol)
84
+
85
+ if self.service_protocol == 17:
86
+ return 'udp/{}'.format(self.service_port)
87
+
88
+ if self.service_protocol == 6:
89
+ return 'tcp/{}'.format(self.service_port)
90
+ else:
91
+ if self.service_port is None or self.service_port == 0:
92
+ return '{}/proto'.format(self.service_protocol)
93
+
94
+ if self.service_protocol == 17:
95
+ return '{}/udp'.format(self.service_port)
96
+
97
+ if self.service_protocol == 6:
98
+ return '{}/tcp'.format(self.service_port)
99
+
100
+ def service_to_str_array(self):
101
+ if self.service_port is None or self.service_port == 0:
102
+ return [self.service_protocol, 'proto']
103
+
104
+ if self.service_protocol == 17:
105
+ return [self.service_port, 'udp']
106
+
107
+ if self.service_protocol == 6:
108
+ return [self.service_port, 'tcp']
109
+
110
+ return ['n/a', 'n/a']
111
+
112
+ def source_is_workload(self):
113
+ return self.source_workload_href is not None
114
+
115
+ def destination_is_workload(self):
116
+ return self.destination_workload_href is not None
117
+
118
+ def get_source_workload_href(self):
119
+ return self.source_workload_href
120
+
121
+ def get_destination_workload_href(self):
122
+ return self.destination_workload_href
123
+
124
+ def get_source_workload(self, org_for_resolution: 'pylo.Organization') -> Optional['pylo.Workload']:
125
+ if self.source_workload_href is None:
126
+ return None
127
+ return org_for_resolution.WorkloadStore.find_by_href_or_create_tmp(self.source_workload_href, '*DELETED*')
128
+
129
+ def get_destination_workload(self, org_for_resolution: 'pylo.Organization') -> Optional['pylo.Workload']:
130
+ if self.destination_workload_href is None:
131
+ return None
132
+ return org_for_resolution.WorkloadStore.find_by_href_or_create_tmp(self.destination_workload_href, '*DELETED*')
133
+
134
+ def get_source_labels_href(self) -> Optional[List[str]]:
135
+ if not self.source_is_workload():
136
+ return None
137
+ return self.source_workload_labels_href
138
+
139
+ def get_destination_labels_href(self) -> Optional[List[str]]:
140
+ if not self.destination_is_workload():
141
+ return None
142
+ return self.destination_workload_labels_href
143
+
144
+ def get_source_iplists(self, org_for_resolution: 'pylo.Organization') ->Dict[str, 'pylo.IPList']:
145
+ if self._source_iplists is None:
146
+ return {}
147
+
148
+ result = {}
149
+
150
+ for record in self._source_iplists:
151
+ href = record.get('href')
152
+ if href is None:
153
+ raise pylo.PyloEx('Cannot find HREF for IPList in Explorer result json', record)
154
+ iplist = org_for_resolution.IPListStore.find_by_href(href)
155
+ if iplist is None:
156
+ raise pylo.PyloEx('Cannot find HREF for IPList in Explorer result json', record)
157
+
158
+ result[href] = iplist
159
+
160
+ return result
161
+
162
+ def get_source_iplists_href(self) -> Optional[List[str]]:
163
+ if self.source_is_workload():
164
+ return None
165
+ if self._source_iplists_href is None:
166
+ return []
167
+ return self._source_iplists_href.copy()
168
+
169
+ def get_destination_iplists_href(self) -> Optional[List[str]]:
170
+ if self.destination_is_workload():
171
+ return None
172
+
173
+ if self._destination_iplists_href is None:
174
+ return []
175
+ return self._destination_iplists_href.copy()
176
+
177
+ def get_destination_iplists(self, org_for_resolution: 'pylo.Organization') ->Dict[str, 'pylo.IPList']:
178
+ if self._destination_iplists is None:
179
+ return {}
180
+
181
+ result = {}
182
+
183
+ for record in self._destination_iplists:
184
+ href = record.get('href')
185
+ if href is None:
186
+ raise pylo.PyloEx('Cannot find HREF for IPList in Explorer result json', record)
187
+ iplist = org_for_resolution.IPListStore.find_by_href(href)
188
+ if iplist is None:
189
+ raise pylo.PyloEx('Cannot find HREF for IPList in Explorer result json', record)
190
+
191
+ result[href] = iplist
192
+
193
+ return result
194
+
195
+ def pd_is_potentially_blocked(self):
196
+ return self.policy_decision_string == 'potentially_blocked'
197
+
198
+ def cast_is_broadcast(self):
199
+ return self._cast_type == 'broadcast'
200
+
201
+ def cast_is_multicast(self):
202
+ return self._cast_type == 'multicast'
203
+
204
+ def cast_is_unicast(self):
205
+ return self._cast_type is not None
206
+
207
+ def set_draft_mode_policy_decision(self, decision: Literal['allowed', 'blocked', 'blocked_by_boundary']):
208
+ self._draft_mode_policy_decision = decision
209
+
210
+ def draft_mode_policy_decision_is_blocked(self) -> Optional[bool]:
211
+ """
212
+ @return: None if draft_mode was not enabled
213
+ """
214
+ return self._draft_mode_policy_decision is not None and \
215
+ (self._draft_mode_policy_decision == 'blocked' or self._draft_mode_policy_decision == 'blocked_by_boundary')
216
+
217
+ def draft_mode_policy_decision_is_allowed(self) -> Optional[bool]:
218
+ """
219
+ @return: None if draft_mode was not enabled
220
+ """
221
+ return self._draft_mode_policy_decision is not None and self._draft_mode_policy_decision == "allowed"
222
+
223
+ def draft_mode_policy_decision_is_unavailable(self) -> Optional[bool]:
224
+ """
225
+ @return: None if draft_mode was not enabled
226
+ """
227
+ return self._draft_mode_policy_decision is None
228
+
229
+ def draft_mode_policy_decision_is_not_defined(self) -> Optional[bool]:
230
+ return self._draft_mode_policy_decision is None
231
+
232
+ def draft_mode_policy_decision_to_str(self) -> str:
233
+ if self._draft_mode_policy_decision is None:
234
+ return 'not_available'
235
+ return self._draft_mode_policy_decision
236
+
237
+
238
+ class ExplorerResultSetV1:
239
+
240
+ owner: 'APIConnector'
241
+
242
+ def __init__(self, data, owner: 'APIConnector', emulated_process_exclusion={}):
243
+ self.owner = owner
244
+ self._raw_results = data
245
+ if len(emulated_process_exclusion) > 0:
246
+ new_data = []
247
+ for record in self._raw_results:
248
+ if 'process_name' in record['service']:
249
+ if record['service']['process_name'] in emulated_process_exclusion:
250
+ continue
251
+ new_data.append(record)
252
+ self._raw_results = new_data
253
+
254
+ self._records: List[ExplorerResult] = []
255
+ self._gen_records()
256
+
257
+ def _gen_records(self):
258
+ for data in self._raw_results:
259
+ try:
260
+ new_record = ExplorerResult(data)
261
+ self._records.append(new_record)
262
+
263
+ except pylo.PyloApiUnexpectedSyntax as error:
264
+ pylo.log.warn(error)
265
+
266
+ def count_records(self):
267
+ return len(self._raw_results)
268
+
269
+ def get_record(self, line: int):
270
+ if line < 0:
271
+ raise pylo.PyloEx('Invalid line #: {}'.format(line))
272
+ if line >= len(self._raw_results):
273
+ raise pylo.PyloEx('Line # doesnt exists, requested #{} while this set contains only {} (starts at 0)'.
274
+ format(line, len(self._raw_results)))
275
+
276
+ return ExplorerResult(self._raw_results[line])
277
+
278
+ def get_all_records(self) -> List[ExplorerResult]:
279
+ return self._records
280
+
281
+ def merge_similar_records_only_process_and_user_differs(self):
282
+ class HashTable:
283
+ def __init__(self):
284
+ self.entries: Dict[str, List[ExplorerResult]] = {}
285
+
286
+ def load(self, records: List[ExplorerResult]):
287
+ for record in records:
288
+ hash = record.source_ip + record.destination_ip + str(record.source_workload_href) + \
289
+ str(record.destination_workload_href) + record.service_to_str() + \
290
+ record.policy_decision_string + record.draft_mode_policy_decision_to_str()
291
+ entry_from_hash = self.entries.get(hash)
292
+ if entry_from_hash is None:
293
+ self.entries[hash] = [record]
294
+ else:
295
+ entry_from_hash.append(record)
296
+
297
+ def results(self) -> List[ExplorerResult]:
298
+ results_list: List[ExplorerResult] = []
299
+
300
+ for hashEntry in self.entries.values():
301
+ if len(hashEntry) == 1:
302
+ results_list.append(hashEntry[0])
303
+ continue
304
+
305
+ record_to_keep = hashEntry.pop()
306
+ merged_users = []
307
+ merged_processes = []
308
+ count_connections = 0
309
+
310
+ last_detected = record_to_keep.last_detected
311
+ first_detected = record_to_keep.first_detected
312
+
313
+ for record in hashEntry:
314
+ if record.username is not None and len(record.username) > 0:
315
+ merged_users.append(record.username)
316
+ if record.process_name is not None and len(record.process_name) > 0:
317
+ merged_processes.append(record.process_name)
318
+ if last_detected < record.last_detected:
319
+ last_detected = record.last_detected
320
+ if first_detected > record.first_detected:
321
+ first_detected = record.first_detected
322
+
323
+ count_connections = count_connections + record.num_connections
324
+
325
+ merged_users = list(set(merged_users))
326
+ merged_processes = list(set(merged_processes))
327
+
328
+ record_to_keep.process_name = merged_processes
329
+ record_to_keep.username = merged_users
330
+ record_to_keep.num_connections = count_connections
331
+ record_to_keep.last_detected = last_detected
332
+ record_to_keep.first_detected = first_detected
333
+
334
+ results_list.append(record_to_keep)
335
+
336
+ return results_list
337
+
338
+ hash_table: HashTable = HashTable()
339
+ hash_table.load(self._records)
340
+ self._records = hash_table.results()
341
+
342
+ def apply_draft_policy_decision_to_all_records(self):
343
+ draft_manager = RuleCoverageQueryManager(self.owner)
344
+ draft_manager.add_query_from_explorer_results(self._records)
345
+ draft_manager.execute()
346
+
347
+
348
+
349
+ class RuleCoverageQueryManager:
350
+
351
+ class QueryServices:
352
+ def __init__(self):
353
+ self.service_hash_to_index: Dict[str, int] = {}
354
+ self.services_array: List[Dict] = []
355
+ self.service_index_to_log_ids: Dict[int, List[int]] = {}
356
+ self.service_index_policy_coverage: Dict[int, List[str]] = {} # for a service ID (used as key) returns a list of matching rules HREF
357
+ self.service_index_to_boundary_policy_coverage: Dict[int, List[str]] = {} # for a service ID (used as key) returns a list of matching boundary rules HREF
358
+
359
+ def add_service(self, service_record: Dict, log_id: int):
360
+ service_hash = '' + str(service_record.get('proto', 'no_proto')) + '/' + str(service_record.get('port', 'no_port')) + '/' \
361
+ + '/' + str(service_record.get('process_name', 'no_process_name')) \
362
+ + '/' + str(service_record.get('windows_service_name', 'no_windows_service_name'))
363
+ # username is not allows in rule_coverage
364
+
365
+ # print(service_hash)
366
+
367
+ if service_hash not in self.service_hash_to_index:
368
+ self.service_hash_to_index[service_hash] = len(self.services_array)
369
+ self.services_array.append(service_record)
370
+
371
+ service_index = self.service_hash_to_index[service_hash]
372
+ if service_index not in self.service_index_to_log_ids:
373
+ self.service_index_to_log_ids[service_index] = []
374
+
375
+ if log_id not in self.service_index_to_log_ids[service_index]:
376
+ self.service_index_to_log_ids[service_index].append(log_id)
377
+
378
+ def get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]:
379
+ policy_decision = None
380
+ found_boundary_block = False
381
+
382
+ for service_id, list_of_log_ids in self.service_index_to_log_ids.items():
383
+ if log_id in list_of_log_ids:
384
+ policy_decision = 'blocked'
385
+ policy_coverage = self.service_index_policy_coverage[service_id]
386
+ if len(policy_coverage) > 0:
387
+ return 'allowed'
388
+
389
+ boundary_policy_coverage = self.service_index_to_boundary_policy_coverage[service_id]
390
+ if len(boundary_policy_coverage) > 0:
391
+ found_boundary_block = True
392
+
393
+ if found_boundary_block:
394
+ return 'blocked_by_boundary'
395
+
396
+ return policy_decision
397
+
398
+ class ObjectToObjectQuery:
399
+ def __init__(self, src_href: str, src_type: Literal['ip_list','workload'], dst_href: str, dst_type: Literal['ip_list','workload']):
400
+ self.src_href = src_href
401
+ self.dst_href = dst_href
402
+ self.src_type = src_type
403
+ self.dst_type = dst_type
404
+ self.services = RuleCoverageQueryManager.QueryServices()
405
+
406
+ def add_service(self, service_record: Dict, log_id: int):
407
+ self.services.add_service(service_record, log_id)
408
+
409
+ def get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]:
410
+ return self.services.get_policy_decision_for_log_id(log_id)
411
+
412
+ def process_response(self, rules: Dict[str, str], response: [[str]]):
413
+ if len(response) != len(self.services.services_array):
414
+ raise Exception('Unexpected response from rule coverage query with mis-matching services count vs reply')
415
+
416
+ for index, single_response in enumerate(response):
417
+ rules_array: [Dict] = []
418
+ for rule in single_response:
419
+ rules_array.append(rules[rule])
420
+ self.services.service_index_policy_coverage[index] = rules_array
421
+
422
+ def process_response_boundary_deny(self, rules: Dict[str, str], response: [[str]]):
423
+ if len(response) != len(self.services.services_array):
424
+ raise Exception('Unexpected response from rule coverage query with mis-matching services count vs reply')
425
+
426
+ for index, single_response in enumerate(response):
427
+ rules_array: [Dict] = []
428
+ for rule in single_response:
429
+ rules_array.append(rules[rule])
430
+ self.services.service_index_to_boundary_policy_coverage[index] = rules_array
431
+
432
+ def generate_api_payload(self) -> RuleCoverageQueryEntryJsonStructure:
433
+ payload: RuleCoverageQueryEntryJsonStructure = {"resolve_labels_as": {"source": ["workloads"], "destination": ["workloads"]}, "services": [],
434
+ 'source': {self.src_type: {'href': self.src_href}},
435
+ 'destination': {self.dst_type: {'href': self.dst_href}}
436
+ }
437
+
438
+ for service_id in range(0, len(self.services.services_array)):
439
+ service = self.services.services_array[service_id]
440
+ # print(service)
441
+ service_json: Dict = service.copy()
442
+ service_json['protocol'] = service_json.pop('proto')
443
+ if 'port' in service_json and service_json['protocol'] != 17 and service_json['protocol'] != 6:
444
+ service_json.pop('port')
445
+ if 'user_name' in service_json:
446
+ service_json.pop('user_name')
447
+ payload['services'].append(service_json)
448
+
449
+ return payload
450
+
451
+ class QueryManager:
452
+ def __init__(self, src_type:Literal['ip_list','workload'], dst_type:Literal['ip_list','workload'] ,include_boundary_rules: bool = True):
453
+ self.queries: Dict[str, RuleCoverageQueryManager.ObjectToObjectQuery] = {}
454
+ self.include_boundary_rules = include_boundary_rules
455
+ self.src_type = src_type
456
+ self.dst_type = dst_type
457
+
458
+ def execute(self, connector: APIConnector, queries_per_batch: int):
459
+ # split queries into arrays of size queries_per_batch
460
+ query_batches: List[List[RuleCoverageQueryManager.ObjectToObjectQuery]] = []
461
+ query_batch: List[RuleCoverageQueryManager.ObjectToObjectQuery] = []
462
+ for query in self.queries.values():
463
+ query_batch.append(query)
464
+ if len(query_batch) == queries_per_batch:
465
+ query_batches.append(query_batch)
466
+ query_batch = []
467
+ if len(query_batch) > 0:
468
+ query_batches.append(query_batch)
469
+
470
+ # print(f'{len(query_batches)} batches of {queries_per_batch} queries')
471
+
472
+ for query_batch in query_batches:
473
+ # print(f'Executing batch of {len(query_batch)} queries')
474
+ payload = []
475
+ for query in query_batch:
476
+ payload.append(query.generate_api_payload())
477
+
478
+ api_response = connector.rule_coverage_query(payload, include_boundary_rules=self.include_boundary_rules)
479
+ # print(api_response)
480
+ # print('-------------------------------------------------------')
481
+
482
+ edges = api_response.get('edges')
483
+ if edges is None:
484
+ raise pylo.PyloEx('rule_coverage request has returned no "edges"', api_response)
485
+
486
+ rules = api_response.get('rules')
487
+ if rules is None:
488
+ raise pylo.PyloEx('rule_coverage request has returned no "rules"', api_response)
489
+
490
+ if len(edges) != len(query_batch):
491
+ raise pylo.PyloEx("rule_coverage has returned {} records while {} where requested".format(len(edges), len(query_batch)))
492
+
493
+ for response_index, edge in enumerate(edges):
494
+ query = query_batch[response_index]
495
+ # print(f'Processing edge {edge} against query {query.ip_list_href} -> {query.workload_href} -> {len(query.services.services_array)}')
496
+ query.process_response(rules, edge)
497
+
498
+ if self.include_boundary_rules:
499
+ deny_edges = api_response.get('deny_edges')
500
+ if deny_edges is None:
501
+ raise pylo.PyloEx('rule_coverage request has returned no "deny_edges"', api_response)
502
+ if len(deny_edges) != len(query_batch):
503
+ raise pylo.PyloEx("rule_coverage has returned {} deny_edges while {} where requested".format(len(deny_edges), len(query_batch)))
504
+
505
+ deny_rules = api_response.get('deny_rules')
506
+ if deny_rules is None:
507
+ raise pylo.PyloEx('rule_coverage request has returned no "deny_rules"', api_response)
508
+
509
+ for response_index, edge in enumerate(deny_edges):
510
+ query = query_batch[response_index]
511
+ # print(f'Processing deny_edge {edge} against query {query.src_workload_href} -> {query.dst_workload_href} -> {len(query.services.services_array)}')
512
+ query.process_response_boundary_deny(deny_rules, edge)
513
+
514
+ def get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal["allowed", "blocked", "blocked_by_boundary"]]:
515
+ policy_decision: Optional[Literal["allowed", "blocked", "blocked_by_boundary"]] = None
516
+ found_blocked_by_boundary = False
517
+
518
+ for query in self.queries.values():
519
+ policy_decision = query.get_policy_decision_for_log_id(log_id) or policy_decision
520
+ if policy_decision == 'allowed':
521
+ return policy_decision
522
+ if query.get_policy_decision_for_log_id(log_id) == 'blocked_by_boundary':
523
+ found_blocked_by_boundary = True
524
+
525
+ if found_blocked_by_boundary:
526
+ return 'blocked_by_boundary'
527
+
528
+ return policy_decision
529
+
530
+ def add_query(self, log_id: int, src_href: str, dst_href: str, service_record):
531
+ hash_key = src_href + dst_href
532
+ if hash_key not in self.queries:
533
+ self.queries[hash_key] = RuleCoverageQueryManager.ObjectToObjectQuery(src_href, self.src_type, dst_href, self.dst_type)
534
+
535
+ self.queries[hash_key].add_service(service_record, log_id)
536
+
537
+
538
+ def __init__(self, owner: APIConnector):
539
+ self.owner = owner
540
+ self.iplist_to_workload_query_manager = RuleCoverageQueryManager.QueryManager('ip_list', 'workload')
541
+ self.workload_to_iplist_query_manager = RuleCoverageQueryManager.QueryManager('workload', 'ip_list')
542
+ self.workload_to_workload_query_manager = RuleCoverageQueryManager.QueryManager('workload', 'workload')
543
+ self.log_id = 0
544
+ self.log_to_id: Dict[ExplorerResult, int] = {}
545
+ self.count_invalid_records = 0
546
+ self.any_iplist_href = self.owner.objects_iplists_get_default_any()
547
+ if self.any_iplist_href is None:
548
+ raise pylo.PyloEx('No "any" iplist found')
549
+
550
+ def add_query_from_explorer_results(self, explorer_results: List[ExplorerResult]) -> None:
551
+ for explorer_result in explorer_results:
552
+ self.add_query_from_explorer_result(explorer_result)
553
+
554
+ def add_query_from_explorer_result(self, log: ExplorerResult):
555
+ self.log_id += 1
556
+ self.log_to_id[log] = self.log_id
557
+
558
+
559
+ if not log.source_is_workload():
560
+ if log.destination_is_workload():
561
+ iplist_hrefs = log.get_source_iplists_href()
562
+ if iplist_hrefs is None:
563
+ iplist_hrefs = [self.any_iplist_href]
564
+ else:
565
+ iplist_hrefs.append(self.any_iplist_href)
566
+
567
+ for iplist_href in iplist_hrefs:
568
+ self.iplist_to_workload_query_manager.add_query(log_id=self.log_id,
569
+ src_href=iplist_href,
570
+ dst_href=log.get_destination_workload_href(),
571
+ service_record=log.service_json)
572
+ else: # IPList to IPList should never happen!
573
+ self.count_invalid_records += 1
574
+ pass
575
+ else:
576
+ if not log.destination_is_workload():
577
+ iplist_hrefs = log.get_destination_iplists_href()
578
+ if iplist_hrefs is None:
579
+ iplist_hrefs = [self.any_iplist_href]
580
+ else:
581
+ iplist_hrefs.append(self.any_iplist_href)
582
+
583
+ for iplist_href in iplist_hrefs:
584
+ self.workload_to_iplist_query_manager.add_query(log_id=self.log_id,
585
+ src_href=log.get_source_workload_href(),
586
+ dst_href=iplist_href,
587
+ service_record=log.service_json)
588
+ else:
589
+ self.workload_to_workload_query_manager.add_query(log_id=self.log_id,
590
+ src_href=log.get_source_workload_href(),
591
+ dst_href=log.get_destination_workload_href(),
592
+ service_record=log.service_json)
593
+
594
+ def count_queries(self):
595
+ return len(self.iplist_to_workload_query_manager.queries)\
596
+ + len(self.workload_to_iplist_query_manager.queries)\
597
+ + len(self.workload_to_workload_query_manager.queries)
598
+
599
+ def count_real_queries(self):
600
+ _log_ids = {}
601
+ for query in self.iplist_to_workload_query_manager.queries.values():
602
+ for log_ids in query.services.service_index_to_log_ids.values():
603
+ for log_id in log_ids:
604
+ _log_ids[log_id] = True
605
+
606
+ for query in self.workload_to_iplist_query_manager.queries.values():
607
+ for log_ids in query.services.service_index_to_log_ids.values():
608
+ for log_id in log_ids:
609
+ _log_ids[log_id] = True
610
+
611
+ for query in self.workload_to_workload_query_manager.queries.values():
612
+ for log_ids in query.services.service_index_to_log_ids.values():
613
+ for log_id in log_ids:
614
+ _log_ids[log_id] = True
615
+
616
+ return len(_log_ids)
617
+
618
+ def _get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]:
619
+ decision = self.iplist_to_workload_query_manager.get_policy_decision_for_log_id(log_id)
620
+ if decision == 'allowed':
621
+ return decision
622
+
623
+ newDecision = self.workload_to_iplist_query_manager.get_policy_decision_for_log_id(log_id)
624
+ decision = newDecision or decision
625
+ if decision == 'allowed':
626
+ return decision
627
+
628
+ newDecision = self.workload_to_workload_query_manager.get_policy_decision_for_log_id(log_id) or decision
629
+ decision = newDecision or decision
630
+ if decision == 'allowed':
631
+ return decision
632
+
633
+ return decision
634
+
635
+ def apply_policy_decisions_to_logs(self):
636
+ for log, log_id in self.log_to_id.items():
637
+ decision = self._get_policy_decision_for_log_id(log_id)
638
+ if decision is None:
639
+ # if len(log.get_source_iplists_href()) == 0 and len(log.get_destination_iplists_href()) == 0 is None:
640
+ # # happens when source or destination is part of no IPList
641
+ # decision = 'blocked'
642
+ # else:
643
+ pylo.log.error(pylo.nice_json(log.raw_json))
644
+ raise pylo.PyloEx('No decision found for log_id {}'.format(log_id), log.raw_json)
645
+
646
+ log.set_draft_mode_policy_decision(decision)
647
+
648
+ def execute(self):
649
+ queries_per_batch = 100
650
+ self.iplist_to_workload_query_manager.execute(self.owner, queries_per_batch)
651
+ self.workload_to_iplist_query_manager.execute(self.owner, queries_per_batch)
652
+ self.workload_to_workload_query_manager.execute(self.owner, queries_per_batch)
653
+
654
+ self.apply_policy_decisions_to_logs()
655
+
656
+ class ExplorerFilterSetV1:
657
+ exclude_processes_emulate: Dict[str, str]
658
+ _exclude_processes: List[str]
659
+ _exclude_direct_services: List['pylo.DirectServiceInRule']
660
+ _time_from: Optional[datetime]
661
+ _time_to: Optional[datetime]
662
+ _policy_decision_filter: List[str]
663
+ _consumer_labels: Dict[str, Union['pylo.Label', 'pylo.LabelGroup']]
664
+ __filter_provider_ip_exclude: List[str]
665
+ __filter_consumer_ip_exclude: List[str]
666
+ __filter_provider_ip_include: List[str]
667
+ __filter_consumer_ip_include: List[str]
668
+
669
+ def __init__(self, max_results=10000):
670
+ self.__filter_consumer_ip_exclude = []
671
+ self.__filter_provider_ip_exclude = []
672
+ self.__filter_consumer_ip_include = []
673
+ self.__filter_provider_ip_include = []
674
+ self._consumer_labels: Dict[str, Union[pylo.Label, pylo.LabelGroup]] = {}
675
+ self._consumer_exclude_labels: Dict[str, Union[pylo.Label, pylo.LabelGroup]] = {}
676
+ self._provider_labels: Dict[str, Union[pylo.Label, pylo.LabelGroup]] = {}
677
+ self._provider_exclude_labels: Dict[str, Union[pylo.Label, pylo.LabelGroup]] = {}
678
+
679
+ self._consumer_workloads = {}
680
+ self._provider_workloads = {}
681
+
682
+ self._consumer_iplists = {}
683
+ self._consumer_iplists_exclude = {}
684
+ self._provider_iplists = {}
685
+ self._provider_iplists_exclude = {}
686
+
687
+
688
+ self.max_results = max_results
689
+ self._policy_decision_filter = []
690
+ self._time_from = None
691
+ self._time_to = None
692
+
693
+ self._include_direct_services = []
694
+
695
+ self._exclude_broadcast = False
696
+ self._exclude_multicast = False
697
+ self._exclude_direct_services = []
698
+ self.exclude_processes_emulate = {}
699
+ self._exclude_processes = []
700
+
701
+ @staticmethod
702
+ def __filter_prop_add_label(prop_dict, label_or_href):
703
+ """
704
+
705
+ @type prop_dict: dict
706
+ @type label_or_href: str|pylo.Label|pylo.LabelGroup
707
+ """
708
+ if isinstance(label_or_href, str):
709
+ prop_dict[label_or_href] = label_or_href
710
+ return
711
+ elif isinstance(label_or_href, pylo.Label):
712
+ prop_dict[label_or_href.href] = label_or_href
713
+ return
714
+ elif isinstance(label_or_href, pylo.LabelGroup):
715
+ # since 21.5 labelgroups can be included directly
716
+ # for nested_label in label_or_href.expand_nested_to_array():
717
+ # prop_dict[nested_label.href] = nested_label
718
+ prop_dict[label_or_href.href] = label_or_href
719
+ return
720
+ else:
721
+ raise pylo.PyloEx("Unsupported object type {}".format(type(label_or_href)))
722
+
723
+ def consumer_include_label(self, label_or_href):
724
+ """
725
+
726
+ @type label_or_href: str|pylo.Label|pylo.LabelGroup
727
+ """
728
+ self.__filter_prop_add_label(self._consumer_labels, label_or_href)
729
+
730
+ def consumer_exclude_label(self, label_or_href: Union[str, 'pylo.Label', 'pylo.LabelGroup']):
731
+ self.__filter_prop_add_label(self._consumer_exclude_labels, label_or_href)
732
+
733
+ def consumer_exclude_labels(self, labels: List[Union[str, 'pylo.Label', 'pylo.LabelGroup']]):
734
+ for label in labels:
735
+ self.consumer_exclude_label(label)
736
+
737
+ def consumer_include_workload(self, workload_or_href:Union[str, 'pylo.Workload']):
738
+ if isinstance(workload_or_href, str):
739
+ self._consumer_workloads[workload_or_href] = workload_or_href
740
+ return
741
+
742
+ if isinstance(workload_or_href, pylo.Workload):
743
+ self._consumer_workloads[workload_or_href.href] = workload_or_href.href
744
+ return
745
+
746
+ raise pylo.PyloEx("Unsupported object type {}".format(type(workload_or_href)))
747
+
748
+ def provider_include_workload(self, workload_or_href:Union[str, 'pylo.Workload']):
749
+ if isinstance(workload_or_href, str):
750
+ self._provider_workloads[workload_or_href] = workload_or_href
751
+ return
752
+
753
+ if isinstance(workload_or_href, pylo.Workload):
754
+ self._provider_workloads[workload_or_href.href] = workload_or_href.href
755
+ return
756
+
757
+ raise pylo.PyloEx("Unsupported object type {}".format(type(workload_or_href)))
758
+
759
+ def consumer_include_iplist(self, iplist_or_href: Union[str, 'pylo.IPList']):
760
+ if isinstance(iplist_or_href, str):
761
+ self._consumer_iplists[iplist_or_href] = iplist_or_href
762
+ return
763
+
764
+ if isinstance(iplist_or_href, pylo.IPList):
765
+ self._consumer_iplists[iplist_or_href.href] = iplist_or_href.href
766
+ return
767
+
768
+ raise pylo.PyloEx("Unsupported object type {}".format(type(iplist_or_href)))
769
+
770
+ def consumer_exclude_cidr(self, ipaddress: str):
771
+ self.__filter_consumer_ip_exclude.append(ipaddress)
772
+
773
+ def consumer_exclude_iplist(self, iplist_or_href: Union[str, 'pylo.IPList']):
774
+ if isinstance(iplist_or_href, str):
775
+ self._consumer_iplists_exclude[iplist_or_href] = iplist_or_href
776
+ return
777
+
778
+ if isinstance(iplist_or_href, pylo.IPList):
779
+ self._consumer_iplists_exclude[iplist_or_href.href] = iplist_or_href.href
780
+ return
781
+
782
+ raise pylo.PyloEx("Unsupported object type {}".format(type(iplist_or_href)))
783
+
784
+ def consumer_exclude_ip4map(self, map: 'pylo.IP4Map'):
785
+ for item in map.to_list_of_cidr_string():
786
+ self.consumer_exclude_cidr(item)
787
+
788
+ def consumer_include_cidr(self, ipaddress: str):
789
+ self.__filter_consumer_ip_include.append(ipaddress)
790
+
791
+ def consumer_include_ip4map(self, map: 'pylo.IP4Map'):
792
+ for item in map.to_list_of_cidr_string(skip_netmask_for_32=True):
793
+ self.consumer_include_cidr(item)
794
+
795
+ def provider_include_label(self, label_or_href):
796
+ """
797
+
798
+ @type label_or_href: str|pylo.Label|pylo.LabelGroup
799
+ """
800
+ self.__filter_prop_add_label(self._provider_labels, label_or_href)
801
+
802
+ def provider_include_iplist(self, iplist_or_href: Union[str, 'pylo.IPList']):
803
+ if isinstance(iplist_or_href, str):
804
+ self._provider_iplists[iplist_or_href] = iplist_or_href
805
+ return
806
+
807
+ if isinstance(iplist_or_href, pylo.IPList):
808
+ self._provider_iplists[iplist_or_href.href] = iplist_or_href.href
809
+ return
810
+
811
+ raise pylo.PyloEx("Unsupported object type {}".format(type(iplist_or_href)))
812
+
813
+ def provider_exclude_label(self, label_or_href: Union[str, 'pylo.Label', 'pylo.LabelGroup']):
814
+ self.__filter_prop_add_label(self._provider_exclude_labels, label_or_href)
815
+
816
+ def provider_exclude_labels(self, labels_or_hrefs: List[Union[str, 'pylo.Label', 'pylo.LabelGroup']]):
817
+ for label in labels_or_hrefs:
818
+ self.provider_exclude_label(label)
819
+
820
+ def provider_exclude_cidr(self, ipaddress: str):
821
+ self.__filter_provider_ip_exclude.append(ipaddress)
822
+
823
+ def provider_exclude_iplist(self, iplist_or_href: Union[str, 'pylo.IPList']):
824
+ if isinstance(iplist_or_href, str):
825
+ self._provider_iplists_exclude[iplist_or_href] = iplist_or_href
826
+ return
827
+
828
+ if isinstance(iplist_or_href, pylo.IPList):
829
+ self._provider_iplists_exclude[iplist_or_href.href] = iplist_or_href.href
830
+ return
831
+
832
+ raise pylo.PyloEx("Unsupported object type {}".format(type(iplist_or_href)))
833
+
834
+ def provider_exclude_ip4map(self, map: 'pylo.IP4Map'):
835
+ for item in map.to_list_of_cidr_string(skip_netmask_for_32=True):
836
+ self.provider_exclude_cidr(item)
837
+
838
+ def provider_include_cidr(self, ipaddress: str):
839
+ self.__filter_provider_ip_include.append(ipaddress)
840
+
841
+ def provider_include_ip4map(self, map: 'pylo.IP4Map'):
842
+ for item in map.to_list_of_cidr_string():
843
+ self.provider_include_cidr(item)
844
+
845
+ def service_include_add(self, service: Union['pylo.DirectServiceInRule',str]):
846
+ if isinstance(service, str):
847
+ self._include_direct_services.append(pylo.DirectServiceInRule.create_from_text(service))
848
+ return
849
+ self._include_direct_services.append(service)
850
+
851
+ def service_include_add_protocol(self, protocol: int):
852
+ self._include_direct_services.append(pylo.DirectServiceInRule(proto=protocol))
853
+
854
+ def service_include_add_protocol_tcp(self):
855
+ self._include_direct_services.append(pylo.DirectServiceInRule(proto=6))
856
+
857
+ def service_include_add_protocol_udp(self):
858
+ self._include_direct_services.append(pylo.DirectServiceInRule(proto=17))
859
+
860
+ def service_exclude_add(self, service: 'pylo.DirectServiceInRule'):
861
+ self._exclude_direct_services.append(service)
862
+
863
+ def service_exclude_add_protocol(self, protocol: int):
864
+ self._exclude_direct_services.append(pylo.DirectServiceInRule(proto=protocol))
865
+
866
+ def service_exclude_add_protocol_tcp(self):
867
+ self._exclude_direct_services.append(pylo.DirectServiceInRule(proto=6))
868
+
869
+ def service_exclude_add_protocol_udp(self):
870
+ self._exclude_direct_services.append(pylo.DirectServiceInRule(proto=17))
871
+
872
+ def process_exclude_add(self, process_name: str, emulate_on_client=False):
873
+ if emulate_on_client:
874
+ self.exclude_processes_emulate[process_name] = process_name
875
+ else:
876
+ self._exclude_processes.append(process_name)
877
+
878
+ def set_exclude_broadcast(self, exclude=True):
879
+ self._exclude_broadcast = exclude
880
+
881
+ def set_exclude_multicast(self, exclude=True):
882
+ self._exclude_multicast = exclude
883
+
884
+ def set_time_from(self, time: datetime):
885
+ self._time_from = time
886
+
887
+ def set_time_from_x_seconds_ago(self, seconds: int):
888
+ self._time_from = datetime.utcnow() - timedelta(seconds=seconds)
889
+
890
+ def set_time_from_x_days_ago(self, days: int):
891
+ return self.set_time_from_x_seconds_ago(days*60*60*24)
892
+
893
+ def set_max_results(self, max: int):
894
+ self.max_results = max
895
+
896
+ def set_time_to(self, time: datetime):
897
+ self._time_to = time
898
+
899
+ def set_time_to_x_seconds_ago(self, seconds: int):
900
+ self._time_to = datetime.utcnow() - timedelta(seconds=seconds)
901
+
902
+ def set_time_to_x_days_ago(self, days: int):
903
+ return self.set_time_to_x_seconds_ago(days*60*60*24)
904
+
905
+ def filter_on_policy_decision_unknown(self):
906
+ self._policy_decision_filter.append('unknown')
907
+
908
+ def filter_on_policy_decision_blocked(self):
909
+ self._policy_decision_filter.append('blocked')
910
+
911
+ def filter_on_policy_decision_potentially_blocked(self):
912
+ self._policy_decision_filter.append('potentially_blocked')
913
+
914
+ def filter_on_policy_decision_all_blocked(self):
915
+ self.filter_on_policy_decision_blocked()
916
+ self.filter_on_policy_decision_potentially_blocked()
917
+
918
+ def filter_on_policy_decision_allowed(self):
919
+ self._policy_decision_filter.append('allowed')
920
+
921
+ def generate_json_query(self):
922
+ # examples:
923
+ # {"sources":{"include":[[]],"exclude":[]}
924
+ # "destinations":{"include":[[]],"exclude":[]},
925
+ # "services":{"include":[],"exclude":[]},
926
+ # "sources_destinations_query_op":"and",
927
+ # "start_date":"2015-02-21T09:18:46.751Z","end_date":"2020-02-21T09:18:46.751Z",
928
+ # "policy_decisions":[],
929
+ # "max_results":10000}
930
+ #
931
+ filters = {
932
+ "sources": {"include": [], "exclude": []},
933
+ "destinations": {"include": [], "exclude": []},
934
+ "services": {"include": [], "exclude": []},
935
+ "sources_destinations_query_op": "and",
936
+ "policy_decisions": self._policy_decision_filter,
937
+ "max_results": self.max_results,
938
+ "query_name": "api call"
939
+ }
940
+
941
+ if self._exclude_broadcast:
942
+ filters['destinations']['exclude'].append({'transmission': 'broadcast'})
943
+
944
+ if self._exclude_multicast:
945
+ filters['destinations']['exclude'].append({'transmission': 'multicast'})
946
+
947
+ if self._time_from is not None:
948
+ filters["start_date"] = self._time_from.strftime('%Y-%m-%dT%H:%M:%SZ')
949
+ else:
950
+ filters["start_date"] = "2010-10-13T11:27:28.824Z",
951
+
952
+ if self._time_to is not None:
953
+ filters["end_date"] = self._time_to.strftime('%Y-%m-%dT%H:%M:%SZ')
954
+ else:
955
+ filters["end_date"] = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
956
+
957
+ if len(self._consumer_labels) > 0:
958
+ tmp = []
959
+ for label in self._consumer_labels.values():
960
+ if label.is_label():
961
+ tmp.append({'label': {'href': label.href}})
962
+ else:
963
+ tmp.append({'label_group': {'href': label.href}})
964
+ filters['sources']['include'].append(tmp)
965
+
966
+ if len(self._consumer_workloads) > 0:
967
+ tmp = []
968
+ for workload_href in self._consumer_workloads.keys():
969
+ tmp.append({'workload': {'href': workload_href}})
970
+ filters['sources']['include'].append(tmp)
971
+
972
+ if len(self._consumer_iplists) > 0:
973
+ tmp = []
974
+ for iplist_href in self._consumer_iplists.keys():
975
+ tmp.append({'ip_list': {'href': iplist_href}})
976
+ filters['sources']['include'].append(tmp)
977
+
978
+ if len(self.__filter_consumer_ip_include) > 0:
979
+ tmp = []
980
+ for ip_txt in self.__filter_consumer_ip_include:
981
+ tmp.append({'ip_address': ip_txt})
982
+ filters['sources']['include'].append(tmp)
983
+
984
+ if len(self._provider_labels) > 0:
985
+ tmp = []
986
+ for label in self._provider_labels.values():
987
+ if label.is_label():
988
+ tmp.append({'label': {'href': label.href}})
989
+ else:
990
+ pass
991
+ tmp.append({'label_group': {'href': label.href}})
992
+ filters['destinations']['include'].append(tmp)
993
+
994
+ if len(self._provider_workloads) > 0:
995
+ tmp = []
996
+ for workload_href in self._provider_workloads.keys():
997
+ tmp.append({'workload': {'href': workload_href}})
998
+ filters['destinations']['include'].append(tmp)
999
+
1000
+ if len(self._provider_iplists) > 0:
1001
+ tmp = []
1002
+ for iplist_href in self._provider_iplists.keys():
1003
+ tmp.append({'ip_list': {'href': iplist_href}})
1004
+ filters['destinations']['include'].append(tmp)
1005
+
1006
+ if len(self.__filter_provider_ip_include) > 0:
1007
+ tmp = []
1008
+ for ip_txt in self.__filter_provider_ip_include:
1009
+ tmp.append({'ip_address': ip_txt})
1010
+ filters['destinations']['include'].append(tmp)
1011
+
1012
+ consumer_exclude_json = []
1013
+ if len(self._consumer_exclude_labels) > 0:
1014
+ for label_href in self._consumer_exclude_labels.keys():
1015
+ filters['sources']['exclude'].append({'label': {'href': label_href}})
1016
+
1017
+ if len(self._consumer_iplists_exclude) > 0:
1018
+ for iplist_href in self._consumer_iplists_exclude.keys():
1019
+ filters['sources']['exclude'].append({'ip_list': {'href': iplist_href}})
1020
+
1021
+ if len(self.__filter_consumer_ip_exclude) > 0:
1022
+ for ipaddress in self.__filter_consumer_ip_exclude:
1023
+ filters['sources']['exclude'].append({'ip_address': ipaddress})
1024
+
1025
+ provider_exclude_json = []
1026
+ if len(self._provider_exclude_labels) > 0:
1027
+ for label_href in self._provider_exclude_labels.keys():
1028
+ filters['destinations']['exclude'].append({'label': {'href': label_href}})
1029
+
1030
+ if len(self._provider_iplists_exclude) > 0:
1031
+ for iplist_href in self._provider_iplists_exclude.keys():
1032
+ filters['destinations']['exclude'].append({'ip_list': {'href': iplist_href}})
1033
+
1034
+ if len(self.__filter_provider_ip_exclude) > 0:
1035
+ for ipaddress in self.__filter_provider_ip_exclude:
1036
+ filters['destinations']['exclude'].append({'ip_address': ipaddress})
1037
+
1038
+ if len(self._include_direct_services) > 0:
1039
+ for service in self._include_direct_services:
1040
+ filters['services']['include'] .append(service.get_api_json())
1041
+
1042
+ if len(self._exclude_direct_services) > 0:
1043
+ for service in self._exclude_direct_services:
1044
+ filters['services']['exclude'].append(service.get_api_json())
1045
+
1046
+ if len(self._exclude_processes) > 0:
1047
+ for process in self._exclude_processes:
1048
+ filters['services']['exclude'].append({'process_name': process})
1049
+
1050
+ # print(filters)
1051
+ return filters
1052
+
1053
+
1054
+ class ExplorerQuery:
1055
+ def __init__(self, connector: APIConnector, max_results: int = 1500, max_running_time_seconds: int = 1800,
1056
+ check_for_update_interval_seconds: int = 10):
1057
+ self.api: APIConnector = connector
1058
+ self.filters = ExplorerFilterSetV1(max_results=max_results)
1059
+ self.results: Optional[ExplorerResultSetV1] = None
1060
+ self.max_running_time_seconds = max_running_time_seconds
1061
+ self.check_for_update_interval_seconds = check_for_update_interval_seconds
1062
+
1063
+
1064
+ def execute(self) -> ExplorerResultSetV1:
1065
+ """
1066
+ Execute the query and stores the results in the 'results' property.
1067
+ It will also return said results for convenience.
1068
+ :return:
1069
+ """
1070
+ self.results = self.api.explorer_search(self.filters, max_running_time_seconds=self.max_running_time_seconds,
1071
+ check_for_update_interval_seconds=self.check_for_update_interval_seconds)
1072
+ return self.results
1073
+
1074
+
1075
+
1076
+
1077
+