Building a DNS-as-a-service with OpenStack Designate

Learn how to install and configure Designate, a multi-tenant DNS-as-a-service (DNSaaS) for OpenStack.
251 readers like this.
Command line prompt

Designate is a multi-tenant DNS-as-a-service that includes a REST API for domain and record management, a framework for integration with Neutron, and integration support for Bind9.

You would want to consider a DNSaaS for the following:

  • A clean REST API for managing zones and records
  • Automatic records generated (with OpenStack integration)
  • Support for multiple authoritative name servers
  • Hosting multiple projects/organizations

Designate's architecture

This article explains how to manually install and configure the latest release of Designate service on CentOS or Red Hat Enterprise Linux 7 (RHEL 7), but you can use the same configuration on other distributions.

Install Designate on OpenStack

I have Ansible roles for bind and Designate that demonstrate the setup in my GitHub repository.

This setup presumes bind service is external (even though you can install bind locally) on the OpenStack controller node.

  1. Install Designate's packages and bind (on OpenStack controller):
    # yum install openstack-designate-* bind bind-utils -y
  2. Create the Designate database and user:
    MariaDB [(none)]> CREATE DATABASE designate CHARACTER SET utf8 COLLATE utf8_general_ci;
    MariaDB [(none)]> GRANT ALL PRIVILEGES ON designate.* TO \
    'designate'@'localhost' IDENTIFIED BY 'rhlab123';
    MariaDB [(none)]> GRANT ALL PRIVILEGES ON designate.* TO 'designate'@'%' \
    IDENTIFIED BY 'rhlab123';

Note: Bind packages must be installed on the controller side for Remote Name Daemon Control (RNDC) to function properly.

Configure bind (DNS server)

  1. Generate RNDC files:
    rndc-confgen -a -k designate -c /etc/rndc.key -r /dev/urandom
    cat <<EOF> etcrndc.conf
    include "/etc/rndc.key";
    options {
       default-key "designate";
       default-server {{ DNS_SERVER_IP }};
       default-port 953;
  2. Add the following into named.conf:
    include "/etc/rndc.key";
    controls {
            inet {{ DNS_SERVER_IP }}  allow { localhost;{{ CONTROLLER_SERVER_IP }}; } keys { "designate"; };

    In the option section, add:

    options {
     allow-new-zones yes;
     request-ixfr no;
     listen-on port 53 { any; };
     recursion no;
     allow-query {; {{ CONTROLLER_SERVER_IP }}; };

    Add the right permissions:

     chown named:named /etc/rndc.key
     chown named:named /etc/rndc.conf
     chmod 600 /etc/rndc.key
     chown -v root:named /etc/named.conf
     chmod g+w /var/named
    # systemctl restart named
    # setsebool named_write_master_zones 1
  3. Push rndc.key and rndc.conf into the OpenStack controller:
    # scp -r /etc/rndc* {{ CONTROLLER_SERVER_IP }}:/etc/

Create OpenStack Designate service and endpoints


# openstack user create --domain default --password-prompt designate
# openstack role add --project services --user designate admin
# openstack service create --name designate --description "DNS" dns

# openstack endpoint create --region RegionOne dns public http://{{ CONTROLLER_SERVER_IP }}:9001/
# openstack endpoint create --region RegionOne dns internal http://{{ CONTROLLER_SERVER_IP }}:9001/  
# openstack endpoint create --region RegionOne dns admin http://{{ CONTROLLER_SERVER_IP }}:9001/

Configure Designate service

  1. Edit /etc/designate/designate.conf:
    • In the [service:api] section, configure auth_strategy:
      listen =
      auth_strategy = keystone
      api_base_uri = http://{{ CONTROLLER_SERVER_IP }}:9001/
      enable_api_v2 = True
      enabled_extensions_v2 = quotas, reports
    • In the [keystone_authtoken] section, configure the following options:
      auth_type = password
      username = designate
      password = rhlab123
      project_name = service
      project_domain_name = Default
      user_domain_name = Default
      www_authenticate_uri = http://{{ CONTROLLER_SERVER_IP }}:5000/
      auth_url = http://{{ CONTROLLER_SERVER_IP }}:5000/
    • In the [service:worker] section, enable the worker model:
      enabled = True
      notify = True
    • In the [storage:sqlalchemy] section, configure database access:
      connection = mysql+pymysql://designate:rhlab123@{{ CONTROLLER_SERVER_IP }}/designate
    • Populate the Designate database:
      # su -s /bin/sh -c "designate-manage database sync" designate
  1. Create Designate's pools.yaml file (has target and bind details):
    • Edit /etc/designate/pools.yaml:
      - name: default
        # The name is immutable. There will be no option to change the name after
        # creation and the only way will to change it will be to delete it
        # (and all zones associated with it) and recreate it.
        description: Default Pool
        attributes: {}
        # List out the NS records for zones hosted within this pool
        # This should be a record that is created outside of designate, that
        # points to the public IP of the controller node.
          - hostname: {{Controller_FQDN}}. # Thisis mDNS
            priority: 1
        # List out the nameservers for this pool. These are the actual BIND servers.
        # We use these to verify changes have propagated to all nameservers.
          - host: {{ DNS_SERVER_IP }}
            port: 53
        # List out the targets for this pool. For BIND there will be one
        # entry for each BIND server, as we have to run rndc command on each server
          - type: bind9
            description: BIND9 Server 1
            # List out the designate-mdns servers from which BIND servers should
            # request zone transfers (AXFRs) from.
            # This should be the IP of the controller node.
            # If you have multiple controllers you can add multiple masters
            # by running designate-mdns on them, and adding them here.
              - host: {{ CONTROLLER_SERVER_IP }}
                port: 5354
            # BIND Configuration options
              host: {{ DNS_SERVER_IP }}
              port: 53
              rndc_host: {{ DNS_SERVER_IP }}
              rndc_port: 953
              rndc_key_file: /etc/rndc.key
              rndc_config_file: /etc/rndc.conf
    • Populate Designate's pools:
      su -s /bin/sh -c "designate-manage pool update" designate
  1. Start Designate central and API services:
    systemctl enable --now designate-central designate-api
  2. Verify Designate's services are up:
    # openstack dns service list
    | service_name | status | stats | capabilities |
    | central      | UP     | -     | -            |
    | api          | UP     | -     | -            |
    | mdns         | UP     | -     | -            |
    | worker       | UP     | -     | -            |
    | producer     | UP     | -     | -            |

Configure OpenStack Neutron with external DNS

  1. Configure iptables for Designate services:
    # iptables -I INPUT -p tcp -m multiport --dports 9001 -m comment --comment "designate incoming" -j ACCEPT
    # iptables -I INPUT -p tcp -m multiport --dports 5354 -m comment --comment "Designate mdns incoming" -j ACCEPT
    # iptables -I INPUT -p tcp -m multiport --dports 53 -m comment --comment "bind incoming" -j ACCEPT
    # iptables -I INPUT -p udp -m multiport --dports 53 -m comment --comment "bind/powerdns incoming" -j ACCEPT
    # iptables -I INPUT -p tcp -m multiport --dports 953 -m comment --comment "rndc incoming - bind only" -j ACCEPT
    # service iptables save; service iptables restart
    # setsebool named_write_master_zones 1
  2. Edit the [default] section of /etc/neutron/neutron.conf:
    external_dns_driver = designate
  3. Add the [designate] section in /_etc/_neutron/neutron.conf:
    url = http://{{ CONTROLLER_SERVER_IP }}:9001/v2  ## This end point of designate
    auth_type = password
    auth_url = http://{{ CONTROLLER_SERVER_IP }}:5000
    username = designate
    password = rhlab123
    project_name = services
    project_domain_name = Default
    user_domain_name = Default
    allow_reverse_dns_lookup = True
    ipv4_ptr_zone_prefix_size = 24
    ipv6_ptr_zone_prefix_size = 116
  4. Edit dns_domain in neutron.conf:
    dns_domain =
    # systemctl restart neutron-*
  5. Add dns to the list of Modular Layer 2 (ML2) drivers in /etc/neutron/plugins/ml2/ml2_conf.ini:
  6. Add zone in Designate:
    # openstack zone create –

    Add a new record in zone

    # openstack recordset create --record '' --type A Test

Designate should now be installed and configured.

User profile image.
Let's brilliant ideas come out smoothly. I am RHCA, love opensource, love working on : Openstack OpenShift/Kubernetes Keycloak SSO, freeipa Ansible Ceph GlusterFs and many opensource projects. My personnel website:

1 Comment

I thought Designate uses different service/package for DNS.. finally it is bind.. Great Tutorial. Thank you Amjad..

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.