OpenStack应用Designate实现DNS服务

一、DNS相关简介

DNS(Domain Name System)是Internet的重要组成部分,它的核心是为IP地址提供一个更易记住的名字。Internet上的大部分服务都会用到DNS,例如:访问网站,发送邮件,登录软件系统,玩游戏,网络聊天等。浏览器通过域名访问网站的实际过程如下图所示:

OpenStack应用Designate实现DNS服务

DNS从1985年开始被使用。但是为IP地址提供一个更易记住的名字可以追溯到ARPANET(Internet前身)时代。最早的ARPANET网络通过一个hosts.txt文件管理地址和hostname的关系,用户需要DNS服务,就从一个ftp下载host.txt文件到本地。最开始的网络中也就几百台计算机,这种方法没什么问题。但是随着网络的增加,文件存储的方式不能满足规模的要求。为了适应日益增长的网络规模,DNS被提出。不过host.txt文件被保留下来了,这就是我们日常熟悉的hosts文件,Linux在/etc/hosts,Windows在 C:/Windows/System32/Drivers/etc/hosts。在现代的计算机中,当请求Domain name(域名)解析时,还是先查找计算机的hosts文件,如果hosts文件没有相应的记录,才会触发DNS请求。
作为host.txt的改进方案,DNS本质上是一个Internet上的域名和IP地址相互映射的分布式数据库。数据库以树形结构存在,如下图所示:

OpenStack应用Designate实现DNS服务

树中每个节点都有自己的标签,根节点有个特殊的标签“.”。树结构中一条路径中所有节点的标签构成了DNS域名。这与Unix文件系统路径类似,区别在于Unix文件系统路径将根节点放在前面,而DNS域名反过来了,将根节点放在了最后。例如,图中host完整的域名是:“eos.cs.berkeley.edu.”,越靠近根节点ROOT的标签在右,越靠近服务器的标签在左。注意,一个完整的域名,是以根节点标签“.”结束。

1.1 DNS zone子树

Zone是DNS树中的子树。Zone本身可以划分成更小的Zone。前面说过DNS的结构与Unix文件系统类似,相应的Zone与Unix文件系统中的磁盘分区类似。我们无法从DNS域名看出当前域名在哪个Zone,就像很难根据Unix文件路径,看出当前目录在哪个磁盘分区一样。在DNS树形结构中,Zone可以用下图来描述。

DNS Zone通常由一个或者多个DNS server管理,一个DNS server也可以管理多个Zone。如下图所示:

DNS与传统的hosts.txt方式的区别在于,通过Zone的划分,将庞大的DNS记录划分成了一个个小块,从而解决数据庞大,不易管理的问题。所以DNS Zone本质上是DNS记录的集合。DNS记录被称为Resource Record(RR)。RR有很多种类型。常见的有以下几种:

  • A:域名与IPv4地址的对应

  • AAAA:域名与IPv6地址的对应

  • PTR:域名与IP地址的对应,区别是A或者AAAA是通过域名获得IP地址,PTR可以通过IP地址获得域名

  • CNAME:记录一个域名与另一个域名的对应关系

  • NS:为当前Zone指定一个DNS server

  • SOA:包含Zone的一些信息,例如首要的DNS server,管理员邮箱地址,更新时间等

1.2 DNS工作过程

这部分介绍DNS工作过程,首先看一下日常中经常接触的DNS server。DNS server大体上可以分为两类。
* 一类是管理DNS zone的DNS server,称为Authoritative DNS server。这些DNS Server只掌握了一个或者多个DNS zone的信息,不能为我们提供整个互联网的DNS信息。
* 另一类是Cache DNS server。这类DNS server不管理DNS zone,但是连接Authoritative DNS server,并且缓存从Authoritative DNS Server获取的信息。最典型的就是谷歌的8.8.8.8。
假设我的电脑配置的DNS server是8.8.8.8,我需要访问www.zhihu.com,首先我的电脑要获取www.zhihu.com的IP地址,需要经过下面所示的步骤:

 

  1.  向8.8.8.8请求获取www.zhihu.com的IP地址。如果8.8.8.8包含了www.zhihu.com的IP地址记录,则直接跳到步骤8。

  2.  8.8.8.8所在的Cache DNS server并没有www.zhihu.com的记录,所以它向Authoritative DNS server请求数据。首先发往Root DNS server,这是全球共有的13个逻辑服务器,每一个是由一个集群构成。

  3.  Root DNS server实际上没有www.zhihu.com的记录,也不可能有,因为全球的DNS记录不可能集中在一起,这在性能上是不能接受的,并且这样就跟之前的hosts.txt文件也没有区别了。不过由于需要解析的是www.zhihu.com,Root DNS server知道如何到达“.com”的DNS Server,也就是TLD(Top-Level Domain)DNS server。因此将TLD DNS server的信息也就是“.com”的DNS server地址发送给8.8.8.8。

  4.  8.8.8.8收到了TLD DNS server的地址之后,继续向“.com” 的DNS server请求数据。

  5.  TLD DNS server 仍然没有www.zhihu.com的信息,但是TLD DNS Server知道zhihu.com的DNS server,于是TLD DNS Server将zhihu.com的DNS server地址发送给8.8.8.8。

  6.  8.8.8.8收到了DNS server地址之后,继续向zhihu.com的DNS server请求数据。

  7.  管理zhihu.com的Authoritative DNS server有www.zhihu.com的记录,于是将对应的IP地址发送给8.8.8.8。

  8.  8.8.8.8拿到了www.zhihu.com对应的IP地址,首先记录在本地缓存,这样下次不用再走一遍234567,接着将IP地址发送给请求主机。

  9.  主机拿到IP地址之后,向IP地址所在的Server发送实际的HTTP请求。

这里的1-8实际上就是第一幅图中的步骤1,2的详细版。
好了,DNS的工作过程大概如此,接下来看一下,如何为OpenStack中的虚机提供DNS服务。OpenStack中的虚机DNS服务,可以分为两个部分:一个是Internal DNS service,另一个是External DNS service。Internal DNS service由Neutron DHCP Service完成,External DNS service由OpenStack Designate项目实现。

1.3 OpenStack Neutron DHCP服务

Neutron DHCP Service默认是由dnsmasq进程实现,dnsmasq同时提供了DNS服务和DHCP服务。它的DHCP服务在OpenStack Neutron中应用广泛,相应的,其提供的DNS服务知名度不那么高。OpenStack Neutron DHCP service是以tenant network为单位提供服务的,也就是说每个tenant network都有独立的DHCP service,独立的dnsmasq进程。那么相应的,Neutron DHCP service提供的DNS service也只能在tenant network范围内。默认情况下,DHCP service会通过DHCP协议,将dnsmasq的管理端口地址(也就是DHCP Server地址)作为虚机的DNS Server写入虚机。在每个dnsmasq的配置文件中(存放于state_path中),会静态的记录虚机的hostname与IP地址的对应。这样,当虚机请求DNS解析的时候,dnsmasq可以从静态的配置文件中获取对应的解析记录,并回送给虚机。

相应的配置项有:

Shell


1

2

3

4

/etc/neutron/neutron.conf

[DEFAULT]

# Domain to use for building the hostnames (string value)

dns_domain = test.org.

虚机的FQDN(Full Qualified Domain Name),默认是由虚机名加上这里配置的dns_domain构成。部署完虚机之后,在虚机内ping同一个tenant network下的其他虚机,可以得到如下响应。

Shell


1

2

3

4

5

6

ubuntu@vm6:~$ ping vm5.test.org

PING vm5.test.org (192.168.1.9)56(84) bytes of data.

64 bytes from vm5.test.org (192.168.1.9): icmp_seq=1 ttl=64 time=95.5 ms

64 bytes from vm5.test.org (192.168.1.9): icmp_seq=2 ttl=64 time=0.802ms

64 bytes from vm5.test.org (192.168.1.9): icmp_seq=3 ttl=64 time=0.737ms

64 bytes from vm5.test.org (192.168.1.9): icmp_seq=4 ttl=64 time=0.730ms

不过,因为只能同一个租户网络内部主机之间域名解析,Internal DNS service在OpenStack中的应用,并不是很多。

二、OpenStack Designate管理配置DNS

Neutron DHCP service提供的DNS服务,存在两个问题:一是只能在tenant network内使用,无法在整个OpenStack下使用,另一个是在OpenStack之外,无法使用其提供的域名访问虚机。因此,接下来要介绍OpenStack中的External DNS service:Designate。项目的介绍可以在其wiki上找到。Designate号称是一个DNSaaS的项目(这年头不把自己叫做as a Service就不舒服)。但是Designate并没有实现DNS协议,而是管理了实现DNS协议的软件,例如BIND9,PowerDNS等。Designate将这些软件与OpenStack连接了起来,通过一套自己提供的API,控制底层的DNS软件,完成例如创建DNS Zone,写入Resource Record等DNS操作。所以,Designate本身只是一个软件框架,一个适配多种DNS软件的软件框架。本文将不会对Designate的架构做介绍,也不会贴一段代码来解释它的实现,接下来的介绍将更偏向于应用。
接下来所有的内容都是基于Pike版本代码(2017-08-08)完成。

2.1 devstack安装

用devstack安装Designate比较简单,只需要在local.conf文件中增加下面内容,再执行./stack.sh即可,这里我用的是bind9作为DNS后端实现。

Shell


1

2

3

# Enable designate

enable_plugin designate https://git.openstack.org/openstack/designate

DESIGNATE_BACKEND_DRIVER=bind9


2.2 与Neutron/Nova集成

在OpenStack Mitaka版本之前,Designate只是一个独立的DNS软件接口,如果用户需要新增DNS记录,可以调用Designate API完成写入。如果你本身就熟悉BIND9的操作,那Designate的意义不是那么的明显。在Mitaka版本,Designate与OpenStack Nova,Neutron做了集成,真正的将Designate与OpenStack结合在了一起,具体来说,就是将DNS记录的创建,与虚机/网络的创建关联起来,用户不再需要特意的去管理Designate中的DNS记录。
需要注意的是,Devstack的安装过程,不会完成所有的Neutron与Designate集成所需要的配置,为了将Designate与Nova/Neutron集成起来,还需要手动修改一些配置。仔细看的话,下面所有的DNS域名都是完整的域名,也就是会以“.”结尾。

Shell


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

/etc/neutron/neutron.conf

 

[DEFAULT]

# Domain to use for building the hostnames (string value)

dns_domain = test.org.

 

# Driver for external DNS integration. (string value)

external_dns_driver = designate

 

[designate]

url = http://:9001/v2

admin_auth_url = http:///identity

admin_username =

admin_password =

admin_tenant_name =

allow_reverse_dns_lookup = True

ipv4_ptr_zone_prefix_size = 24

ipv6_ptr_zone_prefix_size = 116

 

/etc/neutron/plugins/ml2/ml2_conf.ini

[ml2]

extension_drivers = port_security, dns

配置完之后,重启neutron server。接下来看看如何在Neutron中使用Designate。

2.3 Neutron with Designate

为了集成DNS功能,Neutron创建网络时,新增了一个参数,“--dns-domain”。虽然这里指定的是DNS domain,但是对应到DNS数据的话,应该是DNS Zone。另外需要注意的是,Neutron创建网络时,如果指定了dns-domain,Neutron是认为对应的DNS Zone已经存在于Designate中,所以为了正常使用,需要先在Designate中创建DNS Zone。一个完整的流程如下所示:

Shell


1

2

3

4

$ openstack zone create --email my@test.com test.org.

$ neutron net-create dns-net --dns-domain test.org.

$ neutron subnet-create --name dns-subnet dns-net 192.168.1.0/24

$ nova boot --image cirros-0.3.5-x86_64-disk --flavor 1 --nic net-name=dns-net vm5

到此为止,DNS似乎应该工作起来了,但是,查看Designate记录,只有默认的记录,感觉不对啊。

OpenStack应用Designate实现DNS服务

其实这是正常的,因为实际上,现在创建的vm5存在于一个tenant network,默认是VXLAN网络,这个网络不能被外部直接访问。所以这个时候就算创建的DNS记录,也没有实际意义。因为解析到了的IP地址是一个虚拟的私网地址,这个IP地址不能被外界访问。OpenStack的文档是这么定义可以被外部访问的网络的:

Shell


1

2

3

The network cannot have attribute router:external set to True.

The network type can be FLAT, VLAN,GRE, VXLAN or GENEVE.

For network types VLAN, GRE, VXLANor GENEVE, the segmentation ID must be outside the ranges assigned to tenant networks.

只有满足这些条件的网络,创建在里面的虚机才会自动设置DNS记录。那对于普通tenant network中的虚机,希望使用DNS,该怎么办?通过配置FloatingIP。配置完FloatingIP,就可以通过FloatingIP访问tenant network中的虚机,这样DNS记录也有存在的意义,所以我们做如下操作:

Shell


1

2

$ neutron router-interface-add router1 dns-subnet

$ neutron floatingip-create public --port-id

这个时候查看Designate记录,可以看到:
OpenStack应用Designate实现DNS服务
我们多了一条A类型的DNS记录,IP地址是FloatingIP地址,hostname是虚机名+虚机所在网络的dns-domain。
此外,查看Designate Zone列表可以发现,多了一个Zone。

OpenStack应用Designate实现DNS服务

这个Zone是管理PTR记录用的,前面说过,PTR记录用来通过IP查找域名。因为我们刚刚在Neutron的配置中加入了这条“allow_reverse_dns_lookup = True”,因此,Neutron会自动创建这个Zone,以及Zone中的RR。

OpenStack应用Designate实现DNS服务

到这里为止,Designate的介绍完成了。可以看出Designate的定位是OpenStack内部的Authoritative DNS server。由于底层连接的是BIND9,PowerDNS等,也支持向上连接到TLD,将定义的DNS域名发送出去。

2.4 结果验证

将Designate所在的主机IP配置到操作系统的DNS server列表中。为了省事,我直接修改了Ubuntu下的/etc/resolv.conf文件。

OpenStack应用Designate实现DNS服务

可以看到系统已经能够完成DNS解析。


上一篇:DNS区域传输漏洞复现


下一篇:kubernetes之pod拓扑分布约束