Manage Univention DNS with Terraform Credits: Taylor Vick on Unsplash

Manage Univention DNS with Terraform

Using Terraform is a great way to manage infrastructure as code. To map all the different types of resources in a deployment, Terraform uses plugins. Plugins are executable binaries written in Go that communicate with Terraform Core via an RPC interface. Each plugin provides an implementation for a specific service.

Sometimes there is no specific plugin for a service, but if the service provides a REST API, the generic REST API provider can be helpful. This time, I was looking for a way to manage DNS records on a Univention Corporate Server (UCS) using Terraform. The Univention Directory Manager (UDM) API is well documented and can be used with the RESP API provider, but there are a few minor pitfalls to be aware of.

First of all, a basic provider configuration needs to be added to Terraform:

provider "restapi" {
  uri                   = "https://univention.example.com/univention/udm/"
  username              = "myuser"
  password              = "secure-password"
  id_attribute          = "dn"
  debug                 = true
  create_returns_object = true
  headers = {
    accept = "application/json"
  }
}

Ensure that a full URL to the UDM is used in the uri parameter. If username and password are used, the Terraform provider adds a basic authentication header. Alternatively, it is also possible to set other authentication headers manually. This is required to use e.g. token-based authentication instead of username and password. Terraform requires a unique ID for all objects under control. Because manually managing unique IDs is somewhat tedious, it is preferred to let the API handle it whenever possible. In the case of Univention, a basic understanding of object management is required. On a UCS, DNS objects are stored in the OpenLDAP objects. As a distinguished name (DN) uniquely identifies an LDAP record, this attribute can be perfectly used as id_attribute for the Terraform provider. But it is also important to set create_returns_object=true. This option tells the provider that each create operation (POST) will return an object. As a result, for creation events, the provider will parse the returned data, use the id_attribute field as a unique ID, and stores the data along with the ID in Terraforms internal data structures. To finalize the provider configuration, the accept header need to be set to application/json, otherwise the API will return HTML that can not be parsed by the Terraform provider.

With this configuration, the restapi_object resource can now be used to manage DNS records:

resource "restapi_object" "ucs_server" {
  path = "/dns/host_record/"
  data = jsonencode({
    "position" : "zoneName=example.com,cn=dns,dc=example,dc=com,
    "properties" : {
      "name" : "myhost",
      "a" : [
        192.168.0.10
      ],
    }
  })
}