-> Disclaimer: Please refer to our General Support Statement before proceeding with the use of this provider. You can also refer to our troubleshooting guide for guidance on typical problems.
- Release status
- Need help?
- Getting Started
- Authentication
- OneAPI New Framework
- Legacy API Framework
- Usage guide
- Configuration reference
- Pagination
- Contributing
This repository contains the ZIA/ZPA/ZDX/ZCC/ZCON SDK for Golang. This SDK can be used in your server-side code to interact with the Zscaler platform
This SDK is designed to support the new Zscaler API framework OneAPI via a single OAuth2 HTTP client. The SDK is also backwards compatible with the previous Zscaler API framework, and each package is supported by an individual and robust HTTP client designed to handle failures on different levels by performing intelligent retries.
This library uses semantic versioning and updates are posted in (release notes) |
Version | Status |
---|---|
1.x | |
2.x | |
3.x | ✔️ Release (migration guide) |
The latest release can always be found on the (releases page)
If you run into problems, please refer to our General Support Statement before proceeding with the use of this SDK. You can also refer to our troubleshooting guide for guidance on typical problems. You can also raise an issue via (github issues page)
The SDK is compatible with Go version 1.18.x and up. You must use Go Modules to install the SDK.
To install the Zscaler GO SDK in your project:
- Create a module file by running
go mod init
- You can skip this step if you already use
go mod
- Run
go get github.com/zscaler/zscaler-sdk-go/v3@latest
. This will add the SDK to yourgo.mod
file. - Import the package in your project with
import "github.com/zscaler/zscaler-sdk-go/v3/zscaler"
.
-
An administrator account in the Zscaler products you want to interact with.
-
OneAPI: If using the OneAPI entrypoint you must have a API Client created in the Zidentity platform
-
Legacy Framework: If using the legacy API framework you must have API Keys credentials in the the respective Zscaler cloud products.
-
For more information on getting started with Zscaler APIs visit one of the following links:
The latest versions => 3.x of this SDK provides dual API client capability and can be used to interact both with new Zscaler OneAPI framework and the legacy API platform.
Versions of this SDK <= v2.x only support the legacy API platform. If your Zscaler tenant has not been migrated to the new Zscaler Zidentity platform.
If your organization is not ready to move into the Zidentity platform, this SDK can be configured for backwards compatibility by leveraging a built-in attribuite called use_legacy_client
or environment variable ZSCALER_USE_LEGACY_CLIENT
.
As of the publication of SDK version => 3.x, OneAPI is available for programmatic interaction with the following products:
NOTE All other products succh as Zscaler Cloud Connector (ZCON) and Zscaler Digital Experience (ZDX) are supported only via the legacy authentication method described in this README.
OneAPI Resources are automatically created within the ZIdentity Admin UI based on the RBAC Roles
applicable to APIs within the various products. For example, in ZIA, navigate to Administration -> Role Management
and select Add API Role
.
Once this role has been saved, return to the ZIdentity Admin UI and from the Integration menu
select API Resources. Click the View
icon to the right of Zscaler APIs and under the ZIA
dropdown you will see the newly created Role. In the event a newly created role is not seen in the
ZIdentity Admin UI a Sync Now
button is provided in the API Resources menu which will initiate an
on-demand sync of newly created roles.
You can provide credentials via the ZSCALER_CLIENT_ID
, ZSCALER_CLIENT_SECRET
, ZSCALER_VANITY_DOMAIN
, ZSCALER_CLOUD
environment variables, representing your Zidentity OneAPI credentials clientId
, clientSecret
, vanityDomain
and cloud
respectively.
Argument | Description | Environment variable |
---|---|---|
clientId |
(String) Zscaler API Client ID, used with clientSecret or PrivateKey OAuth auth mode. |
ZSCALER_CLIENT_ID |
clientSecret |
(String) A string that contains the password for the API admin. | ZSCALER_CLIENT_SECRET |
privateKey |
(String) A string Private key value. | ZSCALER_PRIVATE_KEY |
vanityDomain |
(String) Refers to the domain name used by your organization https://<vanity_domain>.zslogin.net/oauth2/v1/token |
ZSCALER_VANITY_DOMAIN |
cloud |
(String) The host and basePath for the cloud services API is $api.<cloud_name>.zsapi.net . |
ZSCALER_CLOUD |
OneAPI supports authentication and can interact with alternative Zscaler enviornments i.e beta
, alpha
etc. To authenticate to these environments you must provide the following values:
Argument | Description | Environment variable |
---|---|---|
vanityDomain |
(String) Refers to the domain name used by your organization https://<vanity_domain>.zslogin.net/oauth2/v1/token |
ZSCALER_VANITY_DOMAIN |
cloud |
(String) The host and basePath for the cloud services API is $api.<cloud_name>.zsapi.net . |
ZSCALER_CLOUD |
For example: Authenticating to Zscaler Beta environment:
export ZSCALER_VANITY_DOMAIN="acme"
export ZSCALER_CLOUD="beta"
Note: By default this SDK will send the authentication request and subsequent API calls to the default base URL.
The authentication to Zscaler Private Access (ZPA) via the OneAPI framework, requires the extra attribute called customerId
and optionally the attribute microtenantId
.
Argument | Description | Environment variable |
---|---|---|
clientId |
(String) Zscaler API Client ID, used with clientSecret or PrivateKey OAuth auth mode. |
ZSCALER_CLIENT_ID |
clientSecret |
(String) A string that contains the password for the API admin. | ZSCALER_CLIENT_SECRET |
privateKey |
(String) A string Private key value. | ZSCALER_PRIVATE_KEY |
customerId |
(String) The ZPA tenant ID found under Configuration & Control > Public API > API Keys menu in the ZPA console. | ZPA_CUSTOMER_ID |
microtenantId |
(String) The ZPA microtenant ID found in the respective microtenant instance under Configuration & Control > Public API > API Keys menu in the ZPA console. | ZPA_MICROTENANT_ID |
vanityDomain |
(String) Refers to the domain name used by your organization https://<vanity_domain>.zslogin.net/oauth2/v1/token |
ZSCALER_VANITY_DOMAIN |
cloud |
(String) The host and basePath for the cloud services API is $api.<cloud_name>.zsapi.net . |
ZSCALER_CLOUD |
Construct a client instance by passing it your Zidentity ClientID, ClientSecret and VanityDomain:
import (
"fmt"
"context"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
)
func main() {
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme")
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
}
Construct a client instance by passing it your Zidentity ClientID, PrivateKey and VanityDomain:
import (
"fmt"
"context"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
)
func main() {
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithPrivateKey("private_key.pem"),
zscaler.WithVanityDomain("acme")
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
}
Hard-coding the Zscaler clientID and clientSecret works for quick tests, but for real projects you should use a more secure way of storing these values (such as environment variables). This library supports a few different configuration sources, covered in the configuration reference section.
These examples will help you understand how to use this library. You can also browse the full API reference documentation.
Once you initialize a client
, you can call methods to make requests to the
Zscaler API. Most methods are grouped by the API endpoint they belong to.
In the default configuration the client utilizes a memory cache that has a time
to live on its cached values. See Configuration Setter
Object WithCache(cache bool)
,
WithCacheTtl(i int32)
, and WithCacheTti(i int32)
. This helps to
keep HTTP requests to the Zscaler API at a minimum. In the case where the client
needs to be certain it is accessing recent data; for instance, list items,
delete an item, then list items again; be sure to make use of the refresh next
facility to clear the request cache. To completely disable the request
memory cache configure the client with WithCache(false)
.
By default this SDK retries requests that are returned with a 429 exception. To
disable this functionality set ZSCALER_CLIENT_REQUEST_TIMEOUT
and
ZSCALER_CLIENT_RATE_LIMIT_MAX_RETRIES
to 0
.
Setting only one of the values to zero disables that check. Meaning, by
default, four retry attempts will be made. If you set
ZSCALER_CLIENT_REQUEST_TIMEOUT
to 45 seconds and
ZSCALER_CLIENT_RATE_LIMIT_MAX_RETRIES
to 0
. This SDK will continue to retry
indefinitely for 45 seconds. If both values are non zero, this SDK attempts to
retry until either of the conditions are met (not both).
We use the Date header from the server to calculate the delta, as it's more reliable than system time. But always add 1 second to account for some clock skew in our service:
backoff_seconds = header['X-Rate-Limit-Reset'] - header['Date'] + 1s
If the backoff_seconds
calculation exceeds the request timeout, the initial
429 response will be allowed through without additional attempts.
When creating your client, you can pass in these settings like you would with any other configuration.
import (
"fmt"
"context"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
)
func main() {
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme")
zscaler.WithRequestTimeout(45),
zscaler.WithRateLimitMaxRetries(3),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
client := zscaler.NewOneAPIClient(config)
}
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa/services/scimgroup"
)
func main() {
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme"),
zscaler.WithZPACustomerID("12354547545"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating OneAPI client: %v", err)
}
ctx := context.Background()
idp_Id := "216196257331285825"
allGroups, resp, err := scimgroup.GetAllByIdpId(ctx, service, idp_Id)
if err != nil {
log.Fatalf("Error Getting Groups: %v", err)
}
fmt.Printf("Groups: %+v\n Response: %+v\n\n", allGroups, resp)
for index, user := range allGroups {
fmt.Printf("Group %d: %+v\n", index, user)
}
}
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa/services/scimgroup"
)
func main() {
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme"),
zscaler.WithZPACustomerID("12354547545"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating OneAPI client: %v", err)
}
ctx := context.Background()
groupID := "1405240"
allGroups, _, err := scimgroup.Get(ctx, service, groupID)
if err != nil {
log.Fatalf("Error retrieving scim group: %v", err)
}
fmt.Printf("Successfully retrieved SCIM group: %+v\n", allGroups)
}
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa/services/segmentgroup"
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
)
func main() {
name := "tests-" + acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme"),
zscaler.WithZPACustomerID("12354547545"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating OneAPI client: %v", err)
}
ctx := context.Background()
newGroup := &segmentgroup.SegmentGroup{
Name: name,
Description: name,
Enabled: true,
}
createdGroup, _, err := segmentgroup.Create(ctx, service, newGroup)
if err != nil {
log.Fatalf("Error creating segment group: %v", err)
}
fmt.Printf("Successfully created segment group: ID: %s, Name: %s\n", createdGroup.ID, createdGroup.Name)
}
func main() {
name := "tests-" + acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme"),
zscaler.WithZPACustomerID("12354547545"),
)
if err != nil {
log.Fatalf("Error creating configuration: %v", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating OneAPI client: %v", err)
}
ctx := context.TODO()
groupID := "5448754152554"
groupToUpdate, resp, err := segmentgroup.Get(ctx, service, groupID)
if err != nil {
log.Fatalf("Error fetching group to update: %v", err)
}
fmt.Printf("Group to update: %+v\n Response: %+v\n\n", groupToUpdate, resp)
updateGroup := &segmentgroup.SegmentGroup{
Name: name + "-updated2",
}
updatedGroup, err := segmentgroup.UpdateV2(ctx, service, groupToUpdate.ID, updateGroup)
if err != nil {
log.Fatalf("Error updating group: %v", err)
}
fmt.Printf("Updated Group: %+v\n Response: %+v\n\n", updatedGroup, resp)
}
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zia/services/rule_labels"
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
)
func main() {
name := "tests-" + acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating OneAPI client: %v", err)
}
ctx := context.Background()
newLabel := &rule_labels.RuleLabels{
Name: name,
Description: name,
}
createdLabel, _, err := rule_labels.Create(ctx, service, newLabel)
if err != nil {
log.Fatalf("Error creating rule label: %v", err)
}
fmt.Printf("Successfully created rule label: ID: %d, Name: %s\n", createdLabel.ID, createdLabel.Name)
}
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zia/services/rule_labels"
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
)
func main() {
name := "tests-" + acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating OneAPI client: %v", err)
}
ctx := context.TODO()
labelID := 2073922
labelToUpdate, err := rule_labels.Get(ctx, service, labelID)
if err != nil {
log.Fatalf("Error fetching label to update: %v", err)
}
fmt.Printf("Label to update: %+v\n", labelToUpdate)
updateLabel := &rule_labels.RuleLabels{
Name: name + "-updated2",
}
updatedLabel, resp, err := rule_labels.Update(ctx, service, labelToUpdate.ID, updateLabel)
if err != nil {
log.Fatalf("Error updating label: %v", err)
}
fmt.Printf("Updated Label: %+v\n Response: %+v\n\n", updatedLabel, resp)
}
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zcc/services/devices"
)
func main() {
config, err := zscaler.NewConfiguration(
zscaler.WithClientID(""),
zscaler.WithClientSecret(""),
zscaler.WithVanityDomain("acme"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating OneAPI client: %v", err)
}
ctx := context.Background()
username := ""
osType := ""
listDevices, err := devices.GetAll(ctx, service, username, osType)
if err != nil {
log.Fatalf("Error listing devices: %v", err)
}
fmt.Printf("Devices: %+v\n", listDevices)
for index, user := range listDevices {
fmt.Printf("Device %d: %+v\n", index, user)
}
}
This library looks for configuration in the following sources:
- An
zscaler.yaml
file in a.zscaler
folder in the current user's home directory (~/.zscaler/zscaler.yaml
or%userprofile\.zscaler\zscaler.yaml
) - A
.zscaler.yaml
file in the application or project's root directory - Environment variables
- Configuration explicitly passed to the constructor (see the example in Getting started)
Higher numbers win. In other words, configuration passed via the constructor
will override configuration found in environment variables, which will override
configuration in zscaler.yaml
(if any), and so on.
When you use OneAPI OAuth 2.0 the full YAML configuration looks like:
zscaler:
client:
clientId: "{yourClientId}"
clientSecret: "{yourClientSecret}"
vanityDomain: "{yourVanityDomain}"
customerId: "{yourZpaCustomerId}" # Required if interacting with ZPA Service
connectionTimeout: 30 # seconds
requestTimeout: 0 # seconds
rateLimit:
maxRetries: 4
proxy:
port: null
host: null
username: null
password: null
When you use OneAPI OAuth 2.0 with private key, the full YAML configuration looks like:
zscaler:
client:
clientId: "{yourClientId}"
privateKey: | # THIS IS AN EXAMPLE OF A PARTIAL PRIVATE KEY. NOT USED IN PRODUCTION
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAl4F5CrP6Wu2kKwH1Z+CNBdo0iteHhVRIXeHdeoqIB1iXvuv4
THQdM5PIlot6XmeV1KUKuzw2ewDeb5zcasA4QHPcSVh2+KzbttPQ+RUXCUAr5t+r
0r6gBc5Dy1IPjCFsqsPJXFwqe3RzUb...
-----END RSA PRIVATE KEY-----
vanityDomain: "{yourVanityDomain}"
customerId: "{yourZpaCustomerId}" # Required if interacting with ZPA Service
connectionTimeout: 30 # seconds
requestTimeout: 0 # seconds
rateLimit:
maxRetries: 4
proxy:
port: null
host: null
username: null
password: null
Each one of the configuration values above can be turned into an environment
variable name with the _
(underscore) character:
ZSCALER_CLIENT_ID
ZSCALER_CLIENT_SECRET
- and so on
The client is configured with a configuration setter object passed to the NewOneAPIClient
function.
function | description |
---|---|
WithClientID(clientId string) | OneAPI Client ID |
WithClientSecret(clientSecret string) | OneAPI Client Secret |
WithPrivateKey(privateKey string) | OneAPI Private key value |
WithVanityDomain(vanityDomain string) | The domain name used by your organization |
WithZscalerCloud(cloud string) | The alternative Zscaler cloud name for your organization i.e beta |
WithSandboxToken(sandboxToken string) | The Zscaler Internet Access Sandbox Token |
WithSandboxCloud(sandboxCloud string) | The Zscaler Internet Access Sandbox cloud name |
WithZPACustomerID(customerId string) | The ZPA tenant ID |
WithZPAMicrotenantID(microtenantId string) | The ZPA Microtenant ID |
WithUserAgentExtra(userAgent string) | Append additional information to the HTTP User-Agent |
WithCache(cache bool) | Use request memory cache |
WithCacheManager(cacheManager cache.Cache) | Use custom cache object that implements the cache.Cache interface |
WithCacheTtl(i int32) | Cache time to live in seconds |
WithCacheTti(i int32) | Cache clean up interval in seconds |
WithProxyPort(i int32) | HTTP proxy port |
WithProxyHost(host string) | HTTP proxy host |
WithProxyUsername(username string) | HTTP proxy username |
WithProxyPassword(pass string) | HTTP proxy password |
WithHttpClient(httpClient http.Client) | Custom net/http client |
WithHttpClientPtr(httpClient *http.Client) | pointer to custom net/http client |
WithTestingDisableHttpsCheck(httpsCheck bool) | Disable net/http SSL checks |
WithRequestTimeout(requestTimeout int64) | HTTP request time out in seconds |
WithRateLimitMaxRetries(maxRetries int32) | Max number of request retries when http request times out |
WithRateLimitMaxWait(maxWait int32) | Max wait time to wait before next retry |
WithRateLimitMinWait(minWait int32) | Min wait time to wait before next retry |
WithDebug(debug int32) | Enable debug mode for troubleshooting |
The Zscaler Client's base configuration starts at
config setting |
---|
WithConnectionTimeout(60) |
WithCache(true) |
WithCacheTtl(300) |
WithCacheTti(300) |
WithUserAgentExtra("") |
WithTestingDisableHttpsCheck(false) |
WithRequestTimeout(0) |
WithRateLimitMaxRetries(2) |
Every method that calls the API now has the ability to pass context.Context
to it as the first parameter. If you do not have a context or do not know which
context to use, you can pass context.TODO()
to the methods.
- For authentication via Zscaler Internet Access, you must provide
username
,password
,api_key
andcloud
The ZIA Cloud is identified by several cloud name prefixes, which determines which API endpoint the requests should be sent to. The following cloud environments are supported:
zscaler
zscalerone
zscalertwo
zscalerthree
zscloud
zscalerbeta
zscalergov
zscalerten
zspreview
You can provide credentials via the ZIA_USERNAME
, ZIA_PASSWORD
, ZIA_API_KEY
, ZIA_CLOUD
environment variables, representing your ZIA username
, password
, api_key
and cloud
respectively.
Argument | Description | Environment variable |
---|---|---|
username |
(String) A string that contains the email ID of the API admin. | ZIA_USERNAME |
password |
(String) A string that contains the password for the API admin. | ZIA_PASSWORD |
api_key |
(String) A string that contains the obfuscated API key (i.e., the return value of the obfuscateApiKey() method). | ZIA_API_KEY |
cloud |
(String) The host and basePath for the cloud services API is $zsapi.<Zscaler Cloud Name>/api/v1 . |
ZIA_CLOUD |
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zia"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zia/services/rule_labels"
)
func main() {
username := os.Getenv("ZIA_USERNAME")
password := os.Getenv("ZIA_PASSWORD")
apiKey := os.Getenv("ZIA_API_KEY")
ziaCloud := os.Getenv("ZIA_CLOUD")
ziaCfg, err := zia.NewConfiguration(
zia.WithZiaUsername(username),
zia.WithZiaPassword(password),
zia.WithZiaAPIKey(apiKey),
zia.WithZiaCloud(ziaCloud),
zia.WithDebug(true),
)
if err != nil {
log.Fatalf("Error creating ZPA configuration: %v", err)
}
// Initialize ZPA client
service, err := zscaler.NewLegacyZiaClient(ziaCfg)
if err != nil {
log.Fatalf("Error creating ZIA client: %v", err)
}
// Create a new context
ctx := context.Background()
labels, err := rule_labels.GetAll(ctx, service)
if err != nil {
log.Fatalf("Error Listing Labels: %v", err)
}
fmt.Printf("Labels: %+v\n", labels)
for index, label := range labels {
fmt.Printf("Label %d: %+v\n", index, label)
}
}
For authentication via Zscaler Private Access, you must provide client_id
, client_secret
, customer_id
and cloud
The ZPA Cloud is identified by several cloud name prefixes, which determines which API endpoint the requests should be sent to. The following cloud environments are supported:
PRODUCTION
ZPATWO
BETA
GOV
GOVUS
You can provide credentials via the ZPA_CLIENT_ID
, ZPA_CLIENT_SECRET
, ZPA_CUSTOMER_ID
, ZPA_CLOUD
environment variables, representing your ZPA client_id
, client_secret
, customer_id
and cloud
of your ZPA account, respectively.
~> NOTE ZPA_CLOUD
environment variable is required, and is used to identify the correct API gateway where the API requests should be forwarded to.
Argument | Description | Environment variable |
---|---|---|
client_id |
(String) The ZPA API client ID generated from the ZPA console. | ZPA_CLIENT_ID |
client_secret |
(String) The ZPA API client secret generated from the ZPA console. | ZPA_CLIENT_SECRET |
customer_id |
(String) The ZPA tenant ID found in the Administration > Company menu in the ZPA console. | ZPA_CUSTOMER_ID |
cloud |
(String) The Zscaler cloud for your tenancy. | ZPA_CLOUD |
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa/services/segmentgroup"
)
func main() {
clientID := os.Getenv("ZPA_CLIENT_ID")
clientSecret := os.Getenv("ZPA_CLIENT_SECRET")
customerID := os.Getenv("ZPA_CUSTOMER_ID")
cloud := os.Getenv("ZPA_CLOUD")
zpaCfg, err := zpa.NewConfiguration(
zpa.WithZPAClientID(clientID),
zpa.WithZPAClientSecret(clientSecret),
zpa.WithZPACustomerID(customerID),
zpa.WithZPACloud(cloud),
)
if err != nil {
log.Fatalf("Error creating ZPA configuration: %v", err)
}
// Initialize ZPA client
service, err := zscaler.NewLegacyZpaClient(zpaCfg)
if err != nil {
log.Fatalf("Error creating ZPA client: %v", err)
}
ctx := context.Background()
groups, resp, err := segmentgroup.GetAll(ctx, service)
if err != nil {
log.Fatalf("Error list all segment group: %v", err)
}
fmt.Printf("Groups: %+v\n Response: %+v\n\n", groups, resp)
for index, group := range groups {
fmt.Printf("Group %d: %+v\n", index, group)
}
}
This SDK supports direct interaction with the ZPA SCIM API endpoints. The SCIM APIs allow you to use custom SCIM clients to make REST API calls to Zscaler. The same way as the regular ZPA API All SCIM APIs are rate limited. For more details About SCIM APIs
The ZPA Cloud is identified by several cloud name prefixes, which determines which API endpoint the requests should be sent to. The following cloud environments are supported:
PRODUCTION
ZPATWO
BETA
GOV
GOVUS
You can provide credentials via the ZPA_SCIM_TOKEN
, ZPA_IDP_ID
, ZPA_SCIM_CLOUD
environment variables, representing your ZPA scimToken
, idpId
, and baseURL
of your ZPA account, respectively.
~> NOTE ZPA_SCIM_CLOUD
environment variable is only required when required when authenticating to a ZPA environment other than production. This environment variable is used to identify the correct API gateway where the API requests should be forwarded to.
Argument | Description | Environment variable |
---|---|---|
scimToken |
(String) A string that contains the ZPA SCIM API Token | ZPA_SCIM_TOKEN |
idpId |
(String) A string that contains the ZPA Identity Provider ID | ZPA_IDP_ID |
baseURL |
(String) A string that contains the ZPA cloud environment name | ZPA_SCIM_CLOUD |
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa/services/scim_api"
)
func main() {
scimToken := os.Getenv("ZPA_SCIM_TOKEN")
idpId := os.Getenv("ZPA_IDP_ID")
scimCloud := os.Getenv("ZPA_SCIM_CLOUD")
scimClient, err := zpa.NewScimConfig(
zpa.WithScimToken(scimToken),
zpa.WithIDPId(idpId),
zpa.WithScimCloud(scimCloud),
)
if err != nil {
log.Fatalf("failed to create SCIM client: %v", err)
}
service := zscaler.NewScimService(scimClient)
ctx := context.Background()
groups, _, err := scim_api.GetAllGroups(ctx, service)
if err != nil {
log.Fatalf("Error retrieving SCIM groups: %v", err)
}
log.Printf("Retrieved SCIM Groups: %+v\n", groups)
}
For authentication via Zscaler Client Connector (Mobile Portal), you must provide APIKey
, SecretKey
, cloudEnv
The ZCC Cloud is identified by several cloud name prefixes, which determines which API endpoint the requests should be sent to. The following cloud environments are supported:
zscaler
zscalerone
zscalertwo
zscalerthree
zscloud
zscalerbeta
zscalergov
zscalerten
zspreview
You can provide credentials via the ZCC_CLIENT_ID
, ZCC_CLIENT_SECRET
, ZCC_CLOUD
environment variables, representing your ZCC APIKey
, SecretKey
, and cloudEnv
of your ZCC account, respectively.
~> NOTE ZCC_CLOUD
environment variable is required, and is used to identify the correct API gateway where the API requests should be forwarded to.
Argument | Description | Environment variable |
---|---|---|
APIKey |
(String) A string that contains the apiKey for the Mobile Portal. | ZCC_CLIENT_ID |
SecretKey |
(String) A string that contains the secret key for the Mobile Portal. | ZCC_CLIENT_SECRET |
cloudEnv |
(String) The host and basePath for the ZCC cloud services API is $mobileadmin.<Zscaler Cloud Name>/papi . |
ZCC_CLOUD |
import (
"context"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zcc"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zcc/services/devices"
)
func main() {
clientID := os.Getenv("ZCC_CLIENT_ID")
clientSecret := os.Getenv("ZCC_CLIENT_SECRET")
cloud := os.Getenv("ZCC_CLOUD")
zccCfg, err := zcc.NewConfiguration(
zcc.WithZCCClientID(clientID),
zcc.WithZCCClientSecret(clientSecret),
zcc.WithZCCCloud(cloud),
)
if err != nil {
log.Fatalf("Error creating ZCC configuration: %v", err)
}
// Initialize ZPA client
service, err := zscaler.NewLegacyZccClient(zpaCfg)
if err != nil {
log.Fatalf("Error creating ZCC client: %v", err)
}
ctx := context.TODO()
username := "[email protected]"
osType := "3"
listDevices, err := devices.GetAll(ctx, service, username, osType)
if err != nil {
log.Fatalf("Error listing devices: %v", err)
}
for _, device := range listDevices {
log.Printf("Device: %+v\n", device)
}
}
- For authentication via Zscaler Client Connector, you must provide
username
,password
,api_key
andcloud
The ZCON Cloud is identified by several cloud name prefixes, which determines which API endpoint the requests should be sent to. The following cloud environments are supported:
zscaler
zscalerone
zscalertwo
zscalerthree
zscloud
zscalerbeta
zscalergov
zscalerten
zspreview
You can provide credentials via the ZCON_USERNAME
, ZCON_PASSWORD
, ZCON_API_KEY
, ZCON_CLOUD
environment variables, representing your ZCON username
, password
, api_key
and cloud
respectively.
Argument | Description | Environment variable |
---|---|---|
username |
(String) A string that contains the email ID of the API admin. | ZCON_USERNAME |
password |
(String) A string that contains the password for the API admin. | ZCON_PASSWORD |
api_key |
(String) A string that contains the obfuscated API key (i.e., the return value of the obfuscateApiKey() method). | ZCON_API_KEY |
cloud |
(String) The host and basePath for the cloud services API is $connector.<Zscaler Cloud Name>/api/v1 . |
ZCON_CLOUD |
NOTE: The Zscaler Cloud Connector (ZCON) API Client instantiation DOES NOT require the use of the the useLegacyClient
attribute.
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zcon"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zcon/services"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zcon/services/locationmanagement/location"
)
func main() {
username := os.Getenv("ZCON_USERNAME")
password := os.Getenv("ZCON_PASSWORD")
apiKey := os.Getenv("ZCON_API_KEY")
zconCloud := os.Getenv("ZCON_CLOUD")
zconCfg, err := zcon.NewConfiguration(
zcon.WithZconUsername(username),
zcon.WithZconPassword(password),
zcon.WithZconAPIKey(apiKey),
zcon.WithZconCloud(zconCloud),
zcon.WithDebug(true),
)
if err != nil {
log.Fatalf("Error creating ZCON configuration: %v", err)
}
zconClient, err := zcon.NewClient(zconCfg)
if err != nil {
log.Fatalf("Failed to create ZCON client: %v", err)
}
service := services.New(zconClient)
ctx := context.Background()
locations, err := location.GetAll(ctx, service)
if err != nil {
log.Fatalf("Error listing locations: %v", err)
}
fmt.Printf("Locations: %+v\n", locations)
for index, location := range locations {
fmt.Printf("Location %d: %+v\n", index, location)
}
}
For authentication via Zscaler Digital Experience (ZDX), you must provide APIKeyID
, SecretKey
The ZDX Cloud is identified by several cloud name prefixes, which determines which API endpoint the requests should be sent to.
You can provide credentials via the ZDX_API_KEY_ID
, ZDX_API_KEY_ID
environment variables, representing your ZDX APIKey
, SecretKey
of your ZDX account, respectively.
Argument | Description | Environment variable |
---|---|---|
APIKey |
(String) A string that contains the apiKey for the ZDX Portal. | ZDX_API_KEY_ID |
SecretKey |
(String) A string that contains the secret key for the ZDX Portal. | ZDX_API_KEY_ID |
NOTE: The Zscaler Digital Experience (ZDX) API Client instantiation DOES NOT require the use of the the useLegacyClient
attribute.
import (
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zdx"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zdx/services"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zdx/services/common"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zdx/services/reports/applications"
)
func main() {
apiKey := os.Getenv("ZDX_API_KEY_ID")
secretKey := os.Getenv("ZDX_API_SECRET")
cloud := os.Getenv("ZDX_CLOUD") // Optional
zdxCfg, err := zdx.NewConfiguration(
zdx.WithZDXAPIKeyID(apiKey),
zdx.WithZDXAPISecret(secretKey),
zdx.WithZDXCloud(cloud),
zdx.WithDebug(true),
)
if err != nil {
log.Fatalf("Error creating ZDX configuration: %v", err)
}
zdxClient, err := zdx.NewClient(zdxCfg)
if err != nil {
log.Fatalf("Error creating ZDX client: %v", err)
}
service := services.New(zdxClient)
filters := common.GetFromToFilters{
From: 0, // Start time in epoch seconds (optional)
To: 0, // End time in epoch seconds (optional)
}
apps, resp, err := applications.GetAllApps(service, filters)
if err != nil {
log.Fatalf("Error retrieving applications: %v", err)
}
log.Printf("Successfully retrieved %d applications.\n", len(apps))
log.Printf("HTTP Response: %v\n", resp.Status)
for _, app := range apps {
log.Printf("Application Name: %s, ZDX Score: %.2f\n", app.Name, app.Score)
}
}
For authentication via Zscaler Workflow Automation (ZWA), you must provide key_id
, key_secret
The ZWA Cloud is identified by several cloud name prefixes, which determines which API endpoint the requests should be sent to.
You can provide credentials via the ZWA_API_KEY_ID
, ZWA_API_SECRET
environment variables, representing your ZDX key_id
, key_secret
of your ZWA account, respectively.
Argument | Description | Environment variable |
---|---|---|
key_id |
(String) The ZWA string that contains the API key ID. | ZWA_API_KEY_ID |
key_secret |
(String) The ZWA string that contains the key secret. | ZWA_API_SECRET |
cloud |
(String) The ZWA string containing cloud provisioned for your organization. | ZWA_CLOUD |
NOTE: The Zscaler Workflow Automation (ZWA) API Client instantiation DOES NOT require the use of the the useLegacyClient
attribute.
import (
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zwa"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zwa/services"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zwa/services/dlp_incidents"
)
func main() {
key_id := os.Getenv("ZWA_API_KEY_ID")
key_secret := os.Getenv("ZWA_API_SECRET")
cloud := os.Getenv("ZWA_CLOUD") // Optional
zwaCfg, err := zwa.NewConfiguration(
zwa.WithZWAAPIKeyID(key_id),
zwa.WithZWAAPISecret(key_secret),
zwa.WithZWACloud(cloud),
zwa.WithDebug(true),
)
if err != nil {
log.Fatalf("Error creating ZWA configuration: %v", err)
}
zwaClient, err := zwa.NewClient(zwaCfg)
if err != nil {
log.Fatalf("Error creating ZWA client: %v", err)
}
service := services.New(zwaClient)
dlpIncidentID := "167867439920099003"
evidence, _, err := dlp_incidents.GetDLPIncidentTriggers(ctx, service, dlpIncidentID)
if err != nil {
log.Fatalf("Error fetching DLP incident evidence: %v", err)
}
fmt.Printf("Evidence Details: %+v\n", evidence)
}
Hard-coding any of the Zscaler API credentials works for quick tests, but for real projects you should use a more secure way of storing these values (such as environment variables). This library supports a few different configuration sources, covered in the configuration reference section.
In the default configuration the client utilizes a memory cache that has a time
to live on its cached values. See Configuration Setter
Object WithCache(cache bool)
,
WithCacheTtl(i int32)
, and WithCacheTti(i int32)
. This helps to
keep HTTP requests to the Zscaler API at a minimum. In the case where the client
needs to be certain it is accessing recent data; for instance, list items,
delete an item, then list items again; be sure to make use of the refresh next
facility to clear the request cache. To completely disable the request
memory cache configure the client with WithCache(false)
.
This SDK is designed to handle connection retries and rate limiting to ensure reliable and efficient API interactions.
By default, this SDK retries requests that receive a 429 Too Many Requests
response from the server. The retry mechanism respects the Retry-After
header provided in the response. The Retry-After
header indicates the time required to wait before another call can be made. For example, a value of 13s
in the Retry-After
header means the SDK should wait 13 seconds before retrying the request.
Additionally, the SDK uses an exponential backoff strategy for other server errors, where the wait time between retries increases exponentially up to a maximum limit. This is managed by the BackoffConfig
configuration, which specifies the following:
Enabled
: Set totrue
to enable the backoff and retry mechanism.RetryWaitMinSeconds
: Minimum time to wait before retrying a request.RetryWaitMaxSeconds
: Maximum time to wait before retrying a request.MaxNumOfRetries
: Maximum number of retries for a request.
To comply with API rate limits, the SDK includes a custom rate limiter. The rate limiter ensures that requests do not exceed the following limits:
GET
requests: Maximum 20 requests in a 10-second interval.POST
,PUT
,DELETE
requests: Maximum 10 requests in a 10-second interval.
If the request rate exceeds these limits, the SDK waits for an appropriate amount of time before proceeding with the request. The rate limiter tracks the number of requests and enforces these limits to avoid exceeding the allowed rate.
The ZIA API client in this SDK is designed to handle retries and rate limiting to ensure reliable and efficient interactions with the ZIA API.
The retry mechanism for the ZIA API client works as follows:
- The SDK retries requests that receive a
429 Too Many Requests
response or other recoverable errors. - The primary mechanism for retries leverages the
Retry-After
header included in the response from the server. This header indicates the amount of time to wait before retrying the request. If theRetry-After
header is present in the response body, it is also respected. - If the
Retry-After
header is not provided, the SDK uses an exponential backoff strategy with configurable parameters:RetryWaitMinSeconds
: Minimum time to wait before retrying a request.RetryWaitMaxSeconds
: Maximum time to wait before retrying a request.MaxNumOfRetries
: Maximum number of retries for a request.
- The SDK also includes custom handling for specific error codes and messages to decide if a retry should be attempted.
Each Zscaler service provides pagination support. The SDK independently provides pagination logic for each individual service based on its unique parameters and requirements.
The ZPA package robust support for pagination, allowing users to fetch all results for a specific API endpoint even if the data spans multiple pages. The SDK abstracts pagination, so you can fetch all records seamlessly without worrying about page-by-page API requests.
The SDK includes a generic function, GetAllPagesGenericWithCustomFilters
, which automates fetching all resources across multiple pages. Here's an example of how you can use this functionality to list SCIM groups by an IDP ID.
- Custom Filters: Use the Filter struct to refine results with parameters such as
Search
,SortBy
, andSortOrder
.
func main() {
ctx := context.Background()
idpId := "your-idp-id"
allGroups, resp, err := scimgroup.GetAllByIdpId(ctx, service, idpId)
if err != nil {
log.Fatalf("Error fetching SCIM groups: %v", err)
}
fmt.Printf("Fetched %d SCIM Groups\n", len(allGroups))
for _, group := range allGroups {
fmt.Printf("Group: %+v\n", group)
}
}
The primary pagination functions, such as GetAllPagesGenericWithCustomFilters
and GetAllPagesGeneric
, can be directly invoked to handle paginated API requests. Here’s an example of how a user could utilize these functions:
- Custom Filters: Use the Filter struct to refine results with parameters such as
Search
,SortBy
, andSortOrder
.
import (
"context"
"fmt"
"log"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa/services/common"
"github.com/zscaler/zscaler-sdk-go/v3/zscaler/zpa/services/scimgroup"
)
func main() {
// Initialize ZPA configuration
config, err := zscaler.NewConfiguration(
zscaler.WithClientID("your-client-id"),
zscaler.WithClientSecret("your-client-secret"),
zscaler.WithVanityDomain("your-vanity-domain"),
zscaler.WithZPACustomerID("your-customer-id"),
zscaler.WithDebug(true),
)
if err != nil {
log.Fatalf("Error creating configuration: %v", err)
}
service, err := zscaler.NewOneAPIClient(config)
if err != nil {
log.Fatalf("Error creating ZPA client: %v", err)
}
ctx := context.Background()
relativeURL := "/zpa/mgmtconfig/v1/admin/customers/21619xxxxxxxxxx/scimgroups/idpId/{idpId}"
// Define filters for pagination
filters := common.Filter{
SortBy: "name",
SortOrder: "ASC",
Search: "example-query",
}
// Use the generic pagination function
allGroups, resp, err := common.GetAllPagesGenericWithCustomFilters[ScimGroup](ctx, service.Client, relativeURL, filters)
if err != nil {
log.Fatalf("Error fetching paginated data: %v", err)
}
fmt.Printf("Fetched %d SCIM Groups\n", len(allGroups))
for index, group := range allGroups {
fmt.Printf("Group %d: %+v\n", index, group)
}
fmt.Printf("Response: %+v\n", resp)
}
The ZIA SDK provides pagination support tailored to its API's unique parameters. The SDK allows you to fetch large datasets across multiple pages seamlessly, using built-in utilities or customizable pagination logic.
Pagination in the ZIA service is powered by the ReadAllPages
and ReadPage
functions. These utilities enable efficient data retrieval while handling all necessary API parameters for pagination, including page size and sort options.
- Using Built-In Pagination Functions: The
ReadAllPages
function automates fetching all pages of data for a given endpoint and aggregates the results into a single slice. For example, the GetAllUsers function leveragesReadAllPages
to retrieve all users.
func GetAllUsers(ctx context.Context, service *zscaler.Service) ([]Users, error) {
var users []Users
err := common.ReadAllPages(ctx, service.Client, usersEndpoint+"?"+common.GetSortParams(common.SortField(service.SortBy), common.SortOrder(service.SortOrder)), &users)
if err != nil {
return nil, err
}
return users, nil
}
func main() {
ctx := context.Background()
// Fetch all users
allUsers, err := GetAllUsers(ctx, service)
if err != nil {
log.Fatalf("Error fetching users: %v", err)
}
fmt.Printf("Fetched %d users\n", len(allUsers))
for _, user := range allUsers {
fmt.Printf("User: %+v\n", user)
}
}
We're happy to accept contributions and PRs! Please see the contribution guide to understand how to structure a contribution.
Copyright (c) 2022 Zscaler
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.