zscaler-sdk-python 1.0.0__py2.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.
- zscaler/__init__.py +34 -0
- zscaler/cache/__init__.py +0 -0
- zscaler/cache/cache.py +105 -0
- zscaler/cache/no_op_cache.py +68 -0
- zscaler/cache/zscaler_cache.py +161 -0
- zscaler/constants.py +26 -0
- zscaler/errors/__init__.py +0 -0
- zscaler/errors/error.py +10 -0
- zscaler/errors/http_error.py +20 -0
- zscaler/errors/zscaler_api_error.py +24 -0
- zscaler/exceptions/__init__.py +1 -0
- zscaler/exceptions/exceptions.py +101 -0
- zscaler/logger.py +57 -0
- zscaler/ratelimiter/__init__.py +0 -0
- zscaler/ratelimiter/ratelimiter.py +39 -0
- zscaler/user_agent.py +23 -0
- zscaler/utils.py +577 -0
- zscaler/zia/__init__.py +657 -0
- zscaler/zia/activate.py +52 -0
- zscaler/zia/admin_and_role_management.py +344 -0
- zscaler/zia/apptotal.py +71 -0
- zscaler/zia/audit_logs.py +95 -0
- zscaler/zia/authentication_settings.py +98 -0
- zscaler/zia/client.py +88 -0
- zscaler/zia/cloud_apps.py +406 -0
- zscaler/zia/device_management.py +90 -0
- zscaler/zia/dlp.py +784 -0
- zscaler/zia/errors.py +37 -0
- zscaler/zia/firewall.py +1104 -0
- zscaler/zia/forwarding_control.py +271 -0
- zscaler/zia/isolation_profile.py +83 -0
- zscaler/zia/labels.py +180 -0
- zscaler/zia/locations.py +661 -0
- zscaler/zia/sandbox.py +180 -0
- zscaler/zia/security.py +236 -0
- zscaler/zia/ssl_inspection.py +175 -0
- zscaler/zia/traffic.py +853 -0
- zscaler/zia/url_categories.py +442 -0
- zscaler/zia/url_filtering.py +310 -0
- zscaler/zia/users.py +386 -0
- zscaler/zia/web_dlp.py +295 -0
- zscaler/zia/workload_groups.py +58 -0
- zscaler/zia/zpa_gateway.py +187 -0
- zscaler/zpa/__init__.py +683 -0
- zscaler/zpa/app_segments.py +331 -0
- zscaler/zpa/app_segments_inspection.py +311 -0
- zscaler/zpa/app_segments_pra.py +310 -0
- zscaler/zpa/certificates.py +234 -0
- zscaler/zpa/client.py +113 -0
- zscaler/zpa/cloud_connector_groups.py +75 -0
- zscaler/zpa/connectors.py +518 -0
- zscaler/zpa/emergency_access.py +178 -0
- zscaler/zpa/errors.py +37 -0
- zscaler/zpa/idp.py +83 -0
- zscaler/zpa/inspection.py +1012 -0
- zscaler/zpa/isolation_profile.py +85 -0
- zscaler/zpa/lss.py +568 -0
- zscaler/zpa/machine_groups.py +79 -0
- zscaler/zpa/policies.py +848 -0
- zscaler/zpa/posture_profiles.py +122 -0
- zscaler/zpa/privileged_remote_access.py +862 -0
- zscaler/zpa/provisioning.py +271 -0
- zscaler/zpa/saml_attributes.py +100 -0
- zscaler/zpa/scim_attributes.py +117 -0
- zscaler/zpa/scim_groups.py +146 -0
- zscaler/zpa/segment_groups.py +191 -0
- zscaler/zpa/server_groups.py +217 -0
- zscaler/zpa/servers.py +202 -0
- zscaler/zpa/service_edges.py +404 -0
- zscaler/zpa/trusted_networks.py +127 -0
- zscaler_sdk_python-1.0.0.dist-info/LICENSE.md +21 -0
- zscaler_sdk_python-1.0.0.dist-info/METADATA +59 -0
- zscaler_sdk_python-1.0.0.dist-info/RECORD +75 -0
- zscaler_sdk_python-1.0.0.dist-info/WHEEL +6 -0
- zscaler_sdk_python-1.0.0.dist-info/top_level.txt +1 -0
zscaler/zpa/policies.py
ADDED
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2023, Zscaler Inc.
|
|
4
|
+
#
|
|
5
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
# purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
# copyright notice and this permission notice appear in all copies.
|
|
8
|
+
#
|
|
9
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import functools
|
|
19
|
+
|
|
20
|
+
from box import Box, BoxList
|
|
21
|
+
from requests import Response
|
|
22
|
+
|
|
23
|
+
from zscaler.utils import add_id_groups, convert_keys, snake_to_camel
|
|
24
|
+
from zscaler.zpa.client import ZPAClient
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PolicySetsAPI:
|
|
28
|
+
def __init__(self, client: ZPAClient):
|
|
29
|
+
self.rest = client
|
|
30
|
+
|
|
31
|
+
POLICY_MAP = {
|
|
32
|
+
"access": "ACCESS_POLICY",
|
|
33
|
+
"timeout": "TIMEOUT_POLICY",
|
|
34
|
+
"client_forwarding": "CLIENT_FORWARDING_POLICY",
|
|
35
|
+
"isolation": "ISOLATION_POLICY",
|
|
36
|
+
"inspection": "INSPECTION_POLICY",
|
|
37
|
+
"siem": "SIEM_POLICY",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
reformat_params = [
|
|
41
|
+
("app_server_group_ids", "appServerGroups"),
|
|
42
|
+
("app_connector_group_ids", "appConnectorGroups"),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def _create_conditions(conditions: list):
|
|
47
|
+
"""
|
|
48
|
+
Creates a dict template for feeding conditions into the ZPA Policies API when adding or updating a policy.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
conditions (list): List of condition dicts or tuples.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
:obj:`dict`: The conditions template.
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
template = []
|
|
58
|
+
|
|
59
|
+
for condition in conditions:
|
|
60
|
+
if isinstance(condition, tuple) and len(condition) == 3:
|
|
61
|
+
# Previous tuple logic
|
|
62
|
+
operand = {
|
|
63
|
+
"operands": [
|
|
64
|
+
{
|
|
65
|
+
"objectType": condition[0].upper(),
|
|
66
|
+
"lhs": condition[1],
|
|
67
|
+
"rhs": condition[2],
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
template.append(operand)
|
|
72
|
+
elif isinstance(condition, dict):
|
|
73
|
+
# New dictionary logic based on Go code schema
|
|
74
|
+
condition_template = {}
|
|
75
|
+
|
|
76
|
+
# Extracting keys from the condition dictionary
|
|
77
|
+
for key in ["id", "negated", "operator"]:
|
|
78
|
+
if key in condition:
|
|
79
|
+
condition_template[key] = condition[key]
|
|
80
|
+
|
|
81
|
+
# Handling the operands
|
|
82
|
+
operands = condition.get("operands", [])
|
|
83
|
+
condition_template["operands"] = []
|
|
84
|
+
|
|
85
|
+
for operand in operands:
|
|
86
|
+
operand_template = {}
|
|
87
|
+
|
|
88
|
+
# Extracting keys from the operand dictionary
|
|
89
|
+
for operand_key in [
|
|
90
|
+
"id",
|
|
91
|
+
"idp_id",
|
|
92
|
+
"name",
|
|
93
|
+
"lhs",
|
|
94
|
+
"rhs",
|
|
95
|
+
"objectType",
|
|
96
|
+
]:
|
|
97
|
+
if operand_key in operand:
|
|
98
|
+
operand_template[operand_key] = operand[operand_key]
|
|
99
|
+
|
|
100
|
+
condition_template["operands"].append(operand_template)
|
|
101
|
+
|
|
102
|
+
template.append(condition_template)
|
|
103
|
+
|
|
104
|
+
return template
|
|
105
|
+
|
|
106
|
+
def get_policy(self, policy_type: str) -> Box:
|
|
107
|
+
"""
|
|
108
|
+
Returns the policy and rule sets for the given policy type.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
policy_type (str): The type of policy to be returned. Accepted values are:
|
|
112
|
+
|
|
113
|
+
| ``access`` - returns the Access Policy
|
|
114
|
+
| ``timeout`` - returns the Timeout Policy
|
|
115
|
+
| ``client_forwarding`` - returns the Client Forwarding Policy
|
|
116
|
+
| ``isolation`` - returns the Isolation Policy
|
|
117
|
+
| ``inspection`` - returns the Inspection Policy
|
|
118
|
+
| ``siem`` - returns the SIEM Policy
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
:obj:`Box`: The resource record of the specified policy type.
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
Request the specified Policy.
|
|
125
|
+
|
|
126
|
+
>>> pprint(zpa.policies.get_policy('access'))
|
|
127
|
+
|
|
128
|
+
"""
|
|
129
|
+
# Map the simplified policy_type name to the name expected by the Zscaler API
|
|
130
|
+
mapped_policy_type = self.POLICY_MAP.get(policy_type, None)
|
|
131
|
+
|
|
132
|
+
# If the user provided an incorrect name, raise an error
|
|
133
|
+
if not mapped_policy_type:
|
|
134
|
+
raise ValueError(
|
|
135
|
+
f"Incorrect policy type provided: {policy_type}\n "
|
|
136
|
+
f"Policy type must be 'access', 'timeout', 'client_forwarding' or 'siem'."
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return self.rest.get(f"policySet/policyType/{mapped_policy_type}")
|
|
140
|
+
|
|
141
|
+
def get_rule(self, policy_type: str, rule_id: str) -> Box:
|
|
142
|
+
"""
|
|
143
|
+
Returns the specified policy rule.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
policy_type (str): The type of policy to be returned. Accepted values are:
|
|
147
|
+
|
|
148
|
+
| ``access``
|
|
149
|
+
| ``timeout``
|
|
150
|
+
| ``client_forwarding``
|
|
151
|
+
| ``siem``
|
|
152
|
+
rule_id (str): The unique identifier for the policy rule.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
:obj:`Box`: The resource record for the requested rule.
|
|
156
|
+
|
|
157
|
+
Examples:
|
|
158
|
+
>>> policy_rule = zpa.policies.get_rule(policy_id='99999',
|
|
159
|
+
... rule_id='88888')
|
|
160
|
+
|
|
161
|
+
"""
|
|
162
|
+
# Get the policy id for the supplied policy_type
|
|
163
|
+
policy_id = self.get_policy(policy_type).id
|
|
164
|
+
|
|
165
|
+
return self.rest.get(f"policySet/{policy_id}/rule/{rule_id}")
|
|
166
|
+
|
|
167
|
+
def get_rule_by_name(self, policy_type: str, rule_name: str) -> Box:
|
|
168
|
+
"""
|
|
169
|
+
Returns the specified policy rule by its name.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
policy_type (str): The type of policy to be returned.
|
|
173
|
+
Accepted values are: ``access``, ``timeout``, ``client_forwarding``, ``siem``
|
|
174
|
+
rule_name (str): The name of the policy rule.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
:obj:`Box`: The resource record for the requested rule.
|
|
178
|
+
|
|
179
|
+
Examples:
|
|
180
|
+
>>> policy_rule = zpa.policies.get_rule_by_name(policy_type='access', rule_name='MyRule')
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
all_rules = self.list_rules(policy_type)
|
|
184
|
+
for rule in all_rules:
|
|
185
|
+
if rule.name == rule_name:
|
|
186
|
+
return rule
|
|
187
|
+
return None
|
|
188
|
+
|
|
189
|
+
def list_rules(self, policy_type: str, **kwargs) -> BoxList:
|
|
190
|
+
"""
|
|
191
|
+
Returns policy rules for a given policy type.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
policy_type (str):
|
|
195
|
+
The policy type. Accepted values are:
|
|
196
|
+
|
|
197
|
+
| ``access`` - returns Access Policy rules
|
|
198
|
+
| ``timeout`` - returns Timeout Policy rules
|
|
199
|
+
| ``client_forwarding`` - returns Client Forwarding Policy rules
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
:obj:`list`: A list of all policy rules that match the requested type.
|
|
203
|
+
|
|
204
|
+
Examples:
|
|
205
|
+
>>> for policy in zpa.policies.list_type('type')
|
|
206
|
+
... pprint(policy)
|
|
207
|
+
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
# Map the simplified policy_type name to the name expected by the Zscaler API
|
|
211
|
+
mapped_policy_type = self.POLICY_MAP.get(policy_type, None)
|
|
212
|
+
|
|
213
|
+
# If the user provided an incorrect name, raise an error
|
|
214
|
+
if not mapped_policy_type:
|
|
215
|
+
raise ValueError(
|
|
216
|
+
f"Incorrect policy type provided: {policy_type}\n "
|
|
217
|
+
f"Policy type must be 'access', 'timeout', 'client_forwarding' or 'siem'."
|
|
218
|
+
)
|
|
219
|
+
list, _ = self.rest.get_paginated_data(
|
|
220
|
+
path=f"policySet/rules/policyType/{mapped_policy_type}",
|
|
221
|
+
**kwargs,
|
|
222
|
+
api_version="v1",
|
|
223
|
+
)
|
|
224
|
+
return list
|
|
225
|
+
|
|
226
|
+
def delete_rule(self, policy_type: str, rule_id: str) -> int:
|
|
227
|
+
"""
|
|
228
|
+
Deletes the specified policy rule.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
policy_type (str):
|
|
232
|
+
The type of policy the rule belongs to. Accepted values are:
|
|
233
|
+
|
|
234
|
+
| ``access``
|
|
235
|
+
| ``timeout``
|
|
236
|
+
| ``client_forwarding``
|
|
237
|
+
| ``siem``
|
|
238
|
+
rule_id (str):
|
|
239
|
+
The unique identifier for the policy rule.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
:obj:`int`: The response code for the operation.
|
|
243
|
+
|
|
244
|
+
Examples:
|
|
245
|
+
>>> zpa.policies.delete_rule(policy_id='99999',
|
|
246
|
+
... rule_id='88888')
|
|
247
|
+
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
# Get policy id for specified policy type
|
|
251
|
+
policy_id = self.get_policy(policy_type).id
|
|
252
|
+
|
|
253
|
+
return self.rest.delete(f"policySet/{policy_id}/rule/{rule_id}").status_code
|
|
254
|
+
|
|
255
|
+
def add_access_rule(
|
|
256
|
+
self,
|
|
257
|
+
name: str,
|
|
258
|
+
action: str,
|
|
259
|
+
app_connector_group_ids: list = [],
|
|
260
|
+
app_server_group_ids: list = [],
|
|
261
|
+
**kwargs,
|
|
262
|
+
) -> Box:
|
|
263
|
+
"""
|
|
264
|
+
Add a new Access Policy rule.
|
|
265
|
+
|
|
266
|
+
See the `ZPA Access Policy API reference <https://help.zscaler.com/zpa/access-policy-use-cases>`_
|
|
267
|
+
for further detail on optional keyword parameter structures.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
name (str):
|
|
271
|
+
The name of the new rule.
|
|
272
|
+
action (str):
|
|
273
|
+
The action for the policy. Accepted values are:
|
|
274
|
+
|
|
275
|
+
| ``allow``
|
|
276
|
+
| ``deny``
|
|
277
|
+
**kwargs:
|
|
278
|
+
Optional keyword args.
|
|
279
|
+
|
|
280
|
+
Keyword Args:
|
|
281
|
+
conditions (list):
|
|
282
|
+
A list of conditional rule tuples. Tuples must follow the convention: `Object Type`, `LHS value`,
|
|
283
|
+
`RHS value`. If you are adding multiple values for the same object type then you will need
|
|
284
|
+
a new entry for each value.
|
|
285
|
+
E.g.
|
|
286
|
+
|
|
287
|
+
.. code-block:: python
|
|
288
|
+
|
|
289
|
+
[('app', 'id', '99999'),
|
|
290
|
+
('app', 'id', '88888'),
|
|
291
|
+
('app_group', 'id', '77777),
|
|
292
|
+
('client_type', 'zpn_client_type_exporter', 'zpn_client_type_zapp'),
|
|
293
|
+
('trusted_network', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx', True)]
|
|
294
|
+
custom_msg (str):
|
|
295
|
+
A custom message.
|
|
296
|
+
description (str):
|
|
297
|
+
A description for the rule.
|
|
298
|
+
app_connector_group_ids (:obj:`list` of :obj:`str`):
|
|
299
|
+
A list of application connector IDs that will be attached to the access policy rule.
|
|
300
|
+
app_server_group_ids (:obj:`list` of :obj:`str`):
|
|
301
|
+
A list of application server group IDs that will be attached to the access policy rule.
|
|
302
|
+
Returns:
|
|
303
|
+
:obj:`Box`: The resource record of the newly created access policy rule.
|
|
304
|
+
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
# Initialise the payload
|
|
308
|
+
payload = {
|
|
309
|
+
"name": name,
|
|
310
|
+
"action": action.upper(),
|
|
311
|
+
"conditions": self._create_conditions(kwargs.pop("conditions", [])),
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if app_connector_group_ids:
|
|
315
|
+
payload["appConnectorGroups"] = [
|
|
316
|
+
{"id": group_id} for group_id in app_connector_group_ids
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
if app_server_group_ids:
|
|
320
|
+
payload["appServerGroups"] = [
|
|
321
|
+
{"id": group_id} for group_id in app_server_group_ids
|
|
322
|
+
]
|
|
323
|
+
|
|
324
|
+
add_id_groups(self.reformat_params, kwargs, payload)
|
|
325
|
+
|
|
326
|
+
# Get the policy id of the provided policy type for the URL.
|
|
327
|
+
policy_id = self.get_policy("access").id
|
|
328
|
+
|
|
329
|
+
# Add optional parameters to payload
|
|
330
|
+
for key, value in kwargs.items():
|
|
331
|
+
payload[snake_to_camel(key)] = value
|
|
332
|
+
|
|
333
|
+
response = self.rest.post(f"policySet/{policy_id}/rule", json=payload)
|
|
334
|
+
if isinstance(response, Response):
|
|
335
|
+
# this is only true when the creation failed (status code is not 2xx)
|
|
336
|
+
status_code = response.status_code
|
|
337
|
+
# Handle error response
|
|
338
|
+
raise Exception(
|
|
339
|
+
f"API call failed with status {status_code}: {response.json()}"
|
|
340
|
+
)
|
|
341
|
+
return response
|
|
342
|
+
|
|
343
|
+
def add_timeout_rule(self, name: str, **kwargs) -> Box:
|
|
344
|
+
"""
|
|
345
|
+
Add a new Timeout Policy rule.
|
|
346
|
+
|
|
347
|
+
See the `ZPA Timeout Policy API reference <https://help.zscaler.com/zpa/timeout-policy-use-cases>`_
|
|
348
|
+
for further detail on optional keyword parameter structures.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
name (str):
|
|
352
|
+
The name of the new rule.
|
|
353
|
+
**kwargs:
|
|
354
|
+
Optional parameters.
|
|
355
|
+
|
|
356
|
+
Keyword Args:
|
|
357
|
+
conditions (list):
|
|
358
|
+
A list of conditional rule tuples. Tuples must follow the convention: `Object Type`, `LHS value`,
|
|
359
|
+
`RHS value`. If you are adding multiple values for the same object type then you will need
|
|
360
|
+
a new entry for each value.
|
|
361
|
+
E.g.
|
|
362
|
+
|
|
363
|
+
.. code-block:: python
|
|
364
|
+
|
|
365
|
+
[('app', 'id', '926196382959075416'),
|
|
366
|
+
('app', 'id', '926196382959075417'),
|
|
367
|
+
('app_group', 'id', '926196382959075332),
|
|
368
|
+
('client_type', 'zpn_client_type_exporter', 'zpn_client_type_zapp'),
|
|
369
|
+
('trusted_network', 'b15e4cad-fa6e-8182-9fc3-8125ee6a65e1', True)]
|
|
370
|
+
custom_msg (str):
|
|
371
|
+
A custom message.
|
|
372
|
+
description (str):
|
|
373
|
+
A description for the rule.
|
|
374
|
+
re_auth_idle_timeout (int):
|
|
375
|
+
The re-authentication idle timeout value in seconds.
|
|
376
|
+
re_auth_timeout (int):
|
|
377
|
+
The re-authentication timeout value in seconds.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
:obj:`Box`: The resource record of the newly created Timeout Policy rule.
|
|
381
|
+
|
|
382
|
+
"""
|
|
383
|
+
|
|
384
|
+
# Initialise the payload
|
|
385
|
+
payload = {
|
|
386
|
+
"name": name,
|
|
387
|
+
"action": "RE_AUTH",
|
|
388
|
+
"conditions": self._create_conditions(kwargs.pop("conditions", [])),
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
# Get the policy id of the provided policy type for the URL.
|
|
392
|
+
policy_id = self.get_policy("timeout").id
|
|
393
|
+
|
|
394
|
+
# Use specified timeouts or default to UI values
|
|
395
|
+
payload["reauthTimeout"] = kwargs.get("re_auth_timeout", 172800)
|
|
396
|
+
payload["reauthIdleTimeout"] = kwargs.get("re_auth_idle_timeout", 600)
|
|
397
|
+
|
|
398
|
+
# Add optional parameters to payload
|
|
399
|
+
for key, value in kwargs.items():
|
|
400
|
+
payload[snake_to_camel(key)] = value
|
|
401
|
+
|
|
402
|
+
response = self.rest.post(f"policySet/{policy_id}/rule", json=payload)
|
|
403
|
+
if isinstance(response, Response):
|
|
404
|
+
# this is only true when the creation failed (status code is not 2xx)
|
|
405
|
+
status_code = response.status_code
|
|
406
|
+
# Handle error response
|
|
407
|
+
raise Exception(
|
|
408
|
+
f"API call failed with status {status_code}: {response.json()}"
|
|
409
|
+
)
|
|
410
|
+
return response
|
|
411
|
+
|
|
412
|
+
def add_client_forwarding_rule(self, name: str, action: str, **kwargs) -> Box:
|
|
413
|
+
"""
|
|
414
|
+
Add a new Client Forwarding Policy rule.
|
|
415
|
+
|
|
416
|
+
See the
|
|
417
|
+
`ZPA Client Forwarding Policy API reference <https://help.zscaler.com/zpa/client-forwarding-policy-use-cases>`_
|
|
418
|
+
for further detail on optional keyword parameter structures.
|
|
419
|
+
|
|
420
|
+
Args:
|
|
421
|
+
name (str):
|
|
422
|
+
The name of the new rule.
|
|
423
|
+
action (str):
|
|
424
|
+
The action for the policy. Accepted values are:
|
|
425
|
+
|
|
426
|
+
| ``intercept``
|
|
427
|
+
| ``intercept_accessible``
|
|
428
|
+
| ``bypass``
|
|
429
|
+
**kwargs:
|
|
430
|
+
Optional keyword args.
|
|
431
|
+
|
|
432
|
+
Keyword Args:
|
|
433
|
+
conditions (list):
|
|
434
|
+
A list of conditional rule tuples. Tuples must follow the convention: `Object Type`, `LHS value`,
|
|
435
|
+
`RHS value`. If you are adding multiple values for the same object type then you will need
|
|
436
|
+
a new entry for each value.
|
|
437
|
+
E.g.
|
|
438
|
+
|
|
439
|
+
.. code-block:: python
|
|
440
|
+
|
|
441
|
+
[('app', 'id', '926196382959075416'),
|
|
442
|
+
('app', 'id', '926196382959075417'),
|
|
443
|
+
('app_group', 'id', '926196382959075332),
|
|
444
|
+
('client_type', 'zpn_client_type_exporter', 'zpn_client_type_zapp'),
|
|
445
|
+
('trusted_network', 'b15e4cad-fa6e-8182-9fc3-8125ee6a65e1', True)]
|
|
446
|
+
custom_msg (str):
|
|
447
|
+
A custom message.
|
|
448
|
+
description (str):
|
|
449
|
+
A description for the rule.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
:obj:`Box`: The resource record of the newly created Client Forwarding Policy rule.
|
|
453
|
+
|
|
454
|
+
"""
|
|
455
|
+
|
|
456
|
+
# Initialise the payload
|
|
457
|
+
payload = {
|
|
458
|
+
"name": name,
|
|
459
|
+
"action": action.upper(),
|
|
460
|
+
"conditions": self._create_conditions(kwargs.pop("conditions", [])),
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
# Get the policy id of the provided policy type for the URL.
|
|
464
|
+
policy_id = self.get_policy("client_forwarding").id
|
|
465
|
+
|
|
466
|
+
# Add optional parameters to payload
|
|
467
|
+
for key, value in kwargs.items():
|
|
468
|
+
payload[snake_to_camel(key)] = value
|
|
469
|
+
|
|
470
|
+
response = self.rest.post(f"policySet/{policy_id}/rule", json=payload)
|
|
471
|
+
if isinstance(response, Response):
|
|
472
|
+
# this is only true when the creation failed (status code is not 2xx)
|
|
473
|
+
status_code = response.status_code
|
|
474
|
+
# Handle error response
|
|
475
|
+
raise Exception(
|
|
476
|
+
f"API call failed with status {status_code}: {response.json()}"
|
|
477
|
+
)
|
|
478
|
+
return response
|
|
479
|
+
|
|
480
|
+
def add_isolation_rule(
|
|
481
|
+
self, name: str, action: str, zpn_isolation_profile_id: str, **kwargs
|
|
482
|
+
) -> Box:
|
|
483
|
+
"""
|
|
484
|
+
Add a new Isolation Policy rule.
|
|
485
|
+
|
|
486
|
+
See the
|
|
487
|
+
`ZPA Isolation Policy API reference <https://help.zscaler.com/zpa/configuring-isolation-policies-using-api>`_
|
|
488
|
+
for further detail on optional keyword parameter structures.
|
|
489
|
+
|
|
490
|
+
Args:
|
|
491
|
+
name (str):
|
|
492
|
+
The name of the new rule.
|
|
493
|
+
action (str):
|
|
494
|
+
The action for the policy. Accepted values are:
|
|
495
|
+
|
|
496
|
+
| ``isolate``
|
|
497
|
+
| ``bypass_isolate``
|
|
498
|
+
**kwargs:
|
|
499
|
+
Optional keyword args.
|
|
500
|
+
|
|
501
|
+
Keyword Args:
|
|
502
|
+
conditions (list):
|
|
503
|
+
A list of conditional rule tuples. Tuples must follow the convention: `Object Type`, `LHS value`,
|
|
504
|
+
`RHS value`. If you are adding multiple values for the same object type then you will need
|
|
505
|
+
a new entry for each value.
|
|
506
|
+
E.g.
|
|
507
|
+
|
|
508
|
+
.. code-block:: python
|
|
509
|
+
|
|
510
|
+
[('app', 'id', '926196382959075416'),
|
|
511
|
+
('app', 'id', '926196382959075417'),
|
|
512
|
+
('app_group', 'id', '926196382959075332),
|
|
513
|
+
('client_type', 'zpn_client_type_exporter')]
|
|
514
|
+
zpn_isolation_profile_id (str):
|
|
515
|
+
The isolation profile ID associated with the rule
|
|
516
|
+
description (str):
|
|
517
|
+
A description for the rule.
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
:obj:`Box`: The resource record of the newly created Client Isolation Policy rule.
|
|
521
|
+
|
|
522
|
+
"""
|
|
523
|
+
|
|
524
|
+
# Initialise the payload
|
|
525
|
+
payload = {
|
|
526
|
+
"name": name,
|
|
527
|
+
"action": action.upper(),
|
|
528
|
+
"zpnIsolationProfileId": zpn_isolation_profile_id,
|
|
529
|
+
"conditions": self._create_conditions(kwargs.pop("conditions", [])),
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
# Get the policy id of the provided policy type for the URL.
|
|
533
|
+
policy_id = self.get_policy("isolation").id
|
|
534
|
+
|
|
535
|
+
# Add optional parameters to payload
|
|
536
|
+
for key, value in kwargs.items():
|
|
537
|
+
payload[snake_to_camel(key)] = value
|
|
538
|
+
|
|
539
|
+
response = self.rest.post(f"policySet/{policy_id}/rule", json=payload)
|
|
540
|
+
if isinstance(response, Response):
|
|
541
|
+
# this is only true when the creation failed (status code is not 2xx)
|
|
542
|
+
status_code = response.status_code
|
|
543
|
+
# Handle error response
|
|
544
|
+
raise Exception(
|
|
545
|
+
f"API call failed with status {status_code}: {response.json()}"
|
|
546
|
+
)
|
|
547
|
+
return response
|
|
548
|
+
|
|
549
|
+
def add_app_protection_rule(
|
|
550
|
+
self, name: str, action: str, zpn_inspection_profile_id: str, **kwargs
|
|
551
|
+
) -> Box:
|
|
552
|
+
"""
|
|
553
|
+
Add a new AppProtection Policy rule.
|
|
554
|
+
|
|
555
|
+
See the
|
|
556
|
+
`ZPA AppProtection Policy API reference <https://help.zscaler.com/zpa/configuring-appprotection-policies-using-api>`_
|
|
557
|
+
for further detail on optional keyword parameter structures.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
name (str):
|
|
561
|
+
The name of the new rule.
|
|
562
|
+
action (str):
|
|
563
|
+
The action for the policy. Accepted values are:
|
|
564
|
+
|
|
565
|
+
| ``inspect``
|
|
566
|
+
| ``bypass_inspect``
|
|
567
|
+
**kwargs:
|
|
568
|
+
Optional keyword args.
|
|
569
|
+
|
|
570
|
+
Keyword Args:
|
|
571
|
+
conditions (list):
|
|
572
|
+
A list of conditional rule tuples. Tuples must follow the convention: `Object Type`, `LHS value`,
|
|
573
|
+
`RHS value`. If you are adding multiple values for the same object type then you will need
|
|
574
|
+
a new entry for each value.
|
|
575
|
+
E.g.
|
|
576
|
+
|
|
577
|
+
.. code-block:: python
|
|
578
|
+
|
|
579
|
+
[('app', 'id', '926196382959075416'),
|
|
580
|
+
('app', 'id', '926196382959075417'),
|
|
581
|
+
('app_group', 'id', '926196382959075332),
|
|
582
|
+
('client_type', 'zpn_client_type_exporter')]
|
|
583
|
+
zpn_inspection_profile_id (str):
|
|
584
|
+
The AppProtection profile ID associated with the rule
|
|
585
|
+
description (str):
|
|
586
|
+
A description for the rule.
|
|
587
|
+
|
|
588
|
+
Returns:
|
|
589
|
+
:obj:`Box`: The resource record of the newly created Client Inspection Policy rule.
|
|
590
|
+
|
|
591
|
+
"""
|
|
592
|
+
|
|
593
|
+
# Initialise the payload
|
|
594
|
+
payload = {
|
|
595
|
+
"name": name,
|
|
596
|
+
"action": action.upper(),
|
|
597
|
+
"zpnInspectionProfileId": zpn_inspection_profile_id,
|
|
598
|
+
"conditions": self._create_conditions(kwargs.pop("conditions", [])),
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
# Get the policy id of the provided policy type for the URL.
|
|
602
|
+
policy_id = self.get_policy("inspection").id
|
|
603
|
+
|
|
604
|
+
# Add optional parameters to payload
|
|
605
|
+
for key, value in kwargs.items():
|
|
606
|
+
payload[snake_to_camel(key)] = value
|
|
607
|
+
|
|
608
|
+
response = self.rest.post(f"policySet/{policy_id}/rule", json=payload)
|
|
609
|
+
if isinstance(response, Response):
|
|
610
|
+
# this is only true when the creation failed (status code is not 2xx)
|
|
611
|
+
status_code = response.status_code
|
|
612
|
+
# Handle error response
|
|
613
|
+
raise Exception(
|
|
614
|
+
f"API call failed with status {status_code}: {response.json()}"
|
|
615
|
+
)
|
|
616
|
+
return response
|
|
617
|
+
|
|
618
|
+
def update_rule(self, policy_type: str, rule_id: str, **kwargs) -> Box:
|
|
619
|
+
"""
|
|
620
|
+
Update an existing policy rule.
|
|
621
|
+
|
|
622
|
+
Ensure you are using the correct arguments for the policy type that you want to update.
|
|
623
|
+
|
|
624
|
+
Args:
|
|
625
|
+
policy_type (str):
|
|
626
|
+
The policy type. Accepted values are:
|
|
627
|
+
|
|
628
|
+
| ``access``
|
|
629
|
+
| ``timeout``
|
|
630
|
+
| ``client_forwarding``
|
|
631
|
+
rule_id (str):
|
|
632
|
+
The unique identifier for the rule to be updated.
|
|
633
|
+
**kwargs:
|
|
634
|
+
Optional keyword args.
|
|
635
|
+
|
|
636
|
+
Keyword Args:
|
|
637
|
+
action (str):
|
|
638
|
+
The action for the policy. Accepted values are:
|
|
639
|
+
|
|
640
|
+
| ``allow``
|
|
641
|
+
| ``deny``
|
|
642
|
+
| ``intercept``
|
|
643
|
+
| ``intercept_accessible``
|
|
644
|
+
| ``bypass``
|
|
645
|
+
conditions (list):
|
|
646
|
+
A list of conditional rule tuples. Tuples must follow the convention: `Object Type`, `LHS value`,
|
|
647
|
+
`RHS value`. If you are adding multiple values for the same object type then you will need
|
|
648
|
+
a new entry for each value.
|
|
649
|
+
E.g.
|
|
650
|
+
|
|
651
|
+
.. code-block:: python
|
|
652
|
+
|
|
653
|
+
[('app', 'id', '926196382959075416'),
|
|
654
|
+
('app', 'id', '926196382959075417'),
|
|
655
|
+
('app_group', 'id', '926196382959075332),
|
|
656
|
+
('client_type', 'zpn_client_type_exporter', 'zpn_client_type_zapp'),
|
|
657
|
+
('trusted_network', 'b15e4cad-fa6e-8182-9fc3-8125ee6a65e1', True)]
|
|
658
|
+
custom_msg (str):
|
|
659
|
+
A custom message.
|
|
660
|
+
description (str):
|
|
661
|
+
A description for the rule.
|
|
662
|
+
re_auth_idle_timeout (int):
|
|
663
|
+
The re-authentication idle timeout value in seconds.
|
|
664
|
+
re_auth_timeout (int):
|
|
665
|
+
The re-authentication timeout value in seconds.
|
|
666
|
+
|
|
667
|
+
Returns:
|
|
668
|
+
:obj:`Box`: The updated policy-rule resource record.
|
|
669
|
+
|
|
670
|
+
Examples:
|
|
671
|
+
Updates the name only for an Access Policy rule:
|
|
672
|
+
|
|
673
|
+
>>> zpa.policies.update_rule('access', '99999', name='new_rule_name')
|
|
674
|
+
|
|
675
|
+
Updates the action only for a Client Forwarding Policy rule:
|
|
676
|
+
|
|
677
|
+
>>> zpa.policies.update_rule('client_forwarding', '888888', action='BYPASS')
|
|
678
|
+
|
|
679
|
+
"""
|
|
680
|
+
# Get policy id for specified policy type
|
|
681
|
+
policy_id = self.get_policy(policy_type).id
|
|
682
|
+
|
|
683
|
+
payload = convert_keys(self.get_rule(policy_type, rule_id))
|
|
684
|
+
|
|
685
|
+
# Add optional parameters to payload
|
|
686
|
+
for key, value in kwargs.items():
|
|
687
|
+
if key == "conditions":
|
|
688
|
+
payload["conditions"] = self._create_conditions(value)
|
|
689
|
+
else:
|
|
690
|
+
payload[snake_to_camel(key)] = value
|
|
691
|
+
|
|
692
|
+
resp = self.rest.put(
|
|
693
|
+
f"policySet/{policy_id}/rule/{rule_id}", json=payload
|
|
694
|
+
).status_code
|
|
695
|
+
|
|
696
|
+
# Return the object if it was updated successfully
|
|
697
|
+
if not isinstance(resp, Response):
|
|
698
|
+
return self.get_rule(policy_type, rule_id)
|
|
699
|
+
|
|
700
|
+
def update_access_rule(
|
|
701
|
+
self,
|
|
702
|
+
policy_type: str,
|
|
703
|
+
rule_id: str,
|
|
704
|
+
app_connector_group_ids: list = None,
|
|
705
|
+
app_server_group_ids: list = None,
|
|
706
|
+
**kwargs,
|
|
707
|
+
) -> Box:
|
|
708
|
+
"""
|
|
709
|
+
Update an existing policy rule.
|
|
710
|
+
|
|
711
|
+
Ensure you are using the correct arguments for the policy type that you want to update.
|
|
712
|
+
|
|
713
|
+
Args:
|
|
714
|
+
policy_type (str):
|
|
715
|
+
...
|
|
716
|
+
rule_id (str):
|
|
717
|
+
...
|
|
718
|
+
**kwargs:
|
|
719
|
+
...
|
|
720
|
+
|
|
721
|
+
Keyword Args:
|
|
722
|
+
...
|
|
723
|
+
app_connector_group_ids (:obj:`list` of :obj:`str`):
|
|
724
|
+
A list of application connector IDs that will be attached to the access policy rule. Defaults to an empty list.
|
|
725
|
+
app_server_group_ids (:obj:`list` of :obj:`str`):
|
|
726
|
+
A list of server group IDs that will be attached to the access policy rule. Defaults to an empty list.
|
|
727
|
+
Returns:
|
|
728
|
+
:obj:`Box`: The updated policy-rule resource record.
|
|
729
|
+
|
|
730
|
+
Examples:
|
|
731
|
+
...
|
|
732
|
+
"""
|
|
733
|
+
# Handle default values for app_connector_group_ids and app_server_group_ids
|
|
734
|
+
app_connector_group_ids = app_connector_group_ids or []
|
|
735
|
+
app_server_group_ids = app_server_group_ids or []
|
|
736
|
+
|
|
737
|
+
# Get policy id for specified policy type
|
|
738
|
+
policy_id = self.get_policy(policy_type).id
|
|
739
|
+
|
|
740
|
+
payload = convert_keys(self.get_rule(policy_type, rule_id))
|
|
741
|
+
|
|
742
|
+
# Update kwargs with app_connector_group_ids and app_server_group_ids for processing with add_id_groups
|
|
743
|
+
kwargs["app_connector_group_ids"] = app_connector_group_ids
|
|
744
|
+
kwargs["app_server_group_ids"] = app_server_group_ids
|
|
745
|
+
|
|
746
|
+
add_id_groups(self.reformat_params, kwargs, payload)
|
|
747
|
+
|
|
748
|
+
# Add optional parameters to payload
|
|
749
|
+
for key, value in kwargs.items():
|
|
750
|
+
if key == "conditions":
|
|
751
|
+
payload["conditions"] = self._create_conditions(value)
|
|
752
|
+
else:
|
|
753
|
+
payload[snake_to_camel(key)] = value
|
|
754
|
+
|
|
755
|
+
resp = self.rest.put(
|
|
756
|
+
f"policySet/{policy_id}/rule/{rule_id}", json=payload
|
|
757
|
+
).status_code
|
|
758
|
+
|
|
759
|
+
# Return the object if it was updated successfully
|
|
760
|
+
if not isinstance(resp, Response):
|
|
761
|
+
return self.get_rule(policy_type, rule_id)
|
|
762
|
+
|
|
763
|
+
def reorder_rule(self, policy_type: str, rule_id: str, rule_order: str) -> Box:
|
|
764
|
+
"""
|
|
765
|
+
Change the order of an existing policy rule.
|
|
766
|
+
|
|
767
|
+
Args:
|
|
768
|
+
rule_id (str):
|
|
769
|
+
The unique id of the rule that will be reordered.
|
|
770
|
+
rule_order (str):
|
|
771
|
+
The new order for the rule.
|
|
772
|
+
policy_type (str):
|
|
773
|
+
The policy type. Accepted values are:
|
|
774
|
+
|
|
775
|
+
| ``access``
|
|
776
|
+
| ``timeout``
|
|
777
|
+
| ``client_forwarding``
|
|
778
|
+
|
|
779
|
+
Returns:
|
|
780
|
+
:obj:`Box`: The updated policy rule resource record.
|
|
781
|
+
|
|
782
|
+
Examples:
|
|
783
|
+
Updates the order for an existing policy rule:
|
|
784
|
+
|
|
785
|
+
>>> zpa.policies.reorder_rule(policy_type='access',
|
|
786
|
+
... rule_id='88888',
|
|
787
|
+
... rule_order='2')
|
|
788
|
+
|
|
789
|
+
"""
|
|
790
|
+
# Get policy id for specified policy type
|
|
791
|
+
policy_id = self.get_policy(policy_type).id
|
|
792
|
+
|
|
793
|
+
resp = self._put(
|
|
794
|
+
f"policySet/{policy_id}/rule/{rule_id}/reorder/{rule_order}"
|
|
795
|
+
).status_code
|
|
796
|
+
|
|
797
|
+
if resp == 204:
|
|
798
|
+
return self.get_rule(policy_type, rule_id)
|
|
799
|
+
|
|
800
|
+
def sort_key(self, rules_orders: dict[str, int]):
|
|
801
|
+
def key(a, b):
|
|
802
|
+
if a.id in rules_orders and b.id in rules_orders:
|
|
803
|
+
if rules_orders[a.id] < rules_orders[b.id]:
|
|
804
|
+
return -1
|
|
805
|
+
return 1
|
|
806
|
+
if a.id in rules_orders:
|
|
807
|
+
return -1
|
|
808
|
+
elif b.id in rules_orders:
|
|
809
|
+
return 1
|
|
810
|
+
|
|
811
|
+
if a.rule_order < b.rule_order:
|
|
812
|
+
return -1
|
|
813
|
+
return 1
|
|
814
|
+
|
|
815
|
+
return key
|
|
816
|
+
|
|
817
|
+
def bulk_reorder_rules(self, policy_type: str, rules_orders: dict[str, int]) -> Box:
|
|
818
|
+
"""
|
|
819
|
+
Bulk change the order of policy rules.
|
|
820
|
+
|
|
821
|
+
Args:
|
|
822
|
+
rules_orders (dict(rule_id=>order)):
|
|
823
|
+
A map of rule IDs and orders
|
|
824
|
+
policy_type (str):
|
|
825
|
+
The policy type. Accepted values are:
|
|
826
|
+
|
|
827
|
+
| ``access``
|
|
828
|
+
| ``timeout``
|
|
829
|
+
| ``client_forwarding``
|
|
830
|
+
|
|
831
|
+
"""
|
|
832
|
+
# Get policy id for specified policy type
|
|
833
|
+
policy_set = self.get_policy(policy_type).id
|
|
834
|
+
all = self.list_rules(policy_type)
|
|
835
|
+
all.sort(key=functools.cmp_to_key(self.sort_key(rules_orders=rules_orders)))
|
|
836
|
+
orderedRules = [r.id for r in all]
|
|
837
|
+
|
|
838
|
+
# Construct the URL pathx
|
|
839
|
+
path = f"policySet/{policy_set}/reorder"
|
|
840
|
+
|
|
841
|
+
# Create a new PUT request
|
|
842
|
+
resp = self.rest.put(path, json=orderedRules)
|
|
843
|
+
if resp.status_code <= 299:
|
|
844
|
+
# Return the updated rule information
|
|
845
|
+
return None
|
|
846
|
+
else:
|
|
847
|
+
# Handle the case when the request fails (modify as needed)
|
|
848
|
+
return resp
|