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
|
@@ -0,0 +1,331 @@
|
|
|
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
|
+
from box import Box, BoxList
|
|
18
|
+
from requests import Response
|
|
19
|
+
|
|
20
|
+
from zscaler.utils import (
|
|
21
|
+
add_id_groups,
|
|
22
|
+
convert_keys,
|
|
23
|
+
recursive_snake_to_camel,
|
|
24
|
+
snake_to_camel,
|
|
25
|
+
transform_clientless_apps,
|
|
26
|
+
)
|
|
27
|
+
from zscaler.zpa.client import ZPAClient
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ApplicationSegmentAPI:
|
|
31
|
+
reformat_params = [
|
|
32
|
+
("clientless_app_ids", "clientlessApps"),
|
|
33
|
+
("server_group_ids", "serverGroups"),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
def __init__(self, client: ZPAClient):
|
|
37
|
+
self.rest = client
|
|
38
|
+
|
|
39
|
+
def list_segments(self, **kwargs) -> BoxList:
|
|
40
|
+
"""
|
|
41
|
+
Retrieve all configured application segments.
|
|
42
|
+
|
|
43
|
+
Keyword Args:
|
|
44
|
+
**max_items (int):
|
|
45
|
+
The maximum number of items to request before stopping iteration.
|
|
46
|
+
**max_pages (int):
|
|
47
|
+
The maximum number of pages to request before stopping iteration.
|
|
48
|
+
**pagesize (int):
|
|
49
|
+
Specifies the page size. The default size is 20, but the maximum size is 500.
|
|
50
|
+
**page (int):
|
|
51
|
+
Specifies the page size. The default size is 20, but the maximum size is 500.
|
|
52
|
+
**search (str, optional):
|
|
53
|
+
The search string used to match against features and fields.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
:obj:`BoxList`: List of application segments.
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
>>> app_segments = zpa.app_segments.list_segments()
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
list, _ = self.rest.get_paginated_data(
|
|
63
|
+
path="/application", **kwargs, api_version="v1"
|
|
64
|
+
)
|
|
65
|
+
return list
|
|
66
|
+
|
|
67
|
+
def get_segment(self, segment_id: str) -> Box:
|
|
68
|
+
"""
|
|
69
|
+
Get information for an application segment.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
segment_id (str):
|
|
73
|
+
The unique identifier for the application segment.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
:obj:`Box`: The application segment resource record.
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
>>> app_segment = zpa.app_segments.details('99999')
|
|
80
|
+
|
|
81
|
+
"""
|
|
82
|
+
response = self.rest.get("/application/%s" % (segment_id))
|
|
83
|
+
if isinstance(response, Response):
|
|
84
|
+
status_code = response.status_code
|
|
85
|
+
if status_code != 200:
|
|
86
|
+
return None
|
|
87
|
+
return response
|
|
88
|
+
|
|
89
|
+
def get_segment_by_name(self, name):
|
|
90
|
+
apps = self.list_segments()
|
|
91
|
+
for app in apps:
|
|
92
|
+
if app.get("name") == name:
|
|
93
|
+
return app
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
def delete_segment(self, segment_id: str, force_delete: bool = False) -> int:
|
|
97
|
+
"""
|
|
98
|
+
Delete an application segment.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
force_delete (bool):
|
|
102
|
+
Setting this field to true deletes the mapping between Application Segment and Segment Group.
|
|
103
|
+
segment_id (str):
|
|
104
|
+
The unique identifier for the application segment.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
:obj:`int`: The operation response code.
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
Delete an Application Segment with an id of 99999.
|
|
111
|
+
|
|
112
|
+
>>> zpa.app_segments.delete('99999')
|
|
113
|
+
|
|
114
|
+
Force deletion of an Application Segment with an id of 88888.
|
|
115
|
+
|
|
116
|
+
>>> zpa.app_segments.delete('88888', force_delete=True)
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
query = ""
|
|
120
|
+
if force_delete:
|
|
121
|
+
query = "forceDelete=true"
|
|
122
|
+
response = self.rest.delete("/application/%s?%s" % (segment_id, query))
|
|
123
|
+
return response.status_code
|
|
124
|
+
|
|
125
|
+
def add_segment(
|
|
126
|
+
self,
|
|
127
|
+
name: str,
|
|
128
|
+
domain_names: list,
|
|
129
|
+
segment_group_id: str,
|
|
130
|
+
server_group_ids: list,
|
|
131
|
+
tcp_port_ranges: list = None,
|
|
132
|
+
udp_port_ranges: list = None,
|
|
133
|
+
**kwargs,
|
|
134
|
+
) -> Box:
|
|
135
|
+
"""
|
|
136
|
+
Create an application segment.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
name (str): Name of the application segment.
|
|
140
|
+
domain_names (list of str): Domain names or IP addresses for the segment.
|
|
141
|
+
segment_group_id (str): Unique identifier for the segment group.
|
|
142
|
+
server_group_ids (list of str): Server group IDs for this segment.
|
|
143
|
+
tcp_port_ranges (list of str, optional): TCP port range pairs (e.g., ['22', '22']).
|
|
144
|
+
udp_port_ranges (list of str, optional): UDP port range pairs (e.g., ['35000', '35000']).
|
|
145
|
+
|
|
146
|
+
Keyword Args:
|
|
147
|
+
bypass_type (str): Bypass type for the segment. Values: `ALWAYS`, `NEVER`, `ON_NET`.
|
|
148
|
+
clientless_app_ids (list): IDs for associated clientless apps.
|
|
149
|
+
config_space (str): Config space for the segment. Values: `DEFAULT`, `SIEM`.
|
|
150
|
+
default_idle_timeout (int): Default Idle Timeout for the segment.
|
|
151
|
+
default_max_age (int): Default Max Age for the segment.
|
|
152
|
+
description (str): Additional information about the segment.
|
|
153
|
+
double_encrypt (bool): If true, enables double encryption.
|
|
154
|
+
enabled (bool): If true, enables the application segment.
|
|
155
|
+
health_check_type (str): Health Check Type. Values: `DEFAULT`, `NONE`.
|
|
156
|
+
health_reporting (str): Health Reporting mode. Values: `NONE`, `ON_ACCESS`, `CONTINUOUS`.
|
|
157
|
+
ip_anchored (bool): If true, enables IP Anchoring.
|
|
158
|
+
is_cname_enabled (bool): If true, enables CNAMEs for the segment.
|
|
159
|
+
passive_health_enabled (bool): If true, enables Passive Health Checks.
|
|
160
|
+
icmp_access_type (str): Sets ICMP access type for ZPA clients.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
:obj:`Box`: The newly created application segment.
|
|
164
|
+
|
|
165
|
+
Examples:
|
|
166
|
+
Add a new application segment for example.com on ports 8080-8085:
|
|
167
|
+
|
|
168
|
+
>>> zpa.app_segments.add_segment('new_app_segment',
|
|
169
|
+
... domain_names=['example.com'],
|
|
170
|
+
... segment_group_id='99999',
|
|
171
|
+
... tcp_port_ranges=['8080', '8085'],
|
|
172
|
+
... server_group_ids=['99999', '88888'])
|
|
173
|
+
"""
|
|
174
|
+
# Initialise payload
|
|
175
|
+
payload = {
|
|
176
|
+
"name": name,
|
|
177
|
+
"domainNames": domain_names,
|
|
178
|
+
"tcpPortRanges": tcp_port_ranges,
|
|
179
|
+
"udpPortRanges": udp_port_ranges,
|
|
180
|
+
"segmentGroupId": segment_group_id,
|
|
181
|
+
"serverGroups": [{"id": group_id} for group_id in server_group_ids],
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# Handle clientless_app_ids separately
|
|
185
|
+
if "clientless_app_ids" in kwargs:
|
|
186
|
+
clientless_apps = kwargs.pop("clientless_app_ids")
|
|
187
|
+
payload["clientlessApps"] = transform_clientless_apps(clientless_apps)
|
|
188
|
+
|
|
189
|
+
# add_id_groups(self.reformat_params, kwargs, payload)
|
|
190
|
+
|
|
191
|
+
# # Add optional parameters to payload
|
|
192
|
+
# for key, value in kwargs.items():
|
|
193
|
+
# payload[snake_to_camel(key)] = value
|
|
194
|
+
add_id_groups(self.reformat_params, kwargs, payload)
|
|
195
|
+
for key, value in kwargs.items():
|
|
196
|
+
if value is not None:
|
|
197
|
+
payload[snake_to_camel(key)] = value
|
|
198
|
+
|
|
199
|
+
# Convert the entire payload's keys to camelCase before sending
|
|
200
|
+
camel_payload = recursive_snake_to_camel(payload)
|
|
201
|
+
for key, value in kwargs.items():
|
|
202
|
+
if value is not None:
|
|
203
|
+
camel_payload[snake_to_camel(key)] = value
|
|
204
|
+
|
|
205
|
+
response = self.rest.post("application", json=payload)
|
|
206
|
+
if isinstance(response, Response):
|
|
207
|
+
# this is only true when the creation failed (status code is not 2xx)
|
|
208
|
+
status_code = response.status_code
|
|
209
|
+
# Handle error response
|
|
210
|
+
raise Exception(
|
|
211
|
+
f"API call failed with status {status_code}: {response.json()}"
|
|
212
|
+
)
|
|
213
|
+
return response
|
|
214
|
+
|
|
215
|
+
def update_segment(self, segment_id: str, **kwargs) -> Box:
|
|
216
|
+
"""
|
|
217
|
+
Update an application segment.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
segment_id (str):
|
|
221
|
+
The unique identifier for the application segment.
|
|
222
|
+
**kwargs:
|
|
223
|
+
Optional params.
|
|
224
|
+
|
|
225
|
+
Keyword Args:
|
|
226
|
+
bypass_type (str):
|
|
227
|
+
The type of bypass for the Application Segment. Accepted values are `ALWAYS`, `NEVER` and `ON_NET`.
|
|
228
|
+
clientless_app_ids (:obj:`list`):
|
|
229
|
+
List of unique IDs for clientless apps to associate with this Application Segment.
|
|
230
|
+
config_space (str):
|
|
231
|
+
The config space for this Application Segment. Accepted values are `DEFAULT` and `SIEM`.
|
|
232
|
+
default_idle_timeout (int):
|
|
233
|
+
The Default Idle Timeout for the Application Segment.
|
|
234
|
+
default_max_age (int):
|
|
235
|
+
The Default Max Age for the Application Segment.
|
|
236
|
+
description (str):
|
|
237
|
+
Additional information about this Application Segment.
|
|
238
|
+
domain_names (:obj:`list` of :obj:`str`):
|
|
239
|
+
List of domain names or IP addresses for the application segment.
|
|
240
|
+
double_encrypt (bool):
|
|
241
|
+
Double Encrypt the Application Segment micro-tunnel.
|
|
242
|
+
enabled (bool):
|
|
243
|
+
Enable the Application Segment.
|
|
244
|
+
health_check_type (str):
|
|
245
|
+
Set the Health Check Type. Accepted values are `DEFAULT` and `NONE`.
|
|
246
|
+
health_reporting (str):
|
|
247
|
+
Set the Health Reporting. Accepted values are `NONE`, `ON_ACCESS` and `CONTINUOUS`.
|
|
248
|
+
ip_anchored (bool):
|
|
249
|
+
Enable IP Anchoring for this Application Segment.
|
|
250
|
+
is_cname_enabled (bool):
|
|
251
|
+
Enable CNAMEs for this Application Segment.
|
|
252
|
+
name (str):
|
|
253
|
+
The name of the application segment.
|
|
254
|
+
passive_health_enabled (bool):
|
|
255
|
+
Enable Passive Health Checks for this Application Segment.
|
|
256
|
+
segment_group_id (str):
|
|
257
|
+
The unique identifer for the segment group this application segment belongs to.
|
|
258
|
+
server_group_ids (:obj:`list` of :obj:`str`):
|
|
259
|
+
The list of server group IDs that belong to this application segment.
|
|
260
|
+
tcp_port_ranges (:obj:`list` of :obj:`tuple`):
|
|
261
|
+
List of TCP port ranges specified as a tuple pair, e.g. for ports 21-23, 8080-8085 and 443:
|
|
262
|
+
[(21, 23), (8080, 8085), (443, 443)]
|
|
263
|
+
udp_port_ranges (:obj:`list` of :obj:`tuple`):
|
|
264
|
+
List of UDP port ranges specified as a tuple pair, e.g. for ports 34000-35000 and 36000:
|
|
265
|
+
[(34000, 35000), (36000, 36000)]
|
|
266
|
+
icmp_access_type (str): Sets ICMP access type for ZPA clients.
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
:obj:`Box`: The updated application segment resource record.
|
|
270
|
+
|
|
271
|
+
Examples:
|
|
272
|
+
Rename the application segment for example.com.
|
|
273
|
+
|
|
274
|
+
>>> zpa.app_segments.update('99999',
|
|
275
|
+
... name='new_app_name',
|
|
276
|
+
|
|
277
|
+
"""
|
|
278
|
+
# Set payload to value of existing record and convert nested dict keys.
|
|
279
|
+
payload = convert_keys(self.get_segment(segment_id))
|
|
280
|
+
|
|
281
|
+
if kwargs.get("tcp_port_ranges"):
|
|
282
|
+
payload["tcpPortRange"] = [
|
|
283
|
+
{"from": ports[0], "to": ports[1]}
|
|
284
|
+
for ports in kwargs.pop("tcp_port_ranges")
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
if kwargs.get("udp_port_ranges"):
|
|
288
|
+
payload["udpPortRange"] = [
|
|
289
|
+
{"from": ports[0], "to": ports[1]}
|
|
290
|
+
for ports in kwargs.pop("udp_port_ranges")
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
# Handle the clientless_app_ids directly within this function without a separate helper
|
|
294
|
+
if kwargs.get("clientless_app_ids"):
|
|
295
|
+
# Here you would implement any necessary formatting directly
|
|
296
|
+
formatted_clientless_apps = [
|
|
297
|
+
{"id": app.get("id")} for app in kwargs.pop("clientless_app_ids")
|
|
298
|
+
]
|
|
299
|
+
payload[
|
|
300
|
+
"clientlessApps"
|
|
301
|
+
] = formatted_clientless_apps # use the correct key expected by your API
|
|
302
|
+
|
|
303
|
+
# Convert other keys in payload
|
|
304
|
+
add_id_groups(self.reformat_params, kwargs, payload)
|
|
305
|
+
|
|
306
|
+
# Add remaining optional parameters to payload
|
|
307
|
+
for key, value in kwargs.items():
|
|
308
|
+
payload[snake_to_camel(key)] = value
|
|
309
|
+
|
|
310
|
+
resp = self.rest.put(f"application/{segment_id}", json=payload).status_code
|
|
311
|
+
|
|
312
|
+
# Return the object if it was updated successfully
|
|
313
|
+
if not isinstance(resp, Response):
|
|
314
|
+
return self.get_segment(segment_id)
|
|
315
|
+
|
|
316
|
+
def detach_from_segment_group(self, app_id, seg_group_id):
|
|
317
|
+
seg_group = self.rest.get("/segmentGroup/%s" % (seg_group_id))
|
|
318
|
+
if isinstance(seg_group, Response):
|
|
319
|
+
status_code = seg_group.status_code
|
|
320
|
+
if status_code > 299:
|
|
321
|
+
return None
|
|
322
|
+
apps = seg_group.get("applications", [])
|
|
323
|
+
addaptedApps = []
|
|
324
|
+
for app in apps:
|
|
325
|
+
if app.get("id") != app_id:
|
|
326
|
+
addaptedApps.append(app)
|
|
327
|
+
seg_group["applications"] = addaptedApps
|
|
328
|
+
self.rest.put(
|
|
329
|
+
"/segmentGroup/%s" % (seg_group_id),
|
|
330
|
+
json=seg_group,
|
|
331
|
+
)
|
|
@@ -0,0 +1,311 @@
|
|
|
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
|
+
from box import Box, BoxList
|
|
19
|
+
from requests import Response
|
|
20
|
+
|
|
21
|
+
from zscaler.utils import (
|
|
22
|
+
add_id_groups,
|
|
23
|
+
convert_keys,
|
|
24
|
+
recursive_snake_to_camel,
|
|
25
|
+
snake_to_camel,
|
|
26
|
+
)
|
|
27
|
+
from zscaler.zpa.client import ZPAClient
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class AppSegmentsInspectionAPI:
|
|
31
|
+
# Params that need reformatting
|
|
32
|
+
reformat_params = [
|
|
33
|
+
("server_group_ids", "serverGroups"),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
def __init__(self, client: ZPAClient):
|
|
37
|
+
self.rest = client
|
|
38
|
+
|
|
39
|
+
def list_segment_inspection(self, **kwargs) -> BoxList:
|
|
40
|
+
"""
|
|
41
|
+
Retrieve all configured AppProtection application segments.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
:obj:`BoxList`: List of AppProtection application segments.
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
>>> app_segments = zpa.app_segments_inspection.list_segments_inspection()
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
list, _ = self.rest.get_paginated_data(path="/application", **kwargs)
|
|
51
|
+
return list
|
|
52
|
+
|
|
53
|
+
def get_segment_inspection(self, segment_id: str) -> Box:
|
|
54
|
+
"""
|
|
55
|
+
Get information for an AppProtection application segment.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
segment_id (str):
|
|
59
|
+
The unique identifier for the AppProtection application segment.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
:obj:`Box`: The AppProtection application segment resource record.
|
|
63
|
+
|
|
64
|
+
Examples:
|
|
65
|
+
>>> app_segment = zpa.app_segments_inspection.details('99999')
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
return self.rest.get(f"application/{segment_id}")
|
|
69
|
+
|
|
70
|
+
def get_segment_inspection_by_name(self, name):
|
|
71
|
+
apps = self.list_segment_inspection()
|
|
72
|
+
for app in apps:
|
|
73
|
+
if app.get("name") == name:
|
|
74
|
+
return app
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
def delete_segment_inspection(
|
|
78
|
+
self, segment_id: str, force_delete: bool = False
|
|
79
|
+
) -> int:
|
|
80
|
+
"""
|
|
81
|
+
Delete an AppProtection application segment.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
force_delete (bool):
|
|
85
|
+
Setting this field to true deletes the mapping between AppProtection Application Segment and Segment Group.
|
|
86
|
+
segment_id (str):
|
|
87
|
+
The unique identifier for the AppProtection application segment.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
:obj:`int`: The operation response code.
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
Delete an AppProtection Application Segment with an id of 99999.
|
|
94
|
+
|
|
95
|
+
>>> zpa.app_segments.delete('99999')
|
|
96
|
+
|
|
97
|
+
Force deletion of an AppProtection Application Segment with an id of 88888.
|
|
98
|
+
|
|
99
|
+
>>> zpa.app_segments_inspection.delete('88888', force_delete=True)
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
query = ""
|
|
103
|
+
if force_delete:
|
|
104
|
+
query = "forceDelete=true"
|
|
105
|
+
response = self.rest.delete("/application/%s?%s" % (segment_id, query))
|
|
106
|
+
return response.status_code
|
|
107
|
+
|
|
108
|
+
def add_segment_inspection(
|
|
109
|
+
self,
|
|
110
|
+
name: str,
|
|
111
|
+
domain_names: list,
|
|
112
|
+
segment_group_id: str,
|
|
113
|
+
server_group_ids: list,
|
|
114
|
+
tcp_port_ranges: list = None,
|
|
115
|
+
udp_port_ranges: list = None,
|
|
116
|
+
common_apps_dto: dict = None,
|
|
117
|
+
**kwargs,
|
|
118
|
+
) -> Box:
|
|
119
|
+
"""
|
|
120
|
+
Create an AppProtection application segment.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
segment_group_id (str):
|
|
124
|
+
The unique identifer for the segment group this application segment belongs to.
|
|
125
|
+
udp_ports (:obj:`list` of :obj:`str`):
|
|
126
|
+
List of udp port range pairs, e.g. ['35000', '35000'] for port 35000.
|
|
127
|
+
tcp_ports (:obj:`list` of :obj:`str`):
|
|
128
|
+
List of tcp port range pairs, e.g. ['22', '22'] for port 22-22, ['80', '100'] for 80-100.
|
|
129
|
+
domain_names (:obj:`list` of :obj:`str`):
|
|
130
|
+
List of domain names or IP addresses for the application segment.
|
|
131
|
+
name (str):
|
|
132
|
+
The name of the application segment.
|
|
133
|
+
server_group_ids (:obj:`list` of :obj:`str`):
|
|
134
|
+
The list of server group IDs that belong to this application segment.
|
|
135
|
+
**kwargs:
|
|
136
|
+
Optional keyword args.
|
|
137
|
+
|
|
138
|
+
Keyword Args:
|
|
139
|
+
bypass_type (str):
|
|
140
|
+
The type of bypass for the Application Segment. Accepted values are `ALWAYS`, `NEVER` and `ON_NET`.
|
|
141
|
+
config_space (str):
|
|
142
|
+
The config space for this Application Segment. Accepted values are `DEFAULT` and `SIEM`.
|
|
143
|
+
default_idle_timeout (int):
|
|
144
|
+
The Default Idle Timeout for the Application Segment.
|
|
145
|
+
default_max_age (int):
|
|
146
|
+
The Default Max Age for the Application Segment.
|
|
147
|
+
description (str):
|
|
148
|
+
Additional information about this Application Segment.
|
|
149
|
+
double_encrypt (bool):
|
|
150
|
+
Double Encrypt the Application Segment micro-tunnel.
|
|
151
|
+
enabled (bool):
|
|
152
|
+
Enable the Application Segment.
|
|
153
|
+
health_check_type (str):
|
|
154
|
+
Set the Health Check Type. Accepted values are `DEFAULT` and `NONE`.
|
|
155
|
+
health_reporting (str):
|
|
156
|
+
Set the Health Reporting. Accepted values are `NONE`, `ON_ACCESS` and `CONTINUOUS`.
|
|
157
|
+
ip_anchored (bool):
|
|
158
|
+
Enable IP Anchoring for this Application Segment.
|
|
159
|
+
is_cname_enabled (bool):
|
|
160
|
+
Enable CNAMEs for this Application Segment.
|
|
161
|
+
passive_health_enabled (bool):
|
|
162
|
+
Enable Passive Health Checks for this Application Segment.
|
|
163
|
+
icmp_access_type (str): Sets ICMP access type for ZPA clients.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
:obj:`Box`: The newly created application segment resource record.
|
|
167
|
+
|
|
168
|
+
Examples:
|
|
169
|
+
Add a new AppProtection application segment for example.com, ports 8080-8085.
|
|
170
|
+
|
|
171
|
+
>>> zpa.app_segments_inspection.add_segment_inspection('new_app_segment',
|
|
172
|
+
... domain_names=['example.com'],
|
|
173
|
+
... segment_group_id='99999',
|
|
174
|
+
... tcp_ports=['8080', '8085'],
|
|
175
|
+
... server_group_ids=['99999', '88888'])
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
# Initialise payload
|
|
180
|
+
payload = {
|
|
181
|
+
"name": name,
|
|
182
|
+
"domainNames": domain_names,
|
|
183
|
+
"tcpPortRanges": tcp_port_ranges,
|
|
184
|
+
"udpPortRanges": udp_port_ranges,
|
|
185
|
+
"segmentGroupId": segment_group_id,
|
|
186
|
+
"commonAppsDto": common_apps_dto if common_apps_dto else None,
|
|
187
|
+
"serverGroups": [{"id": group_id} for group_id in server_group_ids],
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# Process common_apps_dto if it's provided
|
|
191
|
+
if common_apps_dto:
|
|
192
|
+
camel_common_apps_dto = recursive_snake_to_camel(common_apps_dto)
|
|
193
|
+
payload["commonAppsDto"] = camel_common_apps_dto
|
|
194
|
+
|
|
195
|
+
add_id_groups(self.reformat_params, kwargs, payload)
|
|
196
|
+
for key, value in kwargs.items():
|
|
197
|
+
if value is not None:
|
|
198
|
+
payload[snake_to_camel(key)] = value
|
|
199
|
+
|
|
200
|
+
# Convert the entire payload's keys to camelCase before sending
|
|
201
|
+
camel_payload = recursive_snake_to_camel(payload)
|
|
202
|
+
for key, value in kwargs.items():
|
|
203
|
+
if value is not None:
|
|
204
|
+
camel_payload[snake_to_camel(key)] = value
|
|
205
|
+
|
|
206
|
+
response = self.rest.post("application", json=camel_payload)
|
|
207
|
+
if isinstance(response, Response):
|
|
208
|
+
# this is only true when the creation failed (status code is not 2xx)
|
|
209
|
+
status_code = response.status_code
|
|
210
|
+
# Handle error response
|
|
211
|
+
raise Exception(
|
|
212
|
+
f"API call failed with status {status_code}: {response.json()}"
|
|
213
|
+
)
|
|
214
|
+
return response
|
|
215
|
+
|
|
216
|
+
def update_segment_inspection(
|
|
217
|
+
self, segment_id: str, common_apps_dto=None, **kwargs
|
|
218
|
+
) -> Box:
|
|
219
|
+
"""
|
|
220
|
+
Update an AppProtection application segment.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
segment_id (str):
|
|
224
|
+
The unique identifier for the AppProtection application segment.
|
|
225
|
+
**kwargs:
|
|
226
|
+
Optional params.
|
|
227
|
+
|
|
228
|
+
Keyword Args:
|
|
229
|
+
bypass_type (str): Bypass type for the segment. Values: `ALWAYS`, `NEVER`, `ON_NET`.
|
|
230
|
+
config_space (str): Config space for the segment. Values: `DEFAULT`, `SIEM`.
|
|
231
|
+
default_idle_timeout (int):
|
|
232
|
+
The Default Idle Timeout for the AppProtection Application Segment.
|
|
233
|
+
default_max_age (int):
|
|
234
|
+
The Default Max Age for the AppProtection Application Segment.
|
|
235
|
+
description (str):
|
|
236
|
+
Additional information about this AppProtection Application Segment.
|
|
237
|
+
domain_names (:obj:`list` of :obj:`str`):
|
|
238
|
+
List of domain names or IP addresses for the AppProtection application segment.
|
|
239
|
+
double_encrypt (bool):
|
|
240
|
+
Double Encrypt the AppProtection Application Segment micro-tunnel.
|
|
241
|
+
enabled (bool):
|
|
242
|
+
Enable the AppProtection Application Segment.
|
|
243
|
+
health_check_type (str):
|
|
244
|
+
Set the Health Check Type. Accepted values are `DEFAULT` and `NONE`.
|
|
245
|
+
health_reporting (str):
|
|
246
|
+
Set the Health Reporting. Accepted values are `NONE`, `ON_ACCESS` and `CONTINUOUS`.
|
|
247
|
+
ip_anchored (bool):
|
|
248
|
+
Enable IP Anchoring for this AppProtection Application Segment.
|
|
249
|
+
is_cname_enabled (bool):
|
|
250
|
+
Enable CNAMEs for this AppProtection Application Segment.
|
|
251
|
+
name (str):
|
|
252
|
+
The name of the AppProtection Application Segment.
|
|
253
|
+
passive_health_enabled (bool):
|
|
254
|
+
Enable Passive Health Checks for this AppProtection Application Segment.
|
|
255
|
+
segment_group_id (str):
|
|
256
|
+
The unique identifer for the segment group this AppProtection application segment belongs to.
|
|
257
|
+
server_group_ids (:obj:`list` of :obj:`str`):
|
|
258
|
+
The list of server group IDs that belong to this AppProtection application segment.
|
|
259
|
+
tcp_ports (:obj:`list` of :obj:`tuple`):
|
|
260
|
+
List of TCP port ranges specified as a tuple pair, e.g. for ports 21-23, 8080-8085 and 443:
|
|
261
|
+
[(21, 23), (8080, 8085), (443, 443)]
|
|
262
|
+
udp_ports (:obj:`list` of :obj:`tuple`):
|
|
263
|
+
List of UDP port ranges specified as a tuple pair, e.g. for ports 34000-35000 and 36000:
|
|
264
|
+
[(34000, 35000), (36000, 36000)]
|
|
265
|
+
icmp_access_type (str): Sets ICMP access type for ZPA clients.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
:obj:`Box`: The updated AppProtection application segment resource record.
|
|
269
|
+
|
|
270
|
+
Examples:
|
|
271
|
+
Rename the application segment for example.com.
|
|
272
|
+
|
|
273
|
+
>>> zpa.app_segments_inspection.update('99999',
|
|
274
|
+
... name='new_app_name',
|
|
275
|
+
|
|
276
|
+
"""
|
|
277
|
+
# Set payload to value of existing record and recursively convert nested dict keys from snake_case to camelCase.
|
|
278
|
+
payload = convert_keys(self.get_segment_inspection(segment_id))
|
|
279
|
+
|
|
280
|
+
if kwargs.get("tcp_port_ranges"):
|
|
281
|
+
payload["tcpPortRange"] = [
|
|
282
|
+
{"from": ports[0], "to": ports[1]}
|
|
283
|
+
for ports in kwargs.pop("tcp_port_ranges")
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
if kwargs.get("udp_port_ranges"):
|
|
287
|
+
payload["udpPortRange"] = [
|
|
288
|
+
{"from": ports[0], "to": ports[1]}
|
|
289
|
+
for ports in kwargs.pop("udp_port_ranges")
|
|
290
|
+
]
|
|
291
|
+
|
|
292
|
+
if common_apps_dto:
|
|
293
|
+
camel_common_apps_dto = recursive_snake_to_camel(
|
|
294
|
+
common_apps_dto
|
|
295
|
+
) # use the recursive function
|
|
296
|
+
payload[
|
|
297
|
+
"commonAppsDto"
|
|
298
|
+
] = camel_common_apps_dto # ensure commonAppsDto gets added to payload
|
|
299
|
+
|
|
300
|
+
# Convert other keys in payload
|
|
301
|
+
add_id_groups(self.reformat_params, kwargs, payload)
|
|
302
|
+
|
|
303
|
+
# Add remaining optional parameters to payload
|
|
304
|
+
for key, value in kwargs.items():
|
|
305
|
+
payload[snake_to_camel(key)] = value
|
|
306
|
+
|
|
307
|
+
resp = self.rest.put(f"application/{segment_id}", json=payload).status_code
|
|
308
|
+
|
|
309
|
+
# Return the object if it was updated successfully
|
|
310
|
+
if not isinstance(resp, Response):
|
|
311
|
+
return self.get_segment_inspection(segment_id)
|