Zscaler Private Access Terraform Provider (Unofficial)

(Unofficial) ZPA Custom Terraform Provider

In this article, I will introduce a custom terraform provider for ZPA that I’ve spent time developing during my past 6 months working at Zscaler. Now that the provider is finished and tested to be fully compatible with the ZPA API service, the GitHub repository has been made public so, customers and partners willing to leverage the provider, contribute with feedback, improvement and development can do so in a collaborative way.

I will also be describing in this article some of the common use cases, where this ZPA provider can be useful, and how it can contribute to make organizations adopting a DevOps mindset more agile and secure. The instructions about how to install the provider plugin for different Terraform versions and operating system platforms is described in the GitHub repository README page.

Once you finish following the install instructions, then navigate to the Index page that explains about how to initialize the provider within your Terraform environment, as well as how to provide the necessary authentication credentials. There are also several configuration examples for all available resources and data sources, to assist with the configuration of your ZPA environment in the Examples folder.

:warning: Important: It is important to emphasize that this Terraform provider is not in any way supported or maintained by Zscaler engineering or support teams; hence, it is provided “AS IS” as a community effort.

The How and Why of Using Terraform with ZPA

As infrastructure stacks grow increasingly more complex and involve an ever-growing number of services and systems, teams have looked to abstract configuration to its own layer of code. This concept of configuring infrastructure as code is gaining traction throughout the industry for a variety of reasons.
For starters, it’s fast. When your infrastructure is all defined as code you can run a script to deploy a series of virtual servers; launch things like containers, databases, and load balancers; and configure any cloud service you might need - such as Zscaler Private Access. Writing the configuration in code also helps keep the settings consistent, reduce the chance of introducing errors, and mitigate deviations between deployments.
Think of the last time a single engineer in your organization was the largest source of knowledge about a certain part of your deployment process. And now, think of how frustrating it was when that engineer left with that knowledge and the rest of the team had to scramble to figure out the missing pieces. When your infrastructure is defined as code, it is already documented for the whole team to see. Engineers can look at the code in a single place and read how the services and processes are configured. This minimizes the risk of losing valuable system knowledge. Of course, the configurations could be documented in a wiki. But we all know that trying to find the right information in a wiki can be a lot of extra work.
All these benefits of configuring infrastructure as code point to the main reason for this strategy and that is increased efficiency. Knowing that the infrastructure is configured as expected gives engineers the confidence that it can be automatically deployed without any trouble. Then, the engineers can focus on building rather than configuring. In this post I will describe how you can use this “Unofficial ZPA Terraform Provider” to configure your ZPA tenant.

Why managing ZPA via Terraform is a great idea?

Organizations using Zscaler Private Access as their Zero Trust solution for private application access, can easily integrate ZPA into their Continuous integration (CI), Continuous Delivery (CD), and development pipelines. HashiCorp Terraform is a powerful and extensible tool for defining and creating a cloud infrastructure in a repeatable way through code. It is used to create, manage and update a wide variety of infrastructure resources, including Zscaler Private Access.

ZPA gives administrators the flexibility to configure settings through either a friendly Admin UI or an API. However, this means a change made via the API can overwrite a setting made in the Admin UI, and vice versa. This can create conflict between teams who want to take an “Infrastructure as Code” approach - where every setting is managed by code - and the Administrative, Security, and IT teams who want the autonomy to quickly check and modify settings through the Admin UI - without the need to write code.

Rather than choosing one approach over the other, this custom ZPA Terraform provider supports either option. Any changes made via Terraform are immediately visible in the ZPA Admin portal and conversely, if the ZPA Admin Dashboard is intentionally (or accidentally) used to change a setting that is managed by Terraform, that change will be caught and flagged by Terraform the next time it’s run, providing an extra layer of protection against unanticipated configuration changes within ZPA.

Essentially, the purpose of this unofficial ZPA Terraform Provider is to enable customers to manage all aspects of their usage of ZPA using automation in a manner that is fast, efficient, and secure.

ZPA + Terraform Use Cases

Use Case 1: Using Terraform instead of the ZPA Admin UI

You can configure, manage, and update your ZPA infrastructure easily with Terraform. Instead of using the ZPA Admin UI, you define your ZPA infrastructure in Terraform configuration files using HashiCorp Configuration Language (HCL). HCL is a declarative language that operators use to define the desired resources. Terraform then makes the necessary API calls to Zscaler Private Access cloud to build the requested state, enabling you to automate the provisioning and deployment processes of your ZPA organization. Some of the key benefits to using Terraform and ZPA together include the following:

  • It makes your ZPA infrastructure more predictable, easier to maintain, and deterministic.
  • Less time is spent managing ZPA when on-boarding new applications.
  • It lowers the Bus Factor Risk: ZPA infrastructure is now defined and accessible in source files rather than sysadmin’s head.

Below is a sample Terraform configuration to programmatically perform common tasks that have historically been done manually via the ZPA admin UI.

Create an Application Segment

resource "zpa_application_segment" "example" {
    name = "example"
    description = "example"
    enabled = true
    health_reporting = "ON_ACCESS"
    bypass_type = "NEVER"
    is_cname_enabled = true
    tcp_port_ranges = ["8080", "8080"]
    domain_names = ["server.acme.com"]
    segment_group_id = zpa_segment_group.example.id
    server_groups {
        id = [ zpa_server_group.servergroup.id]

Second, you need to create some required attributes such as segment group and server groups.

Create a segment group

resource "zpa_segment_group" "example" {
  name = "Example"
  description = "Example"
  enabled = true
  policy_migrated = true
  tcp_keep_alive_enabled = true

Create a server group

resource "zpa_server_group" "example" {
  name = "Example"
  description = "Example"
  enabled = true
  dynamic_discovery = true
  app_connector_groups {
    id = [data.zpa_app_connector_group.aws_connector_group.id]

A Server group depends on an App Connector Group; however, the ZPA API do not currently gives the ability to create an App Connector Group via POST calls, so that’s where Terraform data sources come into play.

The provider will query the name of any existing resource in the ZPA portal and bring the ID that must be tied into the server group field.

data "zpa_app_connector_group" "aws_connector_group" {
  name = "AWS-Connector-Group"

This is just one example of what is currently possible with this unofficial provider. In addition to creating application segments, server groups and segment groups, you can also use this custom provider to manage the following resources:

  • Application Server Controller
  • Browser Access
  • Access policy rules
  • Access policy timeout rules
  • Access policy forwarding rules

Use Case 2: Eliminate configuration drift in your ZPA org(s)

ZPA policies may be edited by several teams and administrators over time, making it difficult to keep track of all the various configuration changes. With Terraform, there is a concept of a state, meaning any changes to your ZPA infrastructure (whether intentional or by accident) are immediately detected rather than living on silently without your knowledge. This allows for:

  • Reduced need to pour through logs to find if any configurations were changed by administrators
  • Improved security should anything become compromised and/or configurations are changed without your knowledge.

One other key consideration when using Terraform is that the state file acts as the source of truth for your most recent infrastructure configuration. Operators should ensure that they have access to the necessary state files when making updates or changes. One way to manage this process is to utilize the new Remote State Storage feature from Terraform Cloud. This provides secure storage and access to your organization’s state files, reducing the risk of misconfigurations or errors.

Below is an example of how Terraform can help catch configuration drift. We start with the output of a terraform apply command (this has been edited for clarity.)

terraform apply                                                                        
  + create
Terraform will perform the following actions:
  # zpa_segment_group.example will be created
  + resource "zpa_segment_group" "example" {
      + description            = "Example Segment Group"
      + enabled                = true
      + id                     = (known after apply)
      + name                   = "Example Segment Group"
      + policy_migrated        = true
      + tcp_keep_alive_enabled = (known after apply)
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

At this point, among other things, we have configured a segment group named Example Segment Group. Now assume that another ZPA Admin comes along and decides to change the name of that resource via the ZPA Admin UI. Traditionally, that sort of change would be hard to catch, but thanks to Terraform, that change is caught the next time the terraform plan command is run:



In the output above, you can see that Terraform noticed the Segment Group name changed from “Example Segment Group” to “Example Segment Group Application” and is noting that this would be changed back when the terraform apply command runs again.

Terraform is an excellent tool for managing your ZPA infrastructure. It enables you to define and configure your ZPA infrastructure programmatically, so that it is automated, predictable, and repeatable.

This, of course, is just the beginning, and as more API resources are made available, the provider will be updated, and new versions released as a best effort in the provider repository in GitHub.

Interested in exploring the Provider? To get started check out the project in the GitHub repository here. Want to contribute or open an issue? Find the project here.



@wguilherme I’ve been tasked by my org to redesign our existing ZPA setup. I’m planning on giving the provider a shot and I was wondering, will applying a TF plan to our existing ZPA instance remove all the configurations that aren’t currently in a state file? Or to put it another way, can I use Terraform going forward without having to recreate the existing setup in terraform first?



Hi @zi_afellows
Thanks for reaching out.
So, you can actually import the ZPA configuration using the native Terraform command called terraform import
I wrote an article about how do the import of ZPA resources using this method.

Happy to have a deeper conversation if you’d like.

1 Like

Hi again @wguilherme,

Sorry it took so long to get back to you, but my attention was directed elsewhere.

My biggest concern is that if I apply a plan with the provider that is missing configurations is that something will be delete from our ZPA instance because it wasn’t in the state file. Basically, are the APIs that are being used “additive” or “authoritative” and will a missed import on my side remove the resource in our ZPA instance?

My org has 30+ App Connector Groups and Server groups and over 100 Application Segments and with no backup option or test environment, I’m moderately concerned.