Our Blog

Ongoing observations by End Point people

SRV DNS records in Terraform and Cloudflare

By Jon Jensen
June 26, 2018

woman walking across train tracks
(Photo by David Goehring, CC BY 2.0, cropped)

At End Point we are using Terraform for a few clients to manage their web hosting infrastructure as code (IaC). Terraform is particularly helpful when working with multiple cloud or infrastructure providers and stitching together their services.

For example, for one web application that involves failover from the primary production infrastructure to a secondary location at a different provider, we are using Cloudflare as a CDN to provide caching, DDoS mitigation, and traffic routing in front of virtual servers at DigitalOcean and Amazon Web Services (AWS).

We decided we wanted to store all of their infrastructure configuration in Terraform, not just what is required for the web application, so we can recreate their entire infrastructure from their Git repository.

This all went fine until we got to their email DNS records. Our client is using Microsoft Office 365 for their email, which requires some SRV records. Terraform’s Cloudflare provider works fine with the universal MX records, but when we first wanted to do this, the Terraform provider for Cloudflare did not support SRV records at all.

Luckily for us, Terraform recently (6 April 2018) gained support for DNS SRV records as mentioned in the release notes and described in more detail in the pull request that added the feature.

Great! So now we can get on with this.

I began by naively assuming that the SRV record data should be given in space-separated form like many DNS interfaces use, including BIND and Cloudflare’s web interface itself. I tried setting it like this:

resource "cloudflare_record" "_sipfederationtls_tcp" {
  domain = "${var.domain}"
  name   = "_sip._tcp.${var.subdomain}"
  type   = "SRV"
  value  = "100 1 443 sipdir.online.lync.com."
}

But that resulted in an error. So when in doubt, consult the documentation, right? I did that:

Those make it clear that a data element is required, but give no indication what format is needed.

This is not currently documented for Cloudflare’s API, nor for Terraform’s Cloudflare provider. User EpiqSty helpfully recorded asking Cloudflare’s support, who recommended reverse-engineering the format:

In the meantime, what I would suggest is you can create a SRV record via our UI and then you can use the API to do a GET request on the DNS records, that should show you all the fields that are required.

Ok, then!

It turns out that we must provide the component parts of the SRV record disassembled in key/​value pairs as the Cloudflare API expects, which looks like this in Terraform config:

resource "cloudflare_record" "_sip_tls" {
  domain = "${var.domain}"
  name   = "_sip._tls.${var.subdomain}"
  type   = "SRV"
  data   = {
    service  = "_sip"
    proto    = "_tls"
    name     = "${var.subdomain}."
    priority = 100
    weight   = 1
    port     = 443
    target   = "sipdir.online.lync.com."
  }
}

One unexpected aspect of this is that it requires duplicating the parts that make up the name although the name doesn’t seem to be used by Cloudflare, which assembles the name from the data components service, proto, and name. The name is apparently just there for Terraform, unlike other DNS records where the name is used as the DNS record value.

The Terraform Cloudflare provider also gained support for the much more obscure DNS LOC record type at the same time, and it works similarly.

Thanks to Ben Vickers who contributed the new feature to Terraform!

devops terraform cloud hosting


Comments

Popular Tags


Archive


Search our blog