illumio-pylo 0.3.3__py3-none-any.whl → 0.3.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.
@@ -62,16 +62,16 @@ all_object_types: Dict[ObjectTypes, ObjectTypes] = {
62
62
  class APIConnector:
63
63
  """docstring for APIConnector."""
64
64
 
65
- def __init__(self, fqdn: str, port, apiuser: str, apikey: str, skip_ssl_cert_check=False, org_id=1, name='unnamed'):
65
+ def __init__(self, fqdn: str, port, api_user: str, api_key: str, skip_ssl_cert_check=False, org_id=1, name='unnamed'):
66
66
  self.name = name
67
67
  self.fqdn: str = fqdn
68
68
  if type(port) is int:
69
69
  port = str(port)
70
70
  self.port: int = port
71
- self._api_key: str = apikey
71
+ self._api_key: str = api_key
72
72
  self._decrypted_api_key: str = None
73
- self.api_user: str = apiuser
74
- self.orgID: int = org_id
73
+ self.api_user: str = api_user
74
+ self.org_id: int = org_id
75
75
  self.skipSSLCertCheck: bool = skip_ssl_cert_check
76
76
  self.version: Optional['pylo.SoftwareVersion'] = None
77
77
  self.version_string: str = "Not Defined"
@@ -148,7 +148,7 @@ class APIConnector:
148
148
  def _make_api_url(self, path: str = '', include_org_id=False) -> str:
149
149
  url = self._make_base_url('/api/v2')
150
150
  if include_org_id:
151
- url += '/orgs/' + str(self.orgID)
151
+ url += '/orgs/' + str(self.org_id)
152
152
  url += path
153
153
 
154
154
  return url
@@ -625,12 +625,14 @@ class APIConnector:
625
625
  return None
626
626
 
627
627
  def objects_ven_get(self,
628
- include_deleted=False,
629
- filter_by_ip: str = None,
630
- filter_by_label: Optional[WorkloadsGetQueryLabelFilterJsonStructure] = None,
631
- filter_by_name: str = None,
632
- max_results: int = None,
633
- async_mode=True) -> List[VenObjectJsonStructure]:
628
+ include_deleted=False,
629
+ filter_by_ip: str = None,
630
+ filter_by_label: Optional[WorkloadsGetQueryLabelFilterJsonStructure] = None,
631
+ filter_by_name: str = None,
632
+ max_results: int = None,
633
+ async_mode=True,
634
+ representation: Optional[Literal['ven_labels']] = None
635
+ ) -> List[VenObjectJsonStructure]:
634
636
  path = '/vens'
635
637
  data = {}
636
638
 
@@ -652,7 +654,6 @@ class APIConnector:
652
654
 
653
655
  return self.do_get_call(path=path, async_call=async_mode, params=data)
654
656
 
655
-
656
657
  def objects_workload_get(self,
657
658
  include_deleted=False,
658
659
  filter_by_ip: str = None,
@@ -935,18 +936,20 @@ class APIConnector:
935
936
 
936
937
  return self.do_get_call(path=path, async_call=False, include_org_id=False )
937
938
 
938
- def object_network_device_endpoint_create(self, network_device_href: str, name: str, endpoint_type: Literal['switch_port'], workloads_href: List[str]) -> List[NetworkDeviceEndpointObjectJsonStructure]:
939
+ def object_network_device_endpoint_create(self, network_device_href: str, name: str,
940
+ endpoint_type: Literal['switch_port'], workloads_href: List[str]) \
941
+ -> List[NetworkDeviceEndpointObjectJsonStructure]:
942
+
939
943
  path = '{}/network_endpoints'.format(network_device_href)
940
944
 
941
- worklaods_href_objects = []
945
+ workloads_href_objects = []
942
946
  for workload_href in workloads_href:
943
- worklaods_href_objects.append({'href': workload_href})
947
+ workloads_href_objects.append({'href': workload_href})
944
948
 
945
- data = { 'config': { 'name': name, 'endpoint_type': endpoint_type }, 'workloads': worklaods_href_objects}
949
+ data = {'config': {'name': name, 'endpoint_type': endpoint_type}, 'workloads': workloads_href_objects}
946
950
 
947
951
  return self.do_post_call(path=path, async_call=False, include_org_id=False, json_arguments=data, json_output_expected=True)
948
952
 
949
-
950
953
  def objects_ruleset_get(self, max_results: int = None, async_mode=True) -> List[RulesetObjectJsonStructure]:
951
954
  path = '/sec_policy/draft/rule_sets'
952
955
  data = {}
@@ -1069,7 +1072,7 @@ class APIConnector:
1069
1072
  'ingress_services': services_json
1070
1073
  }
1071
1074
 
1072
- path = ruleset_href+'/sec_rules'
1075
+ path = ruleset_href + '/sec_rules'
1073
1076
 
1074
1077
  return self.do_post_call(path, json_arguments=data, json_output_expected=True, include_org_id=False)
1075
1078
 
@@ -4,6 +4,7 @@ from typing import Dict, TypedDict, Union, List, Optional
4
4
  import json
5
5
  import os
6
6
  from cryptography.fernet import Fernet
7
+ from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
7
8
  from ..Exception import PyloEx
8
9
  from .. import log
9
10
 
@@ -122,7 +123,7 @@ def get_credentials_from_file(fqdn_or_profile_name: str = None,
122
123
 
123
124
  if fail_with_an_exception:
124
125
  raise PyloEx("No profile found in credential file '{}' with fqdn: {}".
125
- format(credential_file, fqdn_or_profile_name))
126
+ format(credential_file, fqdn_or_profile_name))
126
127
 
127
128
  return None
128
129
 
@@ -133,8 +134,8 @@ def list_potential_credential_files() -> List[str]:
133
134
  :return:
134
135
  """
135
136
  potential_credential_files = []
136
- if os.environ.get('Pylo_CREDENTIAL_FILE', None) is not None:
137
- potential_credential_files.append(os.environ.get('Pylo_CREDENTIAL_FILE'))
137
+ if os.environ.get('PYLO_CREDENTIAL_FILE', None) is not None:
138
+ potential_credential_files.append(os.environ.get('PYLO_CREDENTIAL_FILE'))
138
139
  potential_credential_files.append(os.path.expanduser("~/.pylo/credentials.json"))
139
140
  potential_credential_files.append(os.path.join(os.getcwd(), "credentials.json"))
140
141
 
@@ -153,7 +154,7 @@ def get_all_credentials() -> List[CredentialProfile]:
153
154
  return credentials
154
155
 
155
156
 
156
- def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, overwrite_existing_profile = False) -> str:
157
+ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, overwrite_existing_profile=False) -> str:
157
158
  """
158
159
  Create a credential in a file and return the full path to the file
159
160
  :param file_full_path:
@@ -173,7 +174,10 @@ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, ov
173
174
  for profile in credentials:
174
175
  if profile['name'].lower() == data['name'].lower():
175
176
  if overwrite_existing_profile:
176
- profile = data
177
+ # profile is a dict, remove of all its entries
178
+ for key in list(profile.keys()):
179
+ del profile[key]
180
+ profile.update(data)
177
181
  break
178
182
  else:
179
183
  raise PyloEx("Profile with name {} already exists in file {}".format(data['name'], file_full_path))
@@ -187,7 +191,7 @@ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, ov
187
191
  else:
188
192
  credentials = [credentials, data]
189
193
  else:
190
- credentials = [data]
194
+ credentials = [data]
191
195
 
192
196
  # write to the file
193
197
  with open(file_full_path, 'w') as f:
@@ -195,6 +199,7 @@ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, ov
195
199
 
196
200
  return file_full_path
197
201
 
202
+
198
203
  def create_credential_in_default_file(data: CredentialFileEntry) -> str:
199
204
  """
200
205
  Create a credential in the default credential file and return the full path to the file
@@ -206,32 +211,20 @@ def create_credential_in_default_file(data: CredentialFileEntry) -> str:
206
211
  return file_path
207
212
 
208
213
 
209
- def encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key: paramiko.AgentKey, api_key: str) -> str:
210
- def encrypt(raw: str, key: bytes) -> bytes:
211
- """
212
-
213
- :param raw:
214
- :param key:
215
- :return: base64 encoded encrypted string
216
- """
217
- f = Fernet(base64.urlsafe_b64encode(key))
218
- token = f.encrypt(bytes(raw, 'utf-8'))
219
- return token
220
-
221
-
222
- # generate a random 128bit key
223
- session_key_to_sign = os.urandom(32)
214
+ def encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(ssh_key: paramiko.AgentKey, api_key: str) -> str:
215
+ seed_key_to_be_signed = os.urandom(32)
216
+ signed_seed_key = ssh_key.sign_ssh_data(seed_key_to_be_signed)
217
+ encryption_key = sha256(signed_seed_key).digest()
224
218
 
225
- signed_message = ssh_key.sign_ssh_data(session_key_to_sign)
219
+ nonce = seed_key_to_be_signed[:12]
220
+ chacha20_object = ChaCha20Poly1305(encryption_key)
226
221
 
227
- # use SHA256 to hash the signed message and use it as final AES 256 key
228
- encryption_key = sha256(signed_message).digest()
229
- #print("Encryption key: {}".format(encryption_key.hex()))
230
- encrypted_text = encrypt(api_key, encryption_key)
222
+ encrypted_text = chacha20_object.encrypt(nonce, bytes(api_key, 'utf-8'), ssh_key.get_fingerprint())
231
223
 
232
- api_key = "$encrypted$:ssh-Fernet:{}:{}:{}".format(base64.urlsafe_b64encode(ssh_key.get_fingerprint()).decode('utf-8'),
233
- base64.urlsafe_b64encode(session_key_to_sign).decode('utf-8'),
234
- encrypted_text.decode('utf-8'))
224
+ api_key = "$encrypted$:ssh-ChaCha20Poly1305:{}:{}:{}".format(
225
+ base64.urlsafe_b64encode(ssh_key.get_fingerprint()).decode('utf-8'),
226
+ base64.urlsafe_b64encode(seed_key_to_be_signed).decode('utf-8'),
227
+ base64.urlsafe_b64encode(encrypted_text).decode('utf-8'))
235
228
 
236
229
  return api_key
237
230
 
@@ -251,36 +244,62 @@ def decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload: str)
251
244
  session_key = base64.urlsafe_b64decode(api_key_parts[3])
252
245
  encrypted_api_key = api_key_parts[4]
253
246
 
254
- # find the key in the agent
255
- keys = paramiko.Agent().get_keys()
256
- found_key = None
257
- for key in keys:
258
- if key.get_fingerprint() == fingerprint:
259
- found_key = key
260
- break
261
-
262
- if found_key is None:
247
+ ssh_key = find_ssh_key_from_fingerprint(fingerprint)
248
+ if ssh_key is None:
263
249
  raise PyloEx("No key found in the agent with fingerprint {}".format(fingerprint.hex()))
264
250
 
265
251
  # sign the session key
266
- signed_session_key = found_key.sign_ssh_data(session_key)
252
+ signed_session_key = ssh_key.sign_ssh_data(session_key)
267
253
  encryption_key = sha256(signed_session_key).digest()
268
- #print("Encryption key: {}".format(encryption_key.hex()))
269
- #print("Encrypted from KEY fingerprint: {}".format(fingerprint.hex()))
254
+ # print("Encryption key: {}".format(encryption_key.hex()))
255
+ # print("Encrypted from KEY fingerprint: {}".format(fingerprint.hex()))
270
256
 
271
257
  return decrypt(token_b64_encoded=encrypted_api_key,
272
258
  key=encryption_key
273
259
  )
274
260
 
261
+
262
+ def decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(encrypted_api_key_payload: str) -> str:
263
+ api_key_parts = encrypted_api_key_payload.split(":")
264
+ if len(api_key_parts) != 5:
265
+ raise PyloEx("Invalid encrypted API key format")
266
+
267
+ fingerprint = base64.urlsafe_b64decode(api_key_parts[2])
268
+ seed_key_to_be_signed = base64.urlsafe_b64decode(api_key_parts[3])
269
+ encrypted_api_key = base64.urlsafe_b64decode(api_key_parts[4])
270
+
271
+ ssh_key = find_ssh_key_from_fingerprint(fingerprint)
272
+ if ssh_key is None:
273
+ raise PyloEx("No key found in the agent with fingerprint {}".format(fingerprint.hex()))
274
+
275
+ signed_session_key = ssh_key.sign_ssh_data(seed_key_to_be_signed)
276
+ encryption_key = sha256(signed_session_key).digest()
277
+
278
+ chacha20_object = ChaCha20Poly1305(encryption_key)
279
+ nonce = seed_key_to_be_signed[:12]
280
+
281
+ return chacha20_object.decrypt(nonce, encrypted_api_key, ssh_key.get_fingerprint()).decode('utf-8')
282
+
283
+
275
284
  def decrypt_api_key(encrypted_api_key_payload: str) -> str:
276
285
  # detect the encryption method
277
286
  if not encrypted_api_key_payload.startswith("$encrypted$:"):
278
287
  raise PyloEx("Invalid encrypted API key format")
279
288
  if encrypted_api_key_payload.startswith("$encrypted$:ssh-Fernet:"):
280
289
  return decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload)
290
+ elif encrypted_api_key_payload.startswith("$encrypted$:ssh-ChaCha20Poly1305:"):
291
+ return decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(encrypted_api_key_payload)
281
292
 
282
293
  raise PyloEx("Unsupported encryption method: {}".format(encrypted_api_key_payload.split(":")[1]))
283
294
 
284
295
 
285
296
  def is_api_key_encrypted(encrypted_api_key_payload: str) -> bool:
286
- return encrypted_api_key_payload.startswith("$encrypted$:")
297
+ return encrypted_api_key_payload.startswith("$encrypted$:")
298
+
299
+
300
+ def find_ssh_key_from_fingerprint(fingerprint: bytes) -> Optional[paramiko.AgentKey]:
301
+ keys = paramiko.Agent().get_keys()
302
+ for key in keys:
303
+ if key.get_fingerprint() == fingerprint:
304
+ return key
305
+ return None
@@ -12,6 +12,9 @@ from typing import *
12
12
 
13
13
  class VENAgent(pylo.ReferenceTracker):
14
14
 
15
+ __slots__ = ['href', 'owner', 'workload', 'software_version', '_last_heartbeat', '_status_security_policy_sync_state',
16
+ '_status_security_policy_applied_at', '_status_rule_count', 'mode', 'raw_json']
17
+
15
18
  def __init__(self, href: str, owner: 'pylo.AgentStore', workload: 'pylo.Workload' = None):
16
19
  pylo.ReferenceTracker.__init__(self)
17
20
  self.href: str = href
illumio_pylo/IPList.py CHANGED
@@ -8,13 +8,7 @@ from .Helpers import *
8
8
 
9
9
  class IPList(pylo.ReferenceTracker):
10
10
 
11
- """
12
- :type owner: IPListStore
13
- :type description: str|None
14
- :type raw_entries: dict[str,str]
15
- """
16
- name: str
17
- href: str
11
+ __slots__ = ['owner', 'name', 'href', 'description', 'raw_json', 'raw_entries']
18
12
 
19
13
  def __init__(self, name: str, href: str, owner: 'pylo.IPListStore', description=None):
20
14
  """
illumio_pylo/IPMap.py CHANGED
@@ -20,6 +20,9 @@ for i in range(32):
20
20
 
21
21
 
22
22
  class IP4Map:
23
+
24
+ __slots__ = ['_entries']
25
+
23
26
  def __init__(self):
24
27
  self._entries = []
25
28
 
@@ -5,6 +5,8 @@ from .LabelStore import label_type_role, label_type_env, label_type_loc, label_t
5
5
 
6
6
  class LabelCommon:
7
7
 
8
+ __slots__ = ['owner', 'name', 'href', 'type']
9
+
8
10
  def __init__(self, name: str, href: str, label_type: str, owner: LabelStore):
9
11
  self.owner: LabelStore = owner
10
12
  self.name: str = name
@@ -8,6 +8,8 @@ from .API.JsonPayloadTypes import LabelGroupObjectJsonStructure
8
8
 
9
9
  class LabelGroup(pylo.ReferenceTracker, pylo.LabelCommon):
10
10
 
11
+ __slots__ = ['_members_by_href', 'raw_json']
12
+
11
13
  def __init__(self, name: str, href: str, label_type: str, owner):
12
14
  pylo.ReferenceTracker.__init__(self)
13
15
  pylo.LabelCommon.__init__(self, name, href, label_type, owner)
@@ -47,6 +47,8 @@ class LabelStore:
47
47
  result.append(label)
48
48
  return result
49
49
 
50
+ __slots__ = ['owner', '_items_by_href', 'label_types', 'label_types_as_set', 'label_resolution_cache']
51
+
50
52
  def __init__(self, owner: 'pylo.Organization'):
51
53
  self.owner: "pylo.Organization" = owner
52
54
  self._items_by_href: Dict[str, Union[pylo.Label, pylo.LabelGroup]] = {}
@@ -4,6 +4,8 @@ import illumio_pylo as pylo
4
4
 
5
5
  class LabeledObject:
6
6
 
7
+ __slots__ = ['_labels']
8
+
7
9
  def __init__(self):
8
10
  self._labels: Dict[str, 'pylo.Label'] = {}
9
11
 
@@ -9,6 +9,9 @@ from .API.CredentialsManager import get_credentials_from_file
9
9
 
10
10
  class Organization:
11
11
 
12
+ __slots__ = ['id', 'connector', 'LabelStore', 'IPListStore', 'WorkloadStore', 'VirtualServiceStore', 'AgentStore',
13
+ 'ServiceStore', 'RulesetStore', 'SecurityPrincipalStore', 'pce_version']
14
+
12
15
  def __init__(self, org_id):
13
16
  self.id: int = org_id
14
17
  self.connector: Optional['pylo.APIConnector'] = None
@@ -58,7 +61,7 @@ class Organization:
58
61
  """
59
62
  Credentials files will be looked for in the following order:
60
63
  1. The path provided in the credential_file argument
61
- 2. The path provided in the Pylo_CREDENTIAL_FILE environment variable
64
+ 2. The path provided in the PYLO_CREDENTIAL_FILE environment variable
62
65
  3. The path ~/.pylo/credentials.json
63
66
  4. Current working directory credentials.json
64
67
  :param fqdn_or_profile_name:
@@ -71,7 +74,7 @@ class Organization:
71
74
  credentials = get_credentials_from_file(fqdn_or_profile_name, credential_file)
72
75
 
73
76
  connector = pylo.APIConnector(fqdn=credentials.fqdn, port=credentials.port,
74
- apiuser=credentials.api_user, apikey=credentials.api_key,
77
+ api_user=credentials.api_user, api_key=credentials.api_key,
75
78
  org_id=credentials.org_id,
76
79
  skip_ssl_cert_check=not credentials.verify_ssl, name=fqdn_or_profile_name)
77
80
 
illumio_pylo/Rule.py CHANGED
@@ -28,6 +28,9 @@ class RuleApiUpdateStack:
28
28
 
29
29
  class Rule:
30
30
 
31
+ __slots__ = ['owner', 'description', 'services', 'providers', 'consumers', 'consuming_principals', 'href', 'enabled',
32
+ 'secure_connect', 'unscoped_consumers', 'stateless', 'machine_auth', 'raw_json', 'batch_update_stack']
33
+
31
34
  def __init__(self, owner: 'Ruleset'):
32
35
  self.owner: Ruleset = owner
33
36
  self.description: Optional[str] = None
@@ -123,6 +126,9 @@ class Rule:
123
126
 
124
127
 
125
128
  class RuleSecurityPrincipalContainer(pylo.Referencer):
129
+
130
+ __slots__ = ['owner', '_items']
131
+
126
132
  def __init__(self, owner: 'pylo.Rule'):
127
133
  Referencer.__init__(self)
128
134
  self.owner = owner
@@ -140,6 +146,9 @@ class RuleSecurityPrincipalContainer(pylo.Referencer):
140
146
 
141
147
 
142
148
  class DirectServiceInRule:
149
+
150
+ __slots__ = ['protocol', 'port', 'to_port']
151
+
143
152
  def __init__(self, proto: int, port: int = None, toport: int = None):
144
153
  self.protocol = proto
145
154
  self.port = port
@@ -245,6 +254,9 @@ class DirectServiceInRule:
245
254
 
246
255
 
247
256
  class RuleServiceContainer(pylo.Referencer):
257
+
258
+ __slots__ = ['owner', '_items', '_direct_services', '_cached_port_map']
259
+
248
260
  def __init__(self, owner: 'pylo.Rule'):
249
261
  Referencer.__init__(self)
250
262
  self.owner = owner
@@ -380,6 +392,9 @@ class RuleServiceContainer(pylo.Referencer):
380
392
 
381
393
 
382
394
  class RuleHostContainer(pylo.Referencer):
395
+
396
+ __slots__ = ['owner', '_items', 'name', '_hasAllWorkloads']
397
+
383
398
  def __init__(self, owner: 'pylo.Rule', name: str):
384
399
  Referencer.__init__(self)
385
400
  self.owner = owner
illumio_pylo/Ruleset.py CHANGED
@@ -10,6 +10,8 @@ ruleset_id_extraction_regex = re.compile(r"^/orgs/([0-9]+)/sec_policy/([0-9]+)?(
10
10
 
11
11
  class RulesetScope:
12
12
 
13
+ __slots__ = ['owner', 'scope_entries']
14
+
13
15
  def __init__(self, owner: 'pylo.Ruleset'):
14
16
  self.owner: 'pylo.Ruleset' = owner
15
17
  self.scope_entries: Dict['pylo.RulesetScopeEntry', 'pylo.RulesetScopeEntry'] = {}
@@ -39,6 +41,8 @@ class RulesetScope:
39
41
 
40
42
  class RulesetScopeEntry:
41
43
 
44
+ __slots__ = ['owner', '_labels']
45
+
42
46
  def __init__(self, owner: 'pylo.RulesetScope'):
43
47
  self.owner: pylo.RulesetScope = owner
44
48
  self._labels: Dict[str, Union['pylo.Label', 'pylo.LabelGroup']] = {}
@@ -144,6 +148,8 @@ class RulesetScopeEntry:
144
148
 
145
149
  class Ruleset:
146
150
 
151
+ __slots__ = ['owner', 'href', 'name', 'description', 'scopes', '_rules_by_href', '_rules', 'disabled']
152
+
147
153
  def __init__(self, owner: 'pylo.RulesetStore'):
148
154
  self.owner: 'pylo.RulesetStore' = owner
149
155
  self.href: Optional[str] = None
@@ -7,6 +7,8 @@ from .Helpers import nice_json
7
7
 
8
8
  class RulesetStore:
9
9
 
10
+ __slots__ = ['owner', '_items_by_href']
11
+
10
12
  def __init__(self, owner: 'pylo.Organization'):
11
13
  self.owner: pylo.Organization = owner
12
14
  self._items_by_href: Dict[str, 'pylo.Ruleset'] = {}
@@ -5,6 +5,9 @@ from illumio_pylo import log
5
5
 
6
6
 
7
7
  class SecurityPrincipal(pylo.ReferenceTracker):
8
+
9
+ __slots__ = ['owner', 'name', 'href', 'sid', 'deleted', 'raw_json']
10
+
8
11
  def __init__(self, name: str, href: str, owner: 'pylo.SecurityPrincipalStore'):
9
12
  pylo.ReferenceTracker.__init__(self)
10
13
  self.owner: 'pylo.SecurityPrincipalStore' = owner
illumio_pylo/Service.py CHANGED
@@ -6,6 +6,9 @@ from typing import *
6
6
 
7
7
 
8
8
  class PortMap:
9
+
10
+ __slots__ = ['_tcp_map', '_udp_map', '_protocol_map']
11
+
9
12
  def __init__(self):
10
13
  self._tcp_map: List[List[2]] = [] # [start, end]
11
14
  self._udp_map: List[List[2]] = [] # [start, end]
@@ -99,6 +102,9 @@ class PortMap:
99
102
 
100
103
 
101
104
  class ServiceEntry:
105
+
106
+ __slots__ = ['protocol', 'port', 'to_port', 'icmp_code', 'icmp_type']
107
+
102
108
  def __init__(self, protocol: int, port: int = None, to_port: Optional[int] = None, icmp_code: Optional[int] = None,
103
109
  icmp_type: Optional[int] = None):
104
110
  self.protocol = protocol
@@ -160,6 +166,8 @@ class ServiceEntry:
160
166
 
161
167
  class Service(pylo.ReferenceTracker):
162
168
 
169
+ __slots__ = ['name', 'href', 'owner', 'entries', 'description', 'processName', 'deleted', 'raw_json']
170
+
163
171
  def __init__(self, name: str, href: str, owner: 'pylo.ServiceStore'):
164
172
  pylo.ReferenceTracker.__init__(self)
165
173
 
@@ -6,9 +6,7 @@ version_regex = re.compile(r"^(?P<major>[0-9]+)\.(?P<middle>[0-9]+)\.(?P<minor>[
6
6
 
7
7
  class SoftwareVersion:
8
8
 
9
- """
10
- :type version_string: str
11
- """
9
+ __slots__ = ['version_string', 'is_unknown', 'major', 'middle', 'minor', 'build']
12
10
 
13
11
  def __init__(self, version_string: str):
14
12
  self.version_string = version_string
@@ -4,6 +4,9 @@ import illumio_pylo as pylo
4
4
 
5
5
 
6
6
  class VirtualService(pylo.ReferenceTracker):
7
+
8
+ __slots__ = ['owner', 'name', 'href', 'raw_json']
9
+
7
10
  def __init__(self, name: str, href: str, owner: 'pylo.VirtualServiceStore'):
8
11
  pylo.ReferenceTracker.__init__(self)
9
12
  self.owner = owner
@@ -6,6 +6,8 @@ from .API.JsonPayloadTypes import VirtualServiceObjectJsonStructure
6
6
 
7
7
  class VirtualServiceStore:
8
8
 
9
+ __slots__ = ['owner', 'items_by_href', 'itemsByName']
10
+
9
11
  def __init__(self, owner: 'pylo.Organization'):
10
12
  self.owner: 'pylo.Organization' = owner
11
13
  self.items_by_href: Dict[str, 'pylo.VirtualService'] = {}
illumio_pylo/Workload.py CHANGED
@@ -47,6 +47,9 @@ class WorkloadApiUpdateStack:
47
47
 
48
48
  class Workload(pylo.ReferenceTracker, pylo.Referencer, LabeledObject):
49
49
 
50
+ __slots__ = ['owner', 'name', 'href', 'forced_name', 'hostname', 'description', 'interfaces', 'online', 'os_id',
51
+ 'os_detail', 'ven_agent', 'unmanaged', 'temporary', 'deleted', 'raw_json', '_batch_update_stack']
52
+
50
53
  def __init__(self, name: str, href: str, owner: 'pylo.WorkloadStore'):
51
54
  ReferenceTracker.__init__(self)
52
55
  Referencer.__init__(self)
@@ -10,6 +10,8 @@ from .WorkloadStoreSubClasses import UnmanagedWorkloadDraft, UnmanagedWorkloadDr
10
10
 
11
11
  class WorkloadStore:
12
12
 
13
+ __slots__ = ['owner', 'itemsByHRef']
14
+
13
15
  def __init__(self, owner: 'Organization'):
14
16
  self.owner: Organization = owner
15
17
  self.itemsByHRef: Dict[str, Workload] = {}
@@ -66,6 +66,7 @@ class CreationTracker:
66
66
  workload: Optional[pylo.Workload] = None
67
67
  workload_href: Optional[str] = None
68
68
 
69
+
69
70
  class UnmanagedWorkloadDraftMultiCreatorManager:
70
71
  def __init__(self, owner: 'pylo.WorkloadStore'):
71
72
 
illumio_pylo/__init__.py CHANGED
@@ -1,7 +1,5 @@
1
- __version__ = "0.3.3"
1
+ __version__ = "0.3.5"
2
2
 
3
- import os
4
- import sys
5
3
  from typing import Callable
6
4
 
7
5
  from .tmp import *
@@ -43,7 +41,7 @@ def get_organization(fqdn: str, port: int, api_user: str, api_key: str,
43
41
  """
44
42
  Load an organization from the API with parameters provided as arguments.
45
43
  """
46
- api = APIConnector(fqdn=fqdn, port=port, apiuser=api_user, apikey=api_key, org_id=organization_id,
44
+ api = APIConnector(fqdn=fqdn, port=port, api_user=api_user, api_key=api_key, org_id=organization_id,
47
45
  skip_ssl_cert_check=not verify_ssl)
48
46
  org = Organization(1)
49
47
  org.load_from_api(api, include_deleted_workloads=include_deleted_workloads,
@@ -60,7 +58,7 @@ def get_organization_using_credential_file(fqdn_or_profile_name: str = None,
60
58
  """
61
59
  Credentials files will be looked for in the following order:
62
60
  1. The path provided in the credential_file argument
63
- 2. The path provided in the Pylo_CREDENTIAL_FILE environment variable
61
+ 2. The path provided in the PYLO_CREDENTIAL_FILE environment variable
64
62
  3. The path ~/.pylo/credentials.json
65
63
  4. Current working directory credentials.json
66
64
  :param fqdn_or_profile_name:
@@ -77,7 +75,6 @@ def get_organization_using_credential_file(fqdn_or_profile_name: str = None,
77
75
  callback_api_objects_downloaded=callback_api_objects_downloaded)
78
76
 
79
77
 
80
-
81
78
  ignoreWorkloadsWithSameName = True
82
79
 
83
80
  objectNotFound = object()
@@ -9,8 +9,9 @@ import paramiko
9
9
  import illumio_pylo as pylo
10
10
  import click
11
11
  from illumio_pylo.API.CredentialsManager import get_all_credentials, create_credential_in_file, CredentialFileEntry, \
12
- create_credential_in_default_file, encrypt_api_key_with_paramiko_ssh_key_fernet, decrypt_api_key_with_paramiko_ssh_key_fernet, \
13
- get_credentials_from_file
12
+ create_credential_in_default_file, \
13
+ get_credentials_from_file, encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305, \
14
+ decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305, decrypt_api_key_with_paramiko_ssh_key_fernet
14
15
 
15
16
  from illumio_pylo import log
16
17
  from . import Command
@@ -28,7 +29,6 @@ def fill_parser(parser: argparse.ArgumentParser):
28
29
  test_parser.add_argument('--name', required=False, type=str, default=None,
29
30
  help='Name of the credential profile to test')
30
31
 
31
-
32
32
  create_parser = sub_parser.add_parser('create', help='Create a new credential')
33
33
  create_parser.add_argument('--name', required=False, type=str, default=None,
34
34
  help='Name of the credential')
@@ -46,20 +46,18 @@ def fill_parser(parser: argparse.ArgumentParser):
46
46
 
47
47
  def __main(args, **kwargs):
48
48
  if args['sub_command'] == 'list':
49
+ table = PrettyTable(field_names=["Name", "URL", "API User", "Originating File"])
50
+ # all should be left justified
51
+ table.align = "l"
52
+
49
53
  credentials = get_all_credentials()
50
54
  # sort credentials by name
51
55
  credentials.sort(key=lambda x: x.name)
52
56
 
53
- # print credentials in a nice table
54
- table_template = " {:<19} {:<40} {:<22} {:<25}"
55
- print(table_template.format("Name", "URL", "API User", "Originating File"))
56
-
57
57
  for credential in credentials:
58
- print(table_template.format(credential.name,
59
- credential.fqdn + ':' + str(credential.port),
60
- credential.api_user,
61
- credential.originating_file)
62
- )
58
+ table.add_row([credential.name, credential.fqdn, credential.api_user, credential.originating_file])
59
+
60
+ print(table)
63
61
 
64
62
  elif args['sub_command'] == 'create':
65
63
 
@@ -136,10 +134,11 @@ def __main(args, **kwargs):
136
134
  selected_ssh_key.get_fingerprint().hex(),
137
135
  selected_ssh_key.comment))
138
136
  print(" * encrypting API key with selected key (you may be prompted by your SSH agent for confirmation or PIN code) ...", flush=True, end="")
139
- encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key=selected_ssh_key, api_key=api_key)
137
+ # encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key=selected_ssh_key, api_key=api_key)
138
+ encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(ssh_key=selected_ssh_key, api_key=api_key)
140
139
  print("OK!")
141
140
  print(" * trying to decrypt the encrypted API key...", flush=True, end="")
142
- decrypted_api_key = decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload=encrypted_api_key)
141
+ decrypted_api_key = decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(encrypted_api_key_payload=encrypted_api_key)
143
142
  if decrypted_api_key != api_key:
144
143
  raise pylo.PyloEx("Decrypted API key does not match original API key")
145
144
  print("OK!")
illumio_pylo/tmp.py CHANGED
@@ -37,14 +37,33 @@ def find_connector_or_die(obj) -> 'pylo.APIConnector':
37
37
  :param obj:
38
38
  :return:
39
39
  """
40
- connector = obj.__dict__.get('connector') # type: pylo.APIConnector
41
- if connector is None:
42
- owner = obj.__dict__.get('owner')
43
- if owner is None:
44
- raise Exception("Could not find a Connector object")
45
- return find_connector_or_die(owner)
46
-
47
- return connector
40
+
41
+ connector = None
42
+
43
+ # check if object has a __dict__ attribute
44
+ if not hasattr(obj, '__dict__'):
45
+ # check if it's in __slots__
46
+ if hasattr(obj, '__slots__'):
47
+ if 'connector' in obj.__slots__:
48
+ connector = obj.__getattribute__('connector')
49
+ if connector is not None:
50
+ return connector
51
+ raise Exception("Could not find a Connector object")
52
+ if 'owner' in obj.__slots__:
53
+ owner = obj.__getattribute__('owner')
54
+ if owner is None:
55
+ raise Exception("Could not find a Connector object")
56
+ return find_connector_or_die(owner)
57
+ raise Exception("Could not find a Connector object")
58
+ else:
59
+ connector = obj.__dict__.get('connector') # type: pylo.APIConnector
60
+ if connector is None:
61
+ owner = obj.__dict__.get('owner')
62
+ if owner is None:
63
+ raise Exception("Could not find a Connector object")
64
+ return find_connector_or_die(owner)
65
+
66
+ return connector
48
67
 
49
68
 
50
69
  class IDTranslationTable:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: illumio_pylo
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: A set of tools and library for working with Illumio PCE
5
5
  Home-page: https://github.com/cpainchaud/pylo
6
6
  Author: Christophe Painchaud
@@ -1,32 +1,32 @@
1
- illumio_pylo/AgentStore.py,sha256=O4dz9m0KM0TQPZvvEMoD_5pCkMvQ70YVDaWqbqqhR4k,5091
1
+ illumio_pylo/AgentStore.py,sha256=7xWpjGJHK5Xp69M-WzqcDeC1WMLCeMii1D_hh6xVqb4,5312
2
2
  illumio_pylo/Exception.py,sha256=3lxS-ANBaEvHAKhDb8UzNLj5IpQBmRHNs4YkHONmQjs,1033
3
- illumio_pylo/IPList.py,sha256=XljZM4AHjM59PoR0bPLoJDVjLFJGVjewF91GwXV29UY,4501
4
- illumio_pylo/IPMap.py,sha256=2xCU0BD6Zc5yWgemn6Q0jNgs0owzp7TCyh6sVRLMf5U,10232
3
+ illumio_pylo/IPList.py,sha256=XvvE__qMISOrfHxM18tuLCv_fVWe_d3eb1eck3cEFvQ,4443
4
+ illumio_pylo/IPMap.py,sha256=x8t4eeX0DDYRAoofjL7eeA9hkmQ6v7H0h7iRFHSye-w,10263
5
5
  illumio_pylo/Label.py,sha256=sn6qNFo8Etdl0lUYRoSp_VC0mJymuFJpQ99x9vAwKSY,835
6
- illumio_pylo/LabelCommon.py,sha256=2HzljD2xJSBjf4Ywxk8JpBQQfbiZILCMV_Mj_EATIGk,1500
7
- illumio_pylo/LabelGroup.py,sha256=bVXvONHwR44GkF-9S19Fs2cnc4g8IW42VjyKi7QXmvQ,2624
8
- illumio_pylo/LabelStore.py,sha256=_feA5HdrfnOgcWStBToesu1S2ymHQKEKEG2Ygcadh9g,19809
9
- illumio_pylo/LabeledObject.py,sha256=zXIFcHtuvgxhu93htxiWtHoJ_mMWfSSdOBRNlEiXej0,1991
10
- illumio_pylo/Organization.py,sha256=MeESA6HuU0HzzkIKbj1NW_wzkarq30ptsCiffD1lm2M,12379
6
+ illumio_pylo/LabelCommon.py,sha256=MKdhxKKz6CTrAzI9f9YjtU_gf8G2QVprInNR_vCQ7OA,1551
7
+ illumio_pylo/LabelGroup.py,sha256=ZPC3xBLJUEhStyBTMB3fTTcEi8Z4CDjHUwnq_T-8p5Y,2674
8
+ illumio_pylo/LabelStore.py,sha256=bZjfCs4EZkY4SE5yI37_kshn24-DVhh2tn4YqS965OE,19917
9
+ illumio_pylo/LabeledObject.py,sha256=MsXoe3olAntxIvwAzXaPeOrnJQ_lHXIXAFNsB0lNBAk,2020
10
+ illumio_pylo/Organization.py,sha256=4IvTgJ27kFndBvwsWhcfZxuJ0PZvHH7pFGH4CMP83lE,12591
11
11
  illumio_pylo/Query.py,sha256=lgLjst41ma3HMVkngvTjL7zSLjh80RoXYL5vS3PWO7Q,13330
12
12
  illumio_pylo/ReferenceTracker.py,sha256=HyY0NwZwOdAzSXJrs6i6dhB_kgn1tidZL5LFLLkPuSM,1070
13
- illumio_pylo/Rule.py,sha256=jPU0hj8BDv2t-keL3NCK6NEd-kYSRkjwtzdo1xWiC5E,26352
14
- illumio_pylo/Ruleset.py,sha256=G-YrxHRovECDV0TVOLOJyRbMtlgSNmqiq4jMwR3175A,11711
15
- illumio_pylo/RulesetStore.py,sha256=wJLAKi32y-YiI8NLWWa_Ykrn54AQDcLz3rRlvTGUToI,3379
16
- illumio_pylo/SecurityPrincipal.py,sha256=8c7VYirJvByjW4r8Vz4NYHXlGYawOVE6YHDpizSIIO4,2280
17
- illumio_pylo/Service.py,sha256=CKj5VHjkvy7YL18afHqgJl-Qole7s1NWoah3rWHm6Zw,8280
18
- illumio_pylo/SoftwareVersion.py,sha256=Wg8Mi7vcoL9JgFSRo3i5aiX_OkUIU3ahmgLUrzJ9JYw,4348
19
- illumio_pylo/VirtualService.py,sha256=KAKE4iWuNmOumGradR2vwZxZ_3iiZg4pBST5ixCZSng,561
20
- illumio_pylo/VirtualServiceStore.py,sha256=b6bcMixq0Vfv7WjQTQnFHGCv_Mld7sOfvGi4NtFAMQ4,3057
21
- illumio_pylo/Workload.py,sha256=OIrP2TVFpCjQdjMYPdHkZHcKRszZ2hPnj4uRhI6d8EI,19677
22
- illumio_pylo/WorkloadStore.py,sha256=08FKIk9fubsaHy_-m2a0Io5sO_V9jmTa40-L3vyemRc,10947
23
- illumio_pylo/WorkloadStoreSubClasses.py,sha256=tK7s-7s5wRf9SHv3T00EOzgv4gX8gPIM77KBubCzBuo,6092
24
- illumio_pylo/__init__.py,sha256=xFZtrDXJzFs2mvE4B3udeNXJnu2o953tYyqsHCGSX1g,4192
25
- illumio_pylo/tmp.py,sha256=7PIn11aYfoxed7tjG_I1iZmiacn4TxZPihs7qD7f4DI,3123
26
- illumio_pylo/API/APIConnector.py,sha256=ksStxXka8a5gATM6GKb7foMLZZtBRAleuWJI96ioFoI,60494
13
+ illumio_pylo/Rule.py,sha256=LUMNyHtbOWF207DSuD1Dy_X4Oo6eD_VQ1uQA3jqEMmE,26827
14
+ illumio_pylo/Ruleset.py,sha256=c3mPoibfYroEtV4njBRux3R33772l2z8SDJnZcA_Jhc,11901
15
+ illumio_pylo/RulesetStore.py,sha256=KgTjE-TXIbvzjxusadijpMKY2ySX3DZAwOk3e4GChmk,3424
16
+ illumio_pylo/SecurityPrincipal.py,sha256=gASMxmNFDjfbfqJp0igmLeRpi03XLzGjbL-Ric_RGW4,2354
17
+ illumio_pylo/Service.py,sha256=qyUWvYFtTpJzZMVkppvxnBFFbeQf9bow_K3OBFiEdZ4,8523
18
+ illumio_pylo/SoftwareVersion.py,sha256=H_5WM42ObUkVtuxVWak30KMbEuar567k33E6pb83Zbo,4388
19
+ illumio_pylo/VirtualService.py,sha256=K1GT8pzkMOYkD4ZEwDkdriLOAUFAr0oCYNErJAMy9Ck,617
20
+ illumio_pylo/VirtualServiceStore.py,sha256=MNTwo1cvteUuID6JniWUk5oRHQHGY4OwrWvFaRXDuuk,3116
21
+ illumio_pylo/Workload.py,sha256=9kZHawayQQ_L-OBzyuuDcViWSa7HzDKEfPtcSHMsInw,19910
22
+ illumio_pylo/WorkloadStore.py,sha256=3C6SMU0wRlet6C6UVbjkYNsTY7vkyK_ZwqM1dlCBpsQ,10989
23
+ illumio_pylo/WorkloadStoreSubClasses.py,sha256=4GBb5sXan38Y5OE7O6aAR-IZrZJar0mYE44FbCSb3_k,6093
24
+ illumio_pylo/__init__.py,sha256=GmWEv5NapzQB7NgvF1pnLwBlFy7ybFXSZCFkv88p4g4,4172
25
+ illumio_pylo/tmp.py,sha256=DYlm07YEP6Nm5qScByfTloGi7TGaN9WtklSqeVROPik,3913
26
+ illumio_pylo/API/APIConnector.py,sha256=GxINSxd_6QdH0FLfJyh2OIXwGNwkrnXkz-ioY0Nj_lc,60633
27
27
  illumio_pylo/API/AuditLog.py,sha256=p0mfjrE5S8qoJgA5LIP_XGFBP3iL86Nl6BQEmhMVrPA,1533
28
28
  illumio_pylo/API/ClusterHealth.py,sha256=GdMpVQrHUW4zLM-409GcPHM8H8b3LAppO37ZcUZyT_Q,5122
29
- illumio_pylo/API/CredentialsManager.py,sha256=gGx63cEm4tnf4xLrmP5LAlDuEGlRjfuvOqut3xUl8i8,11030
29
+ illumio_pylo/API/CredentialsManager.py,sha256=-7c9_2VBJ_7zttBd6aa9K8YZ1iZmuQGAURVAy2jPopQ,12166
30
30
  illumio_pylo/API/Explorer.py,sha256=fFAIF-67_uuKgJOP0eZPPJrOGuYmFl33GK75AyMjgJU,47590
31
31
  illumio_pylo/API/JsonPayloadTypes.py,sha256=9gql3-tn3cu1qmpOD_JcPCX5b594eOKDgVhTqHu6CsQ,7984
32
32
  illumio_pylo/API/RuleSearchQuery.py,sha256=O0-MsUXhwmywoO0G-GXnLq6kkVC9LgmxMZwqVKc_oJE,5325
@@ -38,7 +38,7 @@ illumio_pylo/cli/NativeParsers.py,sha256=nzDL54EV0J-Iz0P9EkeiPl6DWQBSbCu-MpEPRad
38
38
  illumio_pylo/cli/__init__.py,sha256=UuZ2KamgIpvfYE1FXilm_THHAvXimdUcvGb3Jrbjfhc,7737
39
39
  illumio_pylo/cli/__main__.py,sha256=ll1gK8k1YL_kPsImI7WVlw2sCyNyhocnuCqko6mGaYI,223
40
40
  illumio_pylo/cli/commands/__init__.py,sha256=yoVkXy-qBGiAAziWiayJdjcclx1WTayShXSPqHelcWA,1489
41
- illumio_pylo/cli/commands/credential_manager.py,sha256=nChEuE7jewCzVNH2dXn3VspsfPmplZO-TjXLt07h7MA,9613
41
+ illumio_pylo/cli/commands/credential_manager.py,sha256=YHu8xb2ejOwt6FVkz6kfeP7mhhL85Vc4yU818iyE_3A,9638
42
42
  illumio_pylo/cli/commands/iplist_analyzer.py,sha256=vOl6fNd0HrUKnKXtY1sj7jeyx2GtuDZENV7mF79O7yU,3714
43
43
  illumio_pylo/cli/commands/iplist_import_from_file.py,sha256=XvC-GlJyjA4dDPzfvGoBFtwelI9g_rQqGzgKgqMYcsI,8284
44
44
  illumio_pylo/cli/commands/ruleset_export.py,sha256=E64oYgGKI1Ry382DqV1gT4IlsLdd55QTqdInXlL9EPU,5896
@@ -65,8 +65,8 @@ illumio_pylo/utilities/resources/iplists-import-example.xlsx,sha256=VW-7CRr8NA2V
65
65
  illumio_pylo/utilities/resources/workload-exporter-filter-example.csv,sha256=cn5IA8AGEPjvS-EsPXA_GJ-LFsdF9t_44rSzFTCmAzE,36
66
66
  illumio_pylo/utilities/resources/workloads-import-example.csv,sha256=DEOGVikFjxQpMFFI0l0jb3hrxEEeZCpTGkmWkz6GUcY,91
67
67
  illumio_pylo/utilities/resources/workloads-import-example.xlsx,sha256=U8Ac2BZidA6NlvBFAVPHqeY5zmg3rjmIAXp5b3b1P5w,17101
68
- illumio_pylo-0.3.3.dist-info/LICENSE,sha256=WYmcYJG1QFgu1hfo7qrEkZ3Jhcz8NUWe6XUraZvlIFs,10172
69
- illumio_pylo-0.3.3.dist-info/METADATA,sha256=cXr1ZrhFl1rQTJgE_0IFxb1okrSPSS0mNeqVS1XmHrs,12224
70
- illumio_pylo-0.3.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
71
- illumio_pylo-0.3.3.dist-info/top_level.txt,sha256=c5cu_ZMuSuxjq48ih58Kc0Tr8-JdQtV8GrKJicvWNFE,13
72
- illumio_pylo-0.3.3.dist-info/RECORD,,
68
+ illumio_pylo-0.3.5.dist-info/LICENSE,sha256=WYmcYJG1QFgu1hfo7qrEkZ3Jhcz8NUWe6XUraZvlIFs,10172
69
+ illumio_pylo-0.3.5.dist-info/METADATA,sha256=NMRToIIoGNsxKDzjMrEuBXs9gxVwCfpVbYBlpHD9JmM,12224
70
+ illumio_pylo-0.3.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
71
+ illumio_pylo-0.3.5.dist-info/top_level.txt,sha256=c5cu_ZMuSuxjq48ih58Kc0Tr8-JdQtV8GrKJicvWNFE,13
72
+ illumio_pylo-0.3.5.dist-info/RECORD,,