Skip to main content

Automating Netskope Private Access Publisher Deployment using Infrastructure-as-Code in Pulumi

  • May 20, 2026
  • 0 replies
  • 2 views

jneerdael
Netskope Employee

Expanded Pulumi provider for Netskope Publishers: now targeting 25+ infrastructure platforms

When deploying Netskope Private Access, one of the recurring operational tasks is provisioning and registering Publishers. A Publisher is the lightweight connector that sits in your data center, cloud environment, or virtualization platform and establishes the secure path between users and private applications, without exposing those applications directly to the internet.

I built an unofficial Pulumi provider for Netskope Publishers to make that process easier to automate across different environments.

The project started with support for AWS, Azure, GCP, Kubernetes, and vSphere. Since then, support has expanded significantly, and we are now adding support for even more cloud and infrastructure platforms.

The provider currently supports, or is being extended to support:

Platform Pulumi component
AWS AwsPublisher
Azure AzurePublisher
GCP GcpPublisher
Kubernetes KubernetesPublisher
vSphere VspherePublisher
ESXi Native EsxiPublisher
Hetzner Cloud HcloudPublisher
Nutanix NutanixPublisher
OpenStack OpenstackPublisher
OVH OvhPublisher
Scaleway ScalewayPublisher
Oracle Cloud Infrastructure OciPublisher
Alibaba Cloud AlicloudPublisher
Proxmox VE ProxmoxvePublisher
Hyper-V HypervPublisher, experimental
DigitalOcean DigitaloceanPublisher
Vultr VultrPublisher
Exoscale ExoscalePublisher
UpCloud UpcloudPublisher
Stackit StackitPublisher
Equinix Metal EquinixPublisher
Outscale OutscalePublisher
Open Telekom Cloud OpentelekomcloudPublisher
Tencent Cloud TencentcloudPublisher
Yandex Cloud YandexPublisher

Full documentation is available here:

https://johnneerdael.github.io/pulumi-netskope-publisher/

Note: this is an open-source community project and is not supported by Netskope Engineering or Netskope Support. All deployments, including Kubernetes deployments, use production Netskope Publisher containers and not a beta build. Kubernetes deployment is not yet officially supported, but early feedback is welcome.

First: what is Pulumi?

Most infrastructure-as-code discussions around Netskope automation naturally start with Terraform. Terraform is a widely used infrastructure-as-code tool that lets you build, change, and version infrastructure across cloud and SaaS providers. Terraform configurations are written in the Terraform language, which is declarative and primarily focused on declaring resources and their relationships.

Pulumi solves a similar infrastructure-as-code problem, but with a different approach. Instead of writing infrastructure in HCL, Pulumi lets you define cloud infrastructure using familiar programming languages such as TypeScript, Python, Go, .NET/C#, Java, and YAML.

That means you can use normal language features like functions, loops, conditionals, classes, testing frameworks, package managers, and IDE tooling while still getting an infrastructure-as-code workflow with previews, state, outputs, and repeatable deployments.

This provider is for people who want that Pulumi workflow for Netskope Private Access Publishers.

What the provider does

The provider exposes Pulumi components for provisioning Netskope Private Access Publishers across cloud providers, Kubernetes clusters, virtualization platforms, and bare-metal-style infrastructure providers.

At a high level, the provider can:

  • create or reuse Netskope Publisher records;
  • generate registration tokens;
  • provision the cloud VM, Kubernetes workload, vSphere VM, Proxmox VM, ESXi VM, or other provider-specific compute resource;
  • inject the registration data into the workload;
  • return useful outputs such as publisher names, publisher IDs, registration tokens, VM IDs, and IP addresses as Pulumi outputs.

The package includes a stateful NetskopeRegistration resource that can register or reuse Netskope Publisher records and generate registration tokens. Provider-specific Publisher components create this automatically when you supply a tenant URL and API token, but you can also use it separately if you want to split tenant-side registration from infrastructure provisioning.

Why the architecture can support so many platforms

The main design principle is that Netskope Publisher registration is separated from the infrastructure-specific part of the deployment.

Each platform component remains responsible for the things that are unique to that platform: image selection, instance type, region or zone, networking, SSH keys, tags, metadata, cloud-init placement, and provider-specific outputs.

The common Publisher workflow is shared:

  1. resolve the Publisher names;
  2. create or reuse the Netskope Publisher records;
  3. generate registration tokens;
  4. render the install or enrollment payload;
  5. pass that payload to the target platform in the way that platform expects;
  6. return consistent Pulumi outputs.

This is what makes it possible to support AWS, Azure, GCP, Kubernetes, vSphere, ESXi, OpenStack, OCI, Alibaba Cloud, Proxmox, Hetzner Cloud, DigitalOcean, Vultr, Exoscale, UpCloud, Stackit, Equinix Metal, Outscale, Open Telekom Cloud, Tencent Cloud, Yandex Cloud, and others with a similar user experience, even though each platform has different APIs and different ways of passing user data or cloud-init.

Some platforms use official Netskope Publisher images or pre-baked images. Others use a bootstrap flow on Ubuntu 22.04, where Pulumi passes cloud-init or user-data to install and enroll the Publisher automatically. Kubernetes is different again: it deploys the Publisher through the Helm chart rather than booting a VM.

The goal is that the platform-specific details stay in the component, while the Publisher lifecycle stays consistent.

Example: deploy AWS Publishers with TypeScript

Here is a small example of what the Pulumi code looks like:

import * as pulumi from "@pulumi/pulumi";
import { AwsPublisher } from "@johninnl/pulumi-netskope-publisher";

const netskope = new pulumi.Config("netskope");
const config = new pulumi.Config();

const publisher = new AwsPublisher("publisher", {
namePrefix: "pub-eu",
replicas: 2,
tenantUrl: netskope.require("tenantUrl"),
apiToken: netskope.requireSecret("apiToken"),
subnetId: config.require("subnetId"),
securityGroupIds: [config.require("securityGroupId")],
instanceType: "t3.medium",
associatePublicIpAddress: false,
bootstrap: true,
});

export const publisherNames = publisher.publisherNames;
export const publishers = pulumi.secret(publisher.publishers);

For AWS, AwsPublisher creates one EC2 instance per Publisher name and registers each instance with Netskope. When bootstrap mode is enabled and no AMI is supplied, the component resolves an Ubuntu image and installs the Publisher using Netskope’s generic bootstrap flow.

The same general pattern exists across the other supported platforms, with platform-specific inputs for things like regions, zones, subnets, VM sizes, images, templates, clusters, Helm settings, metadata, cloud-init, and provider credentials.

Why Pulumi for this?

Terraform is still a great option, especially if your organization already standardizes on Terraform modules and workflows. This project is not meant to replace that for everyone.

The main benefit of Pulumi is that you can express infrastructure in the same languages many teams already use for application or automation code. For example:

  • a TypeScript team can keep infrastructure close to existing Node.js tooling;
  • a Python-heavy automation team can use normal Python packaging and testing;
  • a .NET team can write infrastructure in C#;
  • Go users can consume the generated Go SDK;
  • Java users can use the Java SDK;
  • Rust users can use the generated Rust package where supported by the project documentation.

The documentation includes examples for the Pulumi CLI and multiple languages, so you can choose the language that fits your workflow instead of learning a new configuration language first.

Supported deployment patterns

The provider is designed around common Publisher deployment scenarios.

For high availability, you can set replicas: 2 or pass two explicit names. Each Publisher gets its own Netskope record, token, and workload.

For multi-region deployments, you can create one provider instance and one Publisher component per region, zone, datacenter, cloud placement boundary, or infrastructure environment.

For bring-your-own networking, the package expects you to pass existing network identifiers. It does not create VPCs, VNets, subnets, route tables, NAT gateways, firewalls, or security groups for you.

For bring-your-own images, you can either use bootstrap mode from a stock Ubuntu image or use a pre-baked image that already contains the Publisher wizard.

For Kubernetes, the provider installs the kubernetes-netskope-publisher Helm chart into an existing cluster. It supports token mode, where Pulumi creates one Secret per registration token and one Helm release per Publisher name, and API mode, where the chart registers Publisher pods with the Netskope API during startup.

For vSphere, the provider clones one VM per Publisher name from an existing template and passes registration data through guestinfo cloud-init.

For Proxmox VE, OpenStack, Nutanix, Hetzner Cloud, OVH, Scaleway, OCI, Alibaba Cloud, DigitalOcean, Vultr, Exoscale, UpCloud, Stackit, Equinix Metal, Outscale, Open Telekom Cloud, Tencent Cloud, and Yandex Cloud, the provider follows the same overall pattern but maps the rendered enrollment data to each platform’s own user-data, metadata, guest customization, or cloud-init mechanism.

Secrets and operational notes

Because Publisher registration tokens and rendered cloud-init data are sensitive, the provider treats the publishers output as a secret output. The recommended pattern is to store the Netskope API token as a Pulumi secret:

pulumi config set netskope:apiToken --secret

One important operational detail: pulumi destroy deletes the cloud, VM, or Kubernetes resources that Pulumi owns, but it does not delete the Netskope Publisher record from the tenant. If you no longer need the tenant-side record, remove it from the Netskope admin console or API after confirming it is no longer referenced by policy.

Also make sure your Publisher workload has outbound TCP/443 and DNS resolution to the required Netskope tenant and gateway endpoints. Blocked outbound 443, DNS issues, proxy issues, or routing problems are common reasons why a Publisher never comes online.

Getting started

The project documentation includes a starter walkthrough, admin guides, provider matrix, platform-specific examples, installation instructions, and operational notes.

The starter guide walks through deploying one Netskope Private Access Publisher with Pulumi, including tool installation, cloud account preparation, Netskope tenant preparation, stack configuration, deployment, verification, and cleanup.

Full documentation:

https://johnneerdael.github.io/pulumi-netskope-publisher/

Final disclaimer

This is an unofficial community project. Please review the code, test in a lab or non-production environment first, and make sure your Pulumi state, secrets provider, and Netskope API token handling match your organization’s security requirements.

Feedback, issues, and pull requests are welcome. My goal is to make Netskope Publisher automation easier for teams that prefer Pulumi or want to explore infrastructure-as-code in TypeScript, Python, C#, Go, Java, Rust, or other Pulumi-supported workflows.