---
title: "Manage Univention DNS with Terraform"
date: 2022-09-11T13:57:16+02:00
authors:
  - robert-kaussow
tags:
  - Sysadmin
  - Automation
resources:
  - name: feature
    src: "images/feature.jpg"
    params:
      anchor: Center
      credits: >
        [Taylor Vick](https://unsplash.com/@tvick) on
        [Unsplash](https://unsplash.com/s/photos/data-center)
---

Using [Terraform](/posts/2022/09/store-terraform-state-on-backblaze-s3/) 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](https://registry.terraform.io/providers/Mastercard/restapi/latest/docs) 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:

```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:

```Terraform
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
      ],
    }
  })
}
```
