Designate and Neutron DNS Integration

DNS is hard. So, automating DNS guarantees PTR to A/AAAA record matches every time.

In this article, we will be deploying OpenStack including the Designate and
Neutron services which will be integrated for DNS. We will be using Juju and the OpenStack Charms. In order to avoid muddying up documentation and documentation rot, I will not be duplicating upstream documentation. This deployment relies on the following documentation:

There have been two ways to integrate DNS with Designate and Neutron. The now deprecated method which relies on notifications and is referred to as the sink method

The current methodology and the focus of this post is Neutron direct integration. The OpenStack charms now support this preferred method.

If you are familiar with Juju and OpenStack Charms you know we can create a model of our deployment in yaml. Here is the full bundle we will be using.

For the sake of simplicity here is a model snippet with only the applications and relations that we care about. To be clear this is not a full model but just the relevant parts.

  applications:
    neutron-api:
      charm: cs:~openstack-charmers-next/neutron-api
      options:
        enable-ml2-dns: True
        dns-domain: neutron.example.
        reverse-dns-lookup: True
        ipv4-ptr-zone-prefix-size: 24
    designate:                           
      charm: cs:~openstack-charmers-next/designate   
      options: 
        nameservers: ns1.designate.example.                       
    designate-bind:                      
      charm: cs:~openstack-charmers-next/designate-bind    

  relations:
    - [ designate, designate-bind ]      
    - [ designate, neutron-api ]

Let’s explain some of the configuration parameters.

  • enable-ml2-dns: Tells the neutron to enable the ML2 dns extension.
  • dns-domain: This the is DNS domain name that Neutron will use for default project network DNS records.
  • reverse-dns-lookup: Tells neutron to enable reverse dns lookups.
  • ipv4-ptr-zone-prefix-size: Tells neutron the expected network size in CIDR format.
  • nameservers: Tells designate what to call the nameserver it is creating.

We deploy the model with a simple:

juju deploy ./bundle.yaml

Post-Deploy Cloud Configuration

Once the model has settled. We have an unconfigured OpenStack cloud. At this point you can use your favorite script for creating some users, setting up images and creating flavors.

Once we have created a user and project and acquired our novarc we are set to proceed. We’ll need at least an “external” network and a “private” project network for our test project. Something like this:

# External network
openstack network create --provider-network-type flat --external ext-net
openstack subnet create --gateway 10.50.0.1 --allocation-pool start=10.50.33.1,end=10.50.33.254 --no-dhcp --subnet-range 10.50.0.0/18 --network ext-net ext-subnet

# Project network
openstack network create --provider-network-type gre --internal project-net

NOTE: DO NOT SET –dns-nameserver on the project subnet. By not setting the dns server the project network will default to using the dnsmasq service associated with the network. This is Neutron handling our project internal DNS records automatically.

openstack subnet create --gateway 172.16.0.1 --dhcp --subnet-range 172.16.0.0/12 --network project-net project-subnet

# Router
openstack router create project-router
openstack router add subnet project-router project-subnet
openstack router set --external-gateway ext-net

DNS integration specific settings

We need to create a DNS server in designate. The name must end in a ‘.’

designate server-create --name ns1.designate.example. *

Create the zone for your external DNS. The zone name must end in a ‘.’

openstack zone create --email desnotexist@example designate.example.

Find the Zone id just created

openstack zone list

Create an A record for the automatically created NS record that points to one or more of the designate-bind instances:

juju status designate-bind --format short
openstack recordset create --records $DESIGNATE_BIND_IP --type A $ZONE_ID ns1.designate.example.

At this point we have a functioning, but almost empty, zone for designate.example. You can query it with:

dig @$DESIGNATE_BIND_IP -type NS

Here is the secret sauce (Use Case 3). We tell Neutron that for any floating IPs for our project network create the hostname in a given DNS domain.

neutron net-update project-net --dns_domain designate.example. *

Finally, to connect the DNS forwarders tell Neutron to use Designate Bind as its forwarder.

juju config neutron-gateway dns-servers=$DESIGNATE_BIND_IP

This enables the full DNS query path for project instances:

Project instance -> Neutron dnsmasq -> Designate Bind -> External DNS

I could not find OpenStack client equivalents for these commands. Please let me know in the comments to thwart my ignorance.

Here is an automated version of the above:

#!/usr/bin/bash
set -e
DESIGNATE_BIND_IP=$(juju status designate-bind --format short | awk '/designate-bind/ {print $3}')
DESIGNATE_DOMAIN_EMAIL=doesnotexist@example

designate server-create --name ns1.$DESIGNATE_DOMAIN_NAME
openstack zone create --email $DESIGNATE_DOMAIN_EMAIL $DESIGNATE_DOMAIN_NAME

ZONE_ID=$(openstack zone list -f value -c id)

openstack recordset create --records $DESIGNATE_BIND_IP --type A $ZONE_ID ns1.$DESIGNATE_DOMAIN_NAME

juju config neutron-gateway dns-servers=$DESIGNATE_BIND_IP
neutron net-update private --dns_domain $DESIGNATE_DOMAIN_NAME

Integration In Action

At this point, if we boot an instance with the name ServerName and assign a floating IP good things will happen.

openstack server create {image/key/flavor/network} ServerName
openstack floating ip create
openstack server add floating ip $SERVER_ID $FLOATING_IP

Neutron will create forward and reverse records in dnsmasq for the internal DNS. From the instance itself (or on the project-net):

dig @172.16.0.2 ServerName.neutron.example
dig @172.16.0.2 -x $STATIC_IP

Neutron will inform Designate to create the forward and reverse records for the floating IP in the external DNS.

dig @$DESIGNATE_BIND_IP ServerName.designate.example
dig @$DESIGNATE_BIND_IP -x $FLOATING_IP

We can also see the external DNS record sets in Designate:

openstack recordset list designate.example.

Conclusion

This is an excellent way to automate DNS in OpenStack.

DNS is hard.

DNS is hard. So, automating it guarantees PTR to A/AAAA record matches every time. No more forgotten records. DNS just works.

Happy querying, OpenStack DevOps!