Terraform is an infrastructure-as-code (IaC) solution for DNS management and automation across multiple providers. The IBM NS1 Connect + Terraform toolkit provides the tools needed to sync DNS zones and records across all of your DNS providers to create a single source of truth and to centralize resource management.
Refer to Terraform's NS1 provider documentationNS1 provider documentation to learn more. Additionally, to work effectively with the NS1 provider for Terraform, it is helpful to understand NS1's API data structures and concepts. Refer to the API documentation for details.
Below is an example demonstrating how to use the Terraform toolkit to create a DNS zone on the NS1 Connect platform.
Below are the contents of a Terraform configuration file (terraform_example.tf
) for the zone, terraform.example
:
terraform { required_providers { ns1 = { source = "ns1-terraform/ns1" } } required_version = ">= 0.13" } provider "ns1" { apikey = "API_KEY" rate_limit_parallelism = 60 } resource "ns1_zone" "terraform_example" { zone = "terraform.example" } resource "ns1_record" "first_terraform_example_A" { zone = ns1_zone.terraform_example.zone domain = "first.${ns1_zone.terraform_example.zone}" type = "A" answers { answer = "192.0.2.1" } } resource "ns1_record" "second_terraform_example_A" { zone = ns1_zone.terraform_example.zone domain = "second.${ns1_zone.terraform_example.zone}" type = "A" answers { answer = "192.0.2.2" } }
Below is a breakdown of each resource block.
The first block declares the NS1 provider with the following arguments:
-
API_KEY is a valid API key generated within the NS1 Connect platform.
-
Rate_limit_parallelism is the value recommended by NS1’s Terraform provider documentation.
Warning
If you receive rate-limiting errors or an error message of "invalid character 'u' looking for the beginning of value," check the parallelism value and set it to 60. Setting this to a value of 60 provides a good balance between optimizing for performance and reducing the risk of a 429 response. If you still encounter issues, you can increase this value — NS1 recommends you do so in increments of 20.
The second block defines a resource block of type ns1_zone. NS1 recommends using the domain name of the zone. Note that resource names cannot include periods, so replace the period(s) of the domain name with an underscore. For this example, only the zone's domain name is declared.
The third block defines an ns1_record. Note that a Terraform resource is created for a DNS resource record, and it is important that the two are not confused. NS1 recommends combining the domain name and resource record type to form the resource's name. Also, consider the following:
-
zone is a reference to the zone attribute of the zone resource block that has already been declared. This creates an implicit dependency on the zone resource to avoid issues whereby a resource record is created before the parent zone.
-
domain of the resource is configured to be the domain name of the resource record. Again there is a reference to the zone attribute, but the configuration is more complicated due to interpolation. The alternative is to use first.terraform.example, but this approach is error-prone because you could accidentally create a resource record in another zone. Note there is no explicit relationship between the different types of declared Terraform resources, which means a configuration file could contain unrelated zone and resource records.
-
type is the resource record type.
-
answers is a list of IP addresses.
Lastly, a second resource record is defined in the same way as above.
The next step is to initialize the Terraform working directory. This is the place where the configuration file will reside. You should create a new folder for this purpose. You can have multiple configuration files in the same directory, but that means they all get applied at the same time.
Throughout the next few sections, the output of Terraform is shortened for brevity’s sake. This is indicated by an ellipsis in square brackets: [...].
$ terraform init Initializing the backend... Initializing provider plugins... - Checking for available provider plugins... - Downloading plugin for provider "ns1" (terraform-providers/ns1) 1.8.3... [...] * provider.ns1: version = "~> 1.8" Terraform has been successfully initialized!
The Terraform state is now refreshed to indicate what will change. In this case, the resources do not yet exist in Terraform’s state, so new resources will be created.
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ------------------------------------------------------------------------ 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: [...] Plan: 3 to add, 0 to change, 0 to destroy. [...]
Once verified, the changes can now be applied.
$ terraform apply 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: [...] Plan: 3 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 ns1_zone.terraform_example: Creating... ns1_zone.terraform_example: Creation complete after 1s [id=5ec819124f59db008e3836a5] ns1_record.first_terraform_example_A: Creating... ns1_record.second_terraform_example_A: Creating... ns1_record.first_terraform_example_A: Creation complete after 0s [id=5ec819120eafb9008cf45de1] ns1_record.second_terraform_example_A: Creation complete after 0s [id=5ec8191306e7170090c76d4a] Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
The change is complete. Terraform used the NS1 Connect API to create the zone with two records.