ZIA API Introduction

,

Introduction

This document provides steps for configuring APIs for ZIA and applying for a variety of use cases. The purpose of this document is to provide an introduction to different methods of making API calls and examples to jump start custom integrations and automate tasks.

This document uses Postman as a starting point for validating the API integration and an easy way to convert the API access from Postman to Python. It continues with Python scripts that can be created from Postman. It finishes with using a Software Development Kit (SDK) to use pre-built libraries to simplify the Python scripting and removing the need to build scripts from scratch. Along the way examples are shown with expected results. Finally a number of use cases are provided. The reader can utilize any of the methods described to create their own API calls based on their use case.

Please note that the ZPA API is a different configuration than the ZIA API configuration.

This document follows the API documentation provided in the Zscaler ZIA help documentation.

The examples in this document were created with Postman 10.0.15 and Python 3.10.6.

Prerequisites

Postman

  1. Install the Postman application and create an account. Postman can be accessed at Download Postman | Get Started for Free.

Enable Zscaler API

  1. API access is not enabled by default. A ticket needs to be opened to enable the API access. A ticket can be opened at https://help.zscaler.com/submit-ticket. There are three types of API access that can be granted. For the purposes of this guide, just the Cloud Service API and the Sandbox API need to be requested. The Sandbox API should only be requested if the Sandbox service has been purchased. The third API is the OAUTH 2.0 API. The ticket should be constructed similar to the screenshot below.

  1. Access Administration > Authentication > Administrator Management

  1. Create a ZIA user with admin privileges that is limited as much as possible based on organization, department, location, and location groups within the user configuration. In the screenshot below, the places for granular permissions are the Role and Scope.

Create Zscaler API Key

The first step is to create the Zscaler key and credentials to use for API access.

  1. Access ZIA Admin portal at https://admin.<zscaler cloud>.net where <zscaler cloud> is the specific cloud assigned to your tenant. For example https://admin.zscalertwo.net. Possible clouds are zscaler, zscalerone, zscalertwo, zscalerthree, zscloud, zscalerbeta, or zscalergov.
  2. Go to Administration > Cloud Service API Key Management

  1. With ZIA only one Cloud Service API key can be generated. This could be used for multiple purposes. Copy the key for later use within Postman.

NOTE

Be careful not to regenerate an existing key without checking with other members of the organization that may be using the Cloud Service API key. If the key is regenerated their applications will fail authentication.

ZIA Postman Configuration

Postman is an API platform for building and using Cloud Service APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better Cloud Service APIs faster. Zscaler provides step by step instructions on setting up Postman with ZIA and the full JSON/Postman collection scripts for existing API calls. This significantly eases the ability to create API scripts for automation and integration. This document follows and augments that documentation. A link to the Zscaler ZIA API Postman documentation is linked below.

Create a Workspace

Workspaces provide an area for common configuration. For example, we can create a workspace for all Zscaler related configurations. This includes ZIA, ZPA, and ZDX.

  1. Click on Workspaces and create a new Workspace called Zscaler

Create an Environment

Within the Workspace, environments provide a space to save the variables associated with a particular application. This provides the benefit of having a centralized location for storing tokens, credentials, and URLs so that values can be reused across multiple ZIA API calls. If there is a change to a common variable the change can be made once to the environment for the benefit of all ZIA API calls that use the variable as part of the Postman ZIA script. In our case we will be creating an environment for all ZIA related variables.

  1. Click on the Environment tab. Click the + sign to create a new environment

  1. Click the … to the right of the environment and rename the environment ZIA

  1. Create a variable with name url and initial value https://zsapi.<zscaler cloud>/api/v1. For example https://zsapi.zscalertwo.net/api/v1. Please refer to the base URL shown in the Zscaler ZIA Admin portal config for any changes to the URL. This is available in the ZIA admin portal at Administration > Authentication > Authentication Configuration > Cloud Server API Key Management. Note that the name and capitalization of the variable are important to be exactly as shown because the variable will be used within the API configuration to be imported later.

  1. An example of the Environment is shown below in two screenshots to allow zoom in.

Download Cloud Service API Postman Collection for ZIA

The API Postman collection is a repository of all ZIA API calls that can be bulk imported into Postman as one JSON file. This provides easy access to an updated list of all ZIA API calls.

  1. Download the full list of Cloud Service APIs for import into Postman by first accessing Activation | Zscaler
  2. Click on Try in Postman on any Response section to download the entire API collection. This may not be obvious at first glance because it appears that you are only downloading the individual API information for the one API call, but it really is the entire API list. Save the API list to your computer for later use within Postman

Create Collection

Collections provide the Cloud Service API calls that are imported into Postman and stored within the Workspace

  1. Click on Workspaces and create a new Workspace called “Zscaler”

  1. Click on Import and import the Cloud Service API list downloaded earlier in the Cloud Service API List Download section.

  1. You should now see a new collection created called “ZIA cloud service API 6.1” or similar that reflects the current API collection version being used.

Login

This section covers inserting the authentication from Postman to ZIA

  1. Open Postman and navigate to your ZIA Collection
  2. Select the ZIA Environment from the top right

  1. Open on the Authentication - Post entry

  1. Click on Pre-request Script and replace “yourapikiey” with the key from the Cloud Service API key created in the “Zscaler Cloud Service API Key Creation” section. This will hide your key in the general configuration.

  1. Click on Body and replace the username and password with your Cloud Service API admin credentials. Alternatively, you could create a variable for ‘YouAPIKey’ and define the variable in the environment. This will enable an easier way to modify the key if it changes in the future.

  1. Click Send. The result should look similar to below.

  1. This authentication session lasts for 30 minutes idle time by default in the Zscaler Admin Portal. This can be changed in the Admin Portal under Administration > Advanced Settings to anywhere between 5 minutes and 600 minutes. The session is tracked via a JSESSIONID cookie. The JSESSIONID is created during the initial login and is automatically added to every subsequent API request. If the JSESSIONID is expired, the API request will be returned with an invalid login error. This can be seen in the Post - Authentication Post API as shown below

Activate Changes

If any configuration changes are made they must be activated. This can be done by following the steps below. Best practice is always to perform checks for pending changes to avoid conflict with other admins as the first change will take precedence and until the first admin is done with changes our config will be locked.

  1. Open the Activation Folder
  2. Click on Post - Status Post
  3. Click on Send. A successful example is shown below

Logout

Logging out utilizes the same steps as logging in but with a Delete action. Logging out increases security by not leaving open sessions and saves resources by removing the need to continue tracking the session. Follow the steps below to logout.

  1. Open the API Authentication folder
  2. Click on Del Authentication - Delete
  3. Click on Send. A successful example is shown below

Example: Get All Locations

Walk through how to get all locations using Postman API calls. Within Zscaler we can define physical locations that can then be used to define access policy. Common locations are HQ, branches, and road warriors.

  1. Open the API Authentication folder
  2. Click on the Post Authenticate - Post API and click on send to generate the authenticated session. The output should look similar to below.

  1. Open the Location Management folder
  2. click on Get Locations - Get all.
  3. Click send on the API page. You should receive a listing of your locations. An example is shown below.

Creating ZIA Python Scripts

Python scripts provide a way to include multiple API calls to add more customization and automation to the individual API calls shown with Postman. One way to utilize the APIs is to utilize Postman to create Python script snippets to add into a more comprehensive script to accomplish use cases. The section below provides additional details to get started with creating scripts.

Authentication Best Practices

The first module in a script should authenticate to create the JSESSIONID cookie. This cookie must be used in all subsequent requests to validate that the request is associated with the original authentication request.

The initial authentication request requires sensitive username, password, and Cloud Service API key credentials. This information should be protected as much as possible. With this in mind, the following three methods can be used in order of best to worst options. Environment variables should be used whenever possible. The second two options should only be used if the environment variables method cannot be used.

In each method the following information must be provided

  1. Cloud Service API key - Key defined within the ZIA Admin portal
  2. Cloud - The specific cloud assigned for the tenant (e.g. zscalerone, zscalertwo, zscalerthree)
  3. user name - username to use with admin rights
  4. Password - password associated with the admin user

Authentication Method 1: Environment Variables (Preferred Method)

This is the most secure method of storing sensitive information. For Linux systems the commands below would be added to the shell resource file. For example, .zshrc or .bashrc file depending on which shell is being used. To reapply the file to the current shell, enter “. ./.zshrc”

export ZIA_USERNAME=”api@test.com”
export ZIA_PASSWORD=”HBRMdddsdfs”
export ZIA_API_KEY=”2324242343”
export ZIA_CLOUD=”zscalertwo”

For Windows systems this would look similar to the following

$env: ZIA_USERNAME=”api@test.com”
$env: ZIA_PASSWORD=”HBRMdddsdfs”
$env: ZIA_API_KEY=”2324242343”
$env: ZIA_CLOUD=”zscalertwo”

Once the parameters are within the environment variables it is just a matter of importing them into the python script. This example shows it can be done. It shows how environment variables can be saved to python variables that can be used within a script.

Script

import os
 
# Get all environment variables
print ("----------------------------------------------------------------")
print (os.environ)
print ("----------------------------------------------------------------")
 
# method that does not create error message if variable does not exist
ZIA_CLOUD=os.environ.get('ZIA_CLOUD')
 
# create keyerror if variable does not exist
#ZIA_CLOUD2=os.environ['ZIA_CLOUD']
 
print(ZIA_CLOUD)
print ("----------------------------------------------------------------")

Script Output

rchee@Robs-MacBook-Pro-2 ZIA API % python3 os.pl

----------------------------------------------------------------

environ({'__CFBundleIdentifier': 'com.apple.Terminal', 'TMPDIR': '/var/folders/nf/0fhd08w92bgfng9_fgr3y_040000gn/T/', 'XPC_FLAGS': '0x0', 'TERM': 'xterm-256color', 'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.xDJvlGFAEf/Listeners', 'XPC_SERVICE_NAME': '0', 'TERM_PROGRAM': 'Apple_Terminal', 'TERM_PROGRAM_VERSION': '445', 'TERM_SESSION_ID': 'B533916F-3C3D-45AF-8377-08D260176969', 'SHELL': '/bin/zsh', 'HOME': '/Users/rchee', 'LOGNAME': 'rchee', 'USER': 'rchee', 'PATH': '/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/MacGPG2/bin', 'SHLVL': '1', 'PWD': '/Users/rchee/Documents/ZIA API', 'OLDPWD': '/Users/rchee/Documents/ZPA API', 'HOMEBREW_PREFIX': '/opt/homebrew', 'HOMEBREW_CELLAR': '/opt/homebrew/Cellar', 'HOMEBREW_REPOSITORY': '/opt/homebrew', 'MANPATH': '/opt/homebrew/share/man::', 'INFOPATH': '/opt/homebrew/share/info:', 'ZIA_USERNAME': 'api@azuretwo.cheeworld.com', 'ZIA_PASSWORD': 'xxxxxxx', 'ZIA_API_KEY': 'xxxxxxx', 'ZIA_CLOUD': 'zscalertwo', 'ZPA_CLIENT_ID': 'Mjg4MjU4NjMyNzQxNTUyMjI1LTkxMTQyMWU1LWEzNDAtNDc0OC1hMDc3LTU0M2MzNTZiMDI1Ng==', 'ZPA_CLIENT_SECRET': "-0mf|.D-r}R3-V537X-uI6<'7(:eCUmt", 'ZPA_CUSTOMER_ID': '288258632741552128', 'LANG': 'en_US.UTF-8', '_': '/opt/homebrew/bin/python3', '__CF_USER_TEXT_ENCODING': '0x1F5:0x0:0x0'})

----------------------------------------------------------------

zscalertwo

----------------------------------------------------------------

Authentication Method 2: Static Credentials

In this method, the parameters are hard coded in a configuration file.

Authentication Method 3: JSON Configuration File

In this method, the parameters are housed in a JSON configuration file that is in a safe location that is referenced by the Python script.

Authentication Script Snippet

Use the following python script at the beginning of all Python scripts to complete the authentication and create the JSESSION ID that will be used for Cloud Service API calls

import requests
import json
import time
import http.client
import os
 
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
auth_url = 'https://zsapi.' + zia_cloud + '.net/api/v1/authenticatedSession'
 
def obfuscateApiKey ():
   # this is the API Key from ZIA
    seed = zia_api_key
    now = int(time.time() * 1000)
    n = str(now)[-6:]
    r = str(int(n) >> 1).zfill(6)
    key = ""
    for i in range(0, len(str(n)), 1):
        key += seed[int(str(n)[i])]
    for j in range(0, len(str(r)), 1):
        key += seed[int(str(r)[j])+2]
    return now, key
 
 
def auth_session ():
  now,key = obfuscateApiKey()
 
  auth_payload = json.dumps({
    "username": zia_username,
    "password": zia_password,
    "apiKey": key,
    "timestamp": now
  })
 
  auth_headers = {
    'Content-Type': 'application/json',
    'cache-control': 'no-cache'
  }
 
  response = requests.request("POST", auth_url, headers=auth_headers, data=auth_payload)
  jsess = response.cookies.get_dict()
  for k,v in jsess.items():
    jval = v
  return jval

Example: Create Python Script from Postman

This example uses the Get All Locations Postman example and turns it into a Python script. The script will leverage the Python authentication script snippet from the last section at the start of the script.

  1. Export environment variables to the shell as shown in the Environment Variables section.
  2. Open a new terminal/command prompt to ensure environment variables are applied to the shell
  3. Type “env” to verify that the variables are present. You can add “ | grep ZIA” to filter to just the parameters including ZIA.
rchee@Robs-MacBook-Pro-2 pyZscaler % env | grep ZIA
PWD=/Users/rchee/Documents/ZIA API/pyZscaler
OLDPWD=/Users/rchee/Documents/ZIA API
ZIA_USERNAME=api@azuretwo.cheeworld.com
ZIA_PASSWORD=xxxxx
ZIA_API_KEY=xxxxxx
ZIA_CLOUD=zscalertwo
  1. Start a python script with the following to create the JSESSION ID that must be included with each request
import requests
import json
import time
import http.client
import os
 
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
auth_url = 'https://zsapi.' + zia_cloud + '.net/api/v1/authenticatedSession'
 
def obfuscateApiKey ():
   # this is the API Key from ZIA
    seed = zia_api_key
    now = int(time.time() * 1000)
    n = str(now)[-6:]
    r = str(int(n) >> 1).zfill(6)
    key = ""
    for i in range(0, len(str(n)), 1):
        key += seed[int(str(n)[i])]
    for j in range(0, len(str(r)), 1):
        key += seed[int(str(r)[j])+2]
    return now, key
 
 
def auth_session ():
  now,key = obfuscateApiKey()
 
  auth_payload = json.dumps({
    "username": zia_username,
    "password": zia_password,
    "apiKey": key,
    "timestamp": now
  })
 
  auth_headers = {
    'Content-Type': 'application/json',
    'cache-control': 'no-cache'
  }
 
  response = requests.request("POST", auth_url, headers=auth_headers, data=auth_payload)
  jsess = response.cookies.get_dict()
  for k,v in jsess.items():
    jval = v
  return jval
  1. Follow the steps in the Postman Example: Get All Locations section. After successfully running the steps, click the “</>” on the far right

  1. Select Python - Requests, copy the code, and append the postman auto generated code that was started in step 4.

  1. The final python script should look similar to below
import requests
import json
import time
import http.client
import os
 
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
auth_url = 'https://zsapi.' + zia_cloud + '.net/api/v1/authenticatedSession'
 
def obfuscateApiKey ():
   # this is the API Key from ZIA
    seed = zia_api_key
    now = int(time.time() * 1000)
    n = str(now)[-6:]
    r = str(int(n) >> 1).zfill(6)
    key = ""
    for i in range(0, len(str(n)), 1):
        key += seed[int(str(n)[i])]
    for j in range(0, len(str(r)), 1):
        key += seed[int(str(r)[j])+2]
    return now, key
 
 
def auth_session ():
  now,key = obfuscateApiKey()
 
  auth_payload = json.dumps({
    "username": zia_username,
    "password": zia_password,
    "apiKey": key,
    "timestamp": now
  })
 
  auth_headers = {
    'Content-Type': 'application/json',
    'cache-control': 'no-cache'
  }
 
  response = requests.request("POST", auth_url, headers=auth_headers, data=auth_payload)
  jsess = response.cookies.get_dict()
  for k,v in jsess.items():
    jval = v
  return jval
 
 
url = "https://zsapi.zscalertwo.net/api/v1/locations?page=1&pageSize=100"
 
jsession = auth_session()
 
payload={}
headers = {
 'Content-Type': 'application/json',
 'Cookie': 'JSESSIONID=' + jsession
}
response = requests.request("GET", url, headers=headers, data=payload)
 
print(response.text)

Script Output

python3 zia-get-all-locations-script.pl

[{"id":53311092,"name":"skytap","nonEditable":false,"parentId":0,"upBandwidth":0,"dnBandwidth":0,"country":"NONE","language":"NONE","tz":"UNITED_STATES_AMERICA_CHICAGO","authRequired":false,"sslScanEnabled":false,"zappSslScanEnabled":false,"xffForwardEnabled":false,"otherSubLocation":false,"ecLocation":true,"surrogateIP":false,"idleTimeInMinutes":0,"surrogateIPEnforcedForKnownBrowsers":false,"surrogateRefreshTimeInMinutes":0,"kerberosAuth":false,"digestAuthEnabled":false,"ofwEnabled":false,"ipsControl":false,"aupEnabled":false,"cautionEnabled":false,"aupBlockInternetUntilAccepted":false,"aupForceSslInspection":false,"aupTimeoutInDays":0,"childCount":0,"matchInChild":false,"staticLocationGroups":[],"dynamiclocationGroups":[{"id":51025546,"name":"Unassigned Locations"}],"excludeFromDynamicGroups":false,"excludeFromManualGroups":false,"profile":"NONE"},{"id":53324421,"name":"skytap2","nonEditable":false,"parentId":0,"upBandwidth":0,"dnBandwidth":0,"country":"NONE","language":"NONE","tz":"UNITED_STATES_AMERICA_CHICAGO","authRequired":false,"sslScanEnabled":false,"zappSslScanEnabled":false,"xffForwardEnabled":false,"otherSubLocation":false,"ecLocation":true,"surrogateIP":false,"idleTimeInMinutes":0,"surrogateIPEnforcedForKnownBrowsers":false,"surrogateRefreshTimeInMinutes":0,"kerberosAuth":false,"digestAuthEnabled":false,"ofwEnabled":false,"ipsControl":false,"aupEnabled":false,"cautionEnabled":false,"aupBlockInternetUntilAccepted":false,"aupForceSslInspection":false,"aupTimeoutInDays":0,"childCount":0,"matchInChild":false,"staticLocationGroups":[],"dynamiclocationGroups":[{"id":51025546,"name":"Unassigned Locations"}],"excludeFromDynamicGroups":false,"excludeFromManualGroups":false,"profile":"NONE"}]

Alternate Output

The example below provides alternate outputs that can be provided by pulling variables out of the raw dictionary output shown above. The authentication portion is skipped in this. Add it from above for the complete script. Additionally, this is a great example of how to pull out specific values and assign to variables to use in another part of the script.

Script portion

response = requests.request("GET", url, headers=headers, data=payload)
 
# output in Python dictionary format
locations_json = response.json()
 
# Uncomment to show all key,value pairs
#print (locations_json)
 
# show select location information
for dictionary in locations_json:
  print("----------------")
  for key in dictionary:
    if key=="name" or key=="id" or key=="tz":
      print (key,":",dictionary[key])

Script Output

----------------
id : 53311092
name : skytap
tz : UNITED_STATES_AMERICA_CHICAGO
----------------
id : 53324421
name : skytap2
tz : UNITED_STATES_AMERICA_CHICAGO

Zscaler pyZscaler Software Development Kit (SDK)

Software Development Kits (SDK) are the best way to create scalable scripts as complexity increases. There are a number of unofficial SDKs that can be used to allow easier development of scripts to address ZIA API use cases. This section utilizes pyZscaler Python SDK. pyZscaler is an SDK that provides a uniform and easy-to-use interface for each of the Zscaler product APIs. One nice feature the use of Python Box . Box is designed to be an easy drop in as a transparent replacement for dictionaries that adds dot notation access and a load of other features. Keep in mind that the pyZscaler SDK is not a Zscaler supported SDK since there are currently no Zscaler supported SDKs, but this SDK is the most full featured and well documented. It is also unofficially supported by a Zscaler engineer, Mitch Kelly.

The Zscaler APIs expect and return JSON structures with key names in CamelCase. This violates PEP-8 and results in code that’s hard to read. pyZscaler will seamlessly convert to PEP-8 compliant Snake Case so that your code can remain readable and beautiful. Refer to the pyZscaler Library Documentation at ReadTheDocs to ensure that you are passing correctly named parameters to the class methods.

Create Scripts

The methods are well defined in the pyZscaler library. They each simplify the creation by incorporating many of the steps into the method to eliminate as much additional code as possible and implement error checking.

The prerequisite for running pyZscaler is to have Python 3.7+ installed with pip3 installed as well.

The pyZscaler SDK is installed using “pip3 install pyzscaler”. When creating the Python script, you must import the module using “from pyzscaler.zia import ZIA” at the top of the script. Notice that the top portion is the same Python code to obtain the sensitive information from the environment variables.

With this in mind, the following steps can be taken to utilize a method.

  1. Access ZIA
  2. View the methods available

  1. Click on a method to implement. Users is chosen in the screenshot below

  1. Validate the required parameters
  2. Use the examples provided at the bottom of the method description to show the correct syntax

  1. Create the script. The examples in the section below provide a good representation of what can be done.

Example: Get Users

This example uses the pyZscaler SDK to obtain the current users associated with a tenant. This assumes that the pyZscaler SDK has been installed using “pip3 install pyzscaler”. When creating the Python script, you must import the module using “from pyzscaler.zia import ZIA”. Notice that the top portion is the same Python code to obtain the sensitive information from the environment variables. Only the short bottom part is the pyZscaler portion.

Script

from pyzscaler.zia import ZIA
import os
import sys
 
################################
#gather environment variables
################################
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
################################
# List users
################################
with ZIA(api_key=zia_api_key, cloud=zia_cloud, username=zia_username, password=zia_password) as zia:
  for user in zia.users.list_users():
     for k in user:
       print(k,":",user[k])
     print("---------------------")

Script Output

rchee@Robs-MacBook-Pro-2 pyZscaler % python3 users.pl
id : 51025535
name : DEFAULT ADMIN
email : admin@51025532.zscalertwo.net
groups : [{'id': 51025533, 'name': 'Service Admin'}]
department : {'id': 51025534, 'name': 'Service Admin'}
admin_user : True
is_non_editable : False
deleted : False
---------------------
id : 54030390
name : api
email : api@azuretwo.cheeworld.com
groups : [{'id': 51025533, 'name': 'Service Admin'}]
department : {'id': 51025534, 'name': 'Service Admin'}
admin_user : True
is_non_editable : False
deleted : False
---------------------
id : 52221568
name : userfourtwo
email : userfour@azuretwo.cheeworld.com
groups : [{'id': 52221572, 'name': 'Azuretwo Users'}]
admin_user : False
is_non_editable : False
deleted : False

Example: Get Departments

This example uses the SDK to obtain the current departments associated with a tenant. This assumes that the pyZscaler SDK has been installed using “pip3 install pyzscaler”. Notice that the top portion is the same Python code to obtain the sensitive information from the environment variables. Only the short bottom part is the pyZscaler portion.

Script

from pyzscaler.zia import ZIA
from pprint import pprint
import os
import sys
 
################################
#gather environment variables
################################
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
################################
#list departments
################################
with ZIA(api_key=zia_api_key, cloud=zia_cloud, username=zia_username, password=zia_password) as zia:
  for department in zia.users.list_departments():
     for k in department:
       print(k,":",department[k])
     print("---------------------")

Script Output

id : 56307387
name : Finance
---------------------
id : 56307393
name : IT
---------------------
id : 56307381
name : Marketing
---------------------
is_non_editable : True
id : 51025534
name : Service Admin
---------------------

Example: Get Groups

This example uses the SDK to obtain the current groups associated with a tenant. This assumes that the pyZscaler SDK has been installed using “pip3 install pyzscaler”. Notice that the top portion is the same Python code to obtain the sensitive information from the environment variables. Only the short bottom part is the pyZscaler portion.

Script

from pyzscaler.zia import ZIA
from pprint import pprint
import os
import sys
 
################################
#gather environment variables
################################
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
################################
#list groups
################################
with ZIA(api_key=zia_api_key, cloud=zia_cloud, username=zia_username, password=zia_password) as zia:
  for group in zia.users.list_groups():
     for k in group:
       print(k,":",group[k])
     print("---------------------")

Script Output

id : 52221572
name : Azuretwo Users
---------------------
is_non_editable : True
id : 51025533
name : Service Admin
---------------------

Example: Add Users

This example uses the SDK to add a user into a tenant. This assumes that the pyZscaler SDK has been installed using “pip3 install pyzscaler”. It also assumes that the”Get Departments” and “Get Groups” examples have been run to obtain the group and department IDs for the user. Notice that the top portion is the same Python code to obtain the sensitive information from the environment variables. Only the short bottom part is the pyZscaler portion.

Script

from pyzscaler.zia import ZIA
from pprint import pprint
import os
 
################################
#gather environment variables
################################
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
################################
#add user
################################
with ZIA(api_key=zia_api_key, cloud=zia_cloud, username=zia_username, password=zia_password) as zia:
  user=zia.users.add_user(name='Test User3',
    email='test_user3@azuretwo.cheeworld.com',
    groups=[{
      'id': '52221572'}],
    department={
      'id': '51025534'})
 
  print (user)

Script Output

{'id': 56307773, 'name': 'Test User3', 'email': 'test_user3@azuretwo.cheeworld.com', 'groups': [{'id': 52221572}], 'department': {'id': 51025534}, 'deleted': False}

ZIA Admin Portal

Notice that the test_user3@azuretwo.cheeworld.com exists

Crowdstrike Threat Intelligence Integration

One of the Crowdstrike integrations focuses on threat intelligence sharing from Crowdstrike to Zscaler Internet Access (ZIA). From a high level, Crowdstrike periodically adds the latest malicious URLs and IP addresses to a ZIA custom URL category. This URL category can then be used within ZIA policies to apply a block or caution action to any traffic matching the URL category. The methodology to implement this is based on a Crowdstrike maintained Python script hosted in Github that would exist on a customer owned workstation/server that would use API calls to pull URL and IP information from Crowdstrike and push the information to the Zscaler customer URL category. The sections below will describe the integration in three steps

  1. Configure ZIA
  2. Configure Crowdstrike
  3. Configure Python script on separate server

A public facing deployment guide for this integration in “Use Case 4” is available in the link below.

Public facing deployment guide: https://www.zscaler.com/resources/solution-briefs/partner-crowdstrike-deployment-guide.pdf

Additionally, the Youtube video below provides a brief overview of the integration.

YouTube Video Explaining the Integration

Prerequisites

Licensing

  1. CrowdStrike Falcon Intelligence license and API access
  2. Zscaler ZIA license (note: If the API access is not shown in the Admin portal, as shown below, a support ticket must be opened at https://help.zscaler.com/submit-ticket to enable API access for the ZIA tenant)

Environment Requirements

  1. CrowdStrike Falcon Admin portal access and account
  2. Zscaler Internet Access Admin portal access and account
  3. Linux server with Python 3.7+ installed

ZIA Configuration

Create ZIA Custom URL Category

Create a custom URL category that will be used to house the IP addresses and URLs pushed to ZIA from Crowdstrike.

  1. Access Admin > URL Categories
  2. Add a new URL category with the name “CrowdStrike Malicious URLs - High”. It is important that the name matches exactly, including the case. The Python script will not proceed if the URL category name does not match. Note that at least one URL must be added. A dummy URL such as abcdefg.com could be added.

Create ZIA API Key

The API information will be used within the Python script. With ZIA only one API can be granted. If this already exists for other functionality it can also be used for the Crowdstrike integration.

  1. Access ZIA admin Portal
  2. Access Administration > Cloud Service API Security
  3. Use the existing API key or create a new one if one does not exist. Be careful not to regenerate a new key if one already exists. If there are other applications using the key they will be broken upon regeneration of the key.

Create Crowdstrike Token

The token information will be used within the Python script

  1. Open the Falcon UI
  2. Navigate to API Client and Keys
  3. Click Add a New API Client
  4. Create a client with READ permissions for Indicators (Falcon X)
  5. Save the resulting values

Python Configuration

The Python script must exist on a separate workstation/server. The server must have Python 3.7+ and Git installed. It is possible to run this on a Linux, Mac OSX, or Windows computer.

Environment

For Linux, Python and Git should be obtained via the Linux package manager.

For Mac OSX, Homebrew is a great tool for installing applications. Download homebrew at https://brew.sh. After installing brew, Python can be installed with “brew install python3” and “brew install pip3”. Github can be installed with “brew install git”.

For Windows, various packages are available. Below is are some examples

  1. gVim - for editing
  2. Git SCM
  3. Python for Windows

One additional Python prerequisite that must be met is to install the requirements package using the command below.

pip3 install -r requirements.txt

The output of running the command should look similar to the following.

C:\Windows\System32\zscaler-FalconX-integration>pip3 install -r requirements.txt
Requirement already satisfied: requests==2.25.1 in c:\users\administrator\appdata\local\programs\python\python38\lib\site-packages (from -r requirements.txt (line 1)) (2.25.1)
Collecting requests_toolbelt==0.9.1
  Downloading requests_toolbelt-0.9.1-py2.py3-none-any.whl (54 kB)
     |████████████████████████████████| 54 kB 1.2 MB/s
Requirement already satisfied: idna<3,>=2.5 in c:\users\administrator\appdata\local\programs\python\python38\lib\site-packages (from requests==2.25.1->-r requirements.txt (line 1)) (2.10)
Requirement already satisfied: chardet<5,>=3.0.2 in c:\users\administrator\appdata\local\programs\python\python38\lib\site-packages (from requests==2.25.1->-r requirements.txt (line 1)) (4.0.0)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\users\administrator\appdata\local\programs\python\python38\lib\site-packages (from requests==2.25.1->-r requirements.txt (line 1)) (1.26.5)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\administrator\appdata\local\programs\python\python38\lib\site-packages (from requests==2.25.1->-r requirements.txt (line 1)) (2021.5.30)
Installing collected packages: requests-toolbelt
Successfully installed requests-toolbelt-0.9.1
WARNING: You are using pip version 21.1.1; however, version 22.2.2 is available.
You should consider upgrading via the 'c:\users\administrator\appdata\local\programs\python\python38\python.exe -m pip install --upgrade pip' command.

Download Python Script

  1. Open a command prompt
  2. Enter “git clone https://github.com/CrowdStrike/zscaler-FalconX-integration.git”
  3. Cd zscaler-FalconX-integration
C:\Windows\system32>git clone https://github.com/CrowdStrike/zscaler-FalconX-integration.git
Cloning into 'zscaler-FalconX-integration'...
remote: Enumerating objects: 80, done.
remote: Counting objects: 100% (79/79), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 80 (delta 35), reused 66 (delta 22), pack-reused 1
Receiving objects: 100% (80/80), 16.02 KiB | 2.00 MiB/s, done.
Resolving deltas: 100% (35/35), done.
 
C:\Windows\system32>cd zscaler-FalconX-integration

Modify config.ini

Config.ini hosts some of the credential parameters.

  1. Open config.ini with Vim or another text editor
  2. View the current configuration. It should look like this.
[CROWDSTRIKE]
client=Your Falcon API Client ID
base_url=Your Falcon API Base URL (ex: https://api.crowdstrike.com)
limit=Number of indicators to maintain (Default 10,000)
[ZSCALER]
hostname=Your zscaler Hostname (Hostname only requires the base URL (e.g., https://zsapi.zscalerthree.net))
username=Your ZIA Username
  1. Modify the configuration using the parameters obtained from the sections above to look similar to what is shown below
# CrowdStrike - Zscaler Intel Bridge Configuration File
# Enter values prior to first launch
# Confirm that your Zscaler URL Categories contains a User-Defined category named 'CrowdStrike Malicious URLs - High'
# CrowdStrike configurations
 
# Do not use quotation marks in these values!
 
[CROWDSTRIKE]
client=041aaaf2xxxxxxxxxxxx
base_url=https://api.crowdstrike.com
limit=10000
[ZSCALER]
# ZScaler configurations
 
# Hostname only requires the base URL! (i.e. https://zsapi.zscalerthree.net)
 
hostname=https://zsapi.zscalertwo.net
username=crowdstrike@azuretwo.cheeworld.com
  1. Save the file and exit

Run the script

The last step is to run the script.

python3 intelbridge -s 'Your Falcon API secret' -p 'Your zscaler ZIA Password' -k 'Your zscaler API Key'

An example with parameters added and the working output is shown below

python intelbridge -s jMnq0ohFxxxxxxxxxxxxx -p s0Hyxxxxxxxxxx -k 475xxxxxxxx
10/11/2022 03:27:42 PM Log utility started. Writing to ./logs/2022-10-11-15_27_42_intel_bridge_log.log
10/11/2022 03:27:42 PM Falcon X Zscaler Intel Bridge main routine starting...
10/11/2022 03:27:42 PM Initializing Intel Bridge
10/11/2022 03:27:42 PM Authenticating client 041aaaf2e0514977aed5f8980e65f56d to Falcon API
10/11/2022 03:27:43 PM Authenticating user crowdstrike@azuretwo.cheeworld.com to Zscaler API
10/11/2022 03:27:46 PM Starting Pull/Prepare/Push Loop # 1 With new indicators
10/11/2022 03:27:46 PM Confirming URL category CrowdStrike Malicious URLs - High exists
10/11/2022 03:27:48 PM Validated URL category CrowdStrike Malicious URLs - High
10/11/2022 03:27:48 PM [Falcon API] Getting new Indicators
10/11/2022 03:27:49 PM [Falcon API] responded with 10000 Indicators
10/11/2022 03:27:49 PM Preparing Indicators for Zscaler API
10/11/2022 03:27:49 PM Successfully prepared 9922 Indicators for Zscaler API
10/11/2022 03:27:49 PM [Zscaler API] Beginning URL look up loop
====================Zscaler API URL Lookup====================
//////////// Looking up URLs in indicator chunk 3/100 qty: 100..

View URL Category

The custom URL category should be populated with updated Indicators of Compromise (IOC) IP addresses and URLs

Sandbox

It’s possible to submit files to the Zscaler sandbox directly through an API call. This requires a different API from the API used for the other use cases. To enable the API a help desk ticket must be created at https://help.zscaler.com/submit-ticket. This should be a provisioning ticket requesting enablement of the Sandbox API. Once this is enabled the following should be available in the ZIA Admin portal at Administration > Cloud Service API Key Management. This is shown below.

Submission

Once Sandbox API has been enabled, use the steps below to submit a file. This is shown as a quick way to import files that can easily be added into a broader script. It should be noted that this could also be done via Postman.

  1. Open a command prompt
  2. Navigate to the directory where the potentially malicious file exists
  3. Copy the sandbox API token. Notice that the baseURL to be entered is shown as well.

  1. Use the curl command to send a file to the sandbox using the following command where the correct cloud should be chose (zscalertwo is shown below) and the correct API token used (xxxxxx is shown below)

Curl -k --location —-request POST “https://csbapi.zscalertwo.net/zscsb/submit?force=0&api_token=xxxxxx” —-data-binary @speedtest-results.csv

An example is shown below. Notice the MD5 hash that is provided in the results. This will be used when obtaining the results from the Sandbox detonation.

computer% curl -k --location --request POST "https://csbapi.zscalertwo.net/zscsb/submit?force=0&api_token=AdSqt78bhWGKMMd/LnWnLjkju1N3Gh6ZCrYxQs/KkhW7" --data-binary @putty.exe           
{
	"code": 200,
	"message": "/submit response OK",
	"fileType": "exe64",
	"md5": "E32F72E15F78347C51C4CA1B2847F667",
	"sandboxSubmission": "Submitted to Sandbox"
}%

Results with Postman

The results can be obtained via an API call. We will use Postman as an example. This assumes that the Postman is set up based on the Postman section above.

  1. Open Postman
  2. Authenticate using the API Authentication > Authenticate - Post

  1. Navigate to Sandbox Report > Sandbox report - Get full
  2. Add the MD5 from the submission to the URL after {{url}}/sandbox/report/

  1. Click Send
  2. View the results similar to below

Sandbox Report with pyZscaler

The Sandbox results can also be obtained using pyZscaler. This script highlights the ability to interactively ask for input from the user when the script is run.

Script

from pyzscaler.zia import ZIA
from pprint import pprint
import os
 
if os.environ.get('ZIA_USERNAME') is not None:
    zia_username = os.environ.get('ZIA_USERNAME')
else:
    print("ZIA_USERNAME environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_PASSWORD') is not None:
    zia_password = os.environ.get('ZIA_PASSWORD')
else:
    print("ZIA_PASSWORD environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_API_KEY') is not None:
    zia_api_key = os.environ.get('ZIA_API_KEY')
else:
    print("ZIA_API_KEY environment variable does not exist. Please create it.")
    sys.exit(1)
 
if os.environ.get('ZIA_CLOUD') is not None:
    zia_cloud = os.environ.get('ZIA_CLOUD')
else:
    print("ZIA_CLOUD environment variable does not exist. Please create it.")
    sys.exit(1)
 
 
md5 = input("Enter the Sandbox file MD5: ")
with ZIA(api_key=zia_api_key, cloud=zia_cloud, username=zia_username, password=zia_password) as zia:
  result = zia.sandbox.get_report(md5)
  print (result)

Script Output

python3 get-sandbox-summary-report.pl
Enter the Sandbox file MD5: E32F72E15F78347C51C4CA1B2847F667
{'summary': {'summary': {'status': 'COMPLETED', 'category': 'EXECS', 'file_type': 'EXE64', 'start_time': 1653641328, 'duration': 441703}, 'classification': {'type': 'BENIGN', 'category': 'BENIGN', 'score': 0, 'detected_malware': ''}, 'file_properties': {'file_type': 'EXE64', 'file_size': 1449256, 'md5': 'e32f72e15f78347c51c4ca1b2847f667', 'sha1': 'de8b253c8aee745fdb082fec5ad0618c2e4cdb92', 'sha256': '341cb4515476007153b7f17212f5e4476852837a031efedd5a4adea723c0bcbe', 'issuer': '/C=GB/O=Sectigo Limited/CN=Sectigo Public Code Signing CA R36/C=GB/ST=Cambridgeshire/O=Simon Tatham/CN=Simon Tatham', 'digital_cerificate': '/C=GB/ST=Cambridgeshire/O=Simon Tatham/CN=Simon Tatham', 'ss_deep': '24576:xlU74/s8CUCfJdjgqsLqf3ZfMmVcX3hmyaadfkzrS4LcNcts2g2cKjTeqbGDGOrT:xKc0rJdjgqsLqf3ZfM0Pa5kLLcatsXk+', 'root_ca': '/C=GB/O=Sectigo Limited/CN=Sectigo Public Code Signing CA R36/C=GB/ST=Cambridgeshire/O=Simon Tatham/CN=Simon Tatham'}}}

Summary

This guide has provided an introduction on how to use APIs with Zscaler ZIA. Postman was used as a low barrier to entry method of running the APIs and seeing the results within an easy to use framework. For organizations looking to meet automation and integration requirements, it was shown how to take the Postman API calls and create Python snippets that can be incorporated into larger, more comprehensive Python script. Finally, the use of the pyZscaler SDK was introduced as means of creating Python scripts in a simplified manner that also improved security by using a best practices methodology for direct API calls. As a bonus extra, additional information was provided to submit files to the ZIA Sandbox and retrieve Sandbox reports. Also, included were the steps to integrate the Crowdstrike Threat Intelligence into ZIA.

Organizations can use this guide as a first step towards automation, orchestration, and integration goals with Zscaler Internet Access (ZIA). The example scripts provide a good starting point for creating custom scripts to meet business and technical requirements. As sophistication grows, organizations may also be interested in how to use Terraform to automate and orchestrate the ZIA configuration. This will be explored in a future guide.

References

Documentation References

Zscaler ZIA API Documentation

Use Cases

Crowdstrike Integration

Github Link to Configuration

pyZscaler SDK

Library Reference

User Documentation

Github Repository

Integrated Development Environments (IDEs)

PyCharm

Articles

Setting environment variables

Cloud sandbox example

2 Likes