I have blogged in the past about the various options you can use a ‘custom’ Terraform provider – that is to say, a private or experimental provider not hosted on the Terraform Registry.
There are many ways to achieve this but in the latest 0.14 Terraform version, there is a great option that makes it pretty easy: dev_overrides.

I was testing some of the recent NSX-T security features (Identity-Based Firewalling, Context-Aware Firewalling and Distributed IDS/IPS) and, after having configured them on the UI, I wanted to check the Terraform support.
After having spoken to the developers, it turned out that support for the 2 of the features above are already on GitHub but won’t be published onto the Terraform Registry yet.
So we’re going to have to use a custom provider (instead of downloading it through terraform init), compile it and tell Terraform to use the compiled one instead of the one located in the registry.
Let’s go through the example below.
In the excerpt below, I clone the Terraform repo, get the Go packages, compile the provider before heading back to my home folder and opening up the terraformrc file.
$ git clone https://github.com/vmware/terraform-provider-nsxt.git
Cloning into 'terraform-provider-nsxt'...
remote: Enumerating objects: 59, done.
remote: Counting objects: 100% (59/59), done.
remote: Compressing objects: 100% (42/42), done.
remote: Total 24901 (delta 24), reused 28 (delta 15), pack-reused 24842
Receiving objects: 100% (24901/24901), 21.92 MiB | 1.83 MiB/s, done.
Resolving deltas: 100% (15369/15369), done.
Updating files: 100% (5181/5181), done.
$ cd terraform-provider-nsxt/
$ go get
$ go build -o terraform-provider-nsxt
$ cd $HOME
$ vi .terraformrc
Terraformrc is a Terraform config file. It’s rarely necessary for most Terraform users but it can be useful for advanced use cases. Here is what the “.terraformrc” file looks like:
provider_installation {
dev_overrides {
"registry.terraform.io/vmware/nsxt" = "/Users/nicolasvibert/Documents/Scripts/terraform-l7-fw/terraform-provider-nsxt"
}
}
With this dev_overrides command, we tell Terraform where to locate the provider. Make sure the path is where the provider has been compiled.
You don’t actually need to run “terraform init” now but if you do, Terraform will realize that there is “development overrides” and that it takes precedence over other decisions around provider selection.
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of vmware/nsxt from the dependency lock file
Warning: Provider development overrides are in effect
The following provider development overrides are set in the CLI configuration:
- vmware/nsxt in /Users/nicolasvibert/Documents/Scripts/terraform-l7-fw/terraform-provider-nsxt
The behavior may therefore not match any released version of the provider and
applying changes may cause the state to become incompatible with published
releases.
Error: Failed to query available provider packages
Could not retrieve the list of available versions for provider vmware/nsxt:
the previously-selected version 3.1.1 is no longer available
When I ran Terraform plan, it worked perfectly and I was able to create the resources that are only available on the custom Terraform version:
$ terraform apply
Warning: Provider development overrides are in effect
The following provider development overrides are set in the CLI configuration:
- vmware/nsxt in /Users/nicolasvibert/Documents/Scripts/terraform-l7-fw/terraform-provider-nsxt
The behavior may therefore not match any released version of the provider and
applying changes may cause the state to become incompatible with published
releases.
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# nsxt_policy_context_profile.test will be created
+ resource "nsxt_policy_context_profile" "test" {
+ description = "Terraform provisioned ContextProfile"
+ display_name = "test"
+ id = (known after apply)
+ nsx_id = (known after apply)
+ path = (known after apply)
+ revision = (known after apply)
+ app_id {
+ description = "test-app-id-attribute"
+ is_alg_type = (known after apply)
+ value = [
+ "SSL",
]
+ sub_attribute {
+ cifs_smb_version = []
+ tls_cipher_suite = []
+ tls_version = [
+ "SSL_V3",
]
}
}
+ domain_name {
+ description = "test-domain-name-attribute"
+ value = [
+ "*-myfiles.sharepoint.com",
]
}
}
# nsxt_policy_group.Blue_VMs will be created
+ resource "nsxt_policy_group" "Blue_VMs" {
+ description = "Terraform provisioned Group"
+ display_name = "Blue_VMs"
+ domain = "cgw"
+ id = (known after apply)
+ nsx_id = (known after apply)
+ path = (known after apply)
+ revision = (known after apply)
+ criteria {
+ condition {
+ key = "Tag"
+ member_type = "VirtualMachine"
+ operator = "EQUALS"
+ value = "Blue|NSX_tag"
}
}
}
# nsxt_policy_group.Red_VMs will be created
+ resource "nsxt_policy_group" "Red_VMs" {
+ description = "Terraform provisioned Group"
+ display_name = "Red_VMs"
+ domain = "cgw"
+ id = (known after apply)
+ nsx_id = (known after apply)
+ path = (known after apply)
+ revision = (known after apply)
+ criteria {
+ condition {
+ key = "Tag"
+ member_type = "VirtualMachine"
+ operator = "EQUALS"
+ value = "Red|NSX_tag"
}
}
}
# nsxt_policy_intrusion_service_policy.policy1 will be created
+ resource "nsxt_policy_intrusion_service_policy" "policy1" {
+ description = "Terraform provisioned Policy"
+ display_name = "policy1"
+ domain = "cgw"
+ id = (known after apply)
+ locked = false
+ nsx_id = (known after apply)
+ path = (known after apply)
+ revision = (known after apply)
+ sequence_number = 0
+ stateful = true
+ rule {
+ action = "DETECT"
+ destination_groups = (known after apply)
+ destinations_excluded = false
+ direction = "IN_OUT"
+ disabled = false
+ display_name = "rule1"
+ ids_profiles = [
+ "/infra/settings/firewall/security/intrusion-services/profiles/DefaultIDSProfile",
]
+ ip_version = "IPV4_IPV6"
+ logged = true
+ nsx_id = (known after apply)
+ revision = (known after apply)
+ rule_id = (known after apply)
+ sequence_number = (known after apply)
+ services = [
+ "/infra/services/ICMP-ALL",
]
+ sources_excluded = false
}
}
# nsxt_policy_intrusion_service_profile.profile1 will be created
+ resource "nsxt_policy_intrusion_service_profile" "profile1" {
+ description = "Terraform provisioned Profile"
+ display_name = "test"
+ id = (known after apply)
+ nsx_id = (known after apply)
+ path = (known after apply)
+ revision = (known after apply)
+ severities = [
+ "CRITICAL",
+ "HIGH",
]
+ criteria {
+ attack_types = [
+ "trojan-activity",
+ "successful-admin",
]
+ products_affected = [
+ "Linux",
]
}
+ overridden_signature {
+ action = "REJECT"
+ enabled = true
+ signature_id = "2026323"
}
+ overridden_signature {
+ action = "REJECT"
+ enabled = true
+ signature_id = "2026324"
}
}
# nsxt_policy_intrusion_service_profile.profile2 will be created
+ resource "nsxt_policy_intrusion_service_profile" "profile2" {
+ description = "Terraform-provisioned Profile for network-scanning"
+ display_name = "Network-Scan-Policy"
+ id = (known after apply)
+ nsx_id = (known after apply)
+ path = (known after apply)
+ revision = (known after apply)
+ severities = [
+ "CRITICAL",
+ "HIGH",
+ "LOW",
+ "MEDIUM",
]
+ criteria {
+ attack_types = [
+ "network-scan",
]
}
+ overridden_signature {
+ action = "REJECT"
+ enabled = false
+ signature_id = "2019876"
}
}
# nsxt_policy_security_policy.Colors will be created
+ resource "nsxt_policy_security_policy" "Colors" {
+ category = "Application"
+ description = "Terraform provisioned Security Policy"
+ display_name = "Colors"
+ domain = "cgw"
+ id = (known after apply)
+ locked = false
+ nsx_id = (known after apply)
+ path = (known after apply)
+ revision = (known after apply)
+ sequence_number = 0
+ stateful = true
+ tcp_strict = false
+ rule {
+ action = "DROP"
+ destination_groups = (known after apply)
+ destinations_excluded = false
+ direction = "IN_OUT"
+ disabled = false
+ display_name = "Blue2Red"
+ ip_version = "IPV4_IPV6"
+ logged = true
+ nsx_id = (known after apply)
+ revision = (known after apply)
+ rule_id = (known after apply)
+ sequence_number = (known after apply)
+ services = [
+ "/infra/services/ICMP-ALL",
]
+ source_groups = (known after apply)
+ sources_excluded = false
}
+ rule {
+ action = "DROP"
+ destination_groups = (known after apply)
+ destinations_excluded = false
+ direction = "IN_OUT"
+ disabled = false
+ display_name = "Red2Blue"
+ ip_version = "IPV4_IPV6"
+ logged = true
+ nsx_id = (known after apply)
+ revision = (known after apply)
+ rule_id = (known after apply)
+ sequence_number = (known after apply)
+ services = [
+ "/infra/services/ICMP-ALL",
]
+ source_groups = (known after apply)
+ sources_excluded = false
}
+ rule {
+ action = "DROP"
+ destination_groups = (known after apply)
+ destinations_excluded = false
+ direction = "IN_OUT"
+ disabled = false
+ display_name = "Context-Aware Profile"
+ ip_version = "IPV4_IPV6"
+ logged = true
+ nsx_id = (known after apply)
+ profiles = (known after apply)
+ revision = (known after apply)
+ rule_id = (known after apply)
+ sequence_number = (known after apply)
+ services = [
+ "/infra/services/ICMP-ALL",
]
+ source_groups = (known after apply)
+ sources_excluded = false
}
}
Plan: 7 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
nsxt_policy_group.Blue_VMs: Creating...
nsxt_policy_group.Red_VMs: Creating...
nsxt_policy_intrusion_service_profile.profile1: Creating...
nsxt_policy_intrusion_service_profile.profile2: Creating...
nsxt_policy_context_profile.test: Creating...
nsxt_policy_group.Red_VMs: Creation complete after 2s [id=f5a8c760-1f36-4999-b4e5-77ce6db6e1a6]
nsxt_policy_group.Blue_VMs: Creation complete after 2s [id=f5184581-4cf6-4d43-ace4-9ab2534f7d45]
nsxt_policy_intrusion_service_policy.policy1: Creating...
nsxt_policy_context_profile.test: Creation complete after 2s [id=90b54ef5-6967-4f9b-9919-991a17324af2]
nsxt_policy_security_policy.Colors: Creating...
nsxt_policy_intrusion_service_policy.policy1: Creation complete after 0s [id=cd24b954-cdc3-421d-9161-2c35d805a434]
nsxt_policy_security_policy.Colors: Creation complete after 1s [id=ebdff320-ac7e-4ad1-88d6-535906594271]
nsxt_policy_intrusion_service_profile.profile2: Creation complete after 6s [id=4b00da4d-9bb8-4cb1-ab86-1af528d9d36f]
nsxt_policy_intrusion_service_profile.profile1: Creation complete after 6s [id=9a836371-fb65-402d-ac44-6e4535cfc383]
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
That’s it! Thanks for reading this post.