A cookbook to manage bind DNS servers, and zones.
Included ldap2zone recipe depends on Chef 0.10.10 features,
such as chef_gem
.
The net-ldap v0.2.2 Ruby gem is required for the ldap2zone recipe.
-
bind['masters']
- Array of authoritative servers which you transfer zones from.
- Default empty
-
bind['ipv6_listen']
- Boolean, whether BIND should listen on ipv6
- Default is false
-
bind['acl-role']
- Search key for pulling split-domain ACLs out of
data_bags
- Defaults to internal-acl, and has no effect if you do not need ACLs.
- Search key for pulling split-domain ACLs out of
-
bind['acl']
- An array node attribute which
data_bag
ACLs are pushed on to, and then passed to named.options template. - Default is an empty array.
- An array node attribute which
-
bind['allow-query']
- Array of ACL names to allow queries.
- Defaults to localhost and local networks.
-
bind['allow-query-cache']
- Array of ACL names to allow answers from cache.
- Defaults to value of 'allow-query' option.
-
bind['allow-recursion']
- Array of ACL names to allow recursive queries.
- Defaults to value of 'allow-query' option.
-
bind['recursion']
- Explicitly set recursion posibility. Boolean.
- Defaults to true
-
bind['zones']['attribute']
- An array attribute where zone names may be set from role
attributes. The dynamic source attributes
bind['zones']['ldap']
andbind['zones']['databag']
will be combined with zone names set via role attributes before the named.conf template is rendered.
- An array attribute where zone names may be set from role
attributes. The dynamic source attributes
-
bind['zones']['ldap']
- An array attribute where zone names may be set from an ldap source.
-
bind['zones']['databag']
- An array attribute where zone names may be set from a databag source.
-
bind['zones']['zones']
- An array of hashs of all described zones.
-
bind['zonetype']
- The zone type, master, or slave for configuring the named.conf template.
- Defaults to slave
-
bind['zonesource']
- The external zone data source, included examples are databag or ldap
- Defaults to databag. Should have no effect if no zone names
exist in the bind
data_bag
.
-
bind['options']
- Free form options for named.conf template
- Defaults to an empty array.
-
bind['allow_solo_search']
- Boolean true/false, enabling chef-solo search
- Defaults to false
-
bind['enable_log']
- Boolean, toggle bind query logging. Note this applies only to a dedicated log, such as a query log. i.e. bind may still log to the messages/kernel log if configured to do so with syslog.
- Default to false
-
bind['log_file']
- Absolute path to bind log file, assuming directory exists. Again, this has no effect on syslog configuration.
- Default to
/var/log/bind9/query.log
-
`bind['statistics-channel']
- Boolean to enable a statistics-channel on a TCP port.
- Default, platform-specific
-
`bind['statistics-port']
- Integer for statistics-channel TCP port.
- Default, 8080
-
bind['packages']
- packages to install
- Platform specific defaults
-
bind['sysconfdir']
- etc directory for named
- Platform specific defaults
-
bind['conf_file']
- Full path to named.conf
- Platform specific defaults
-
bind['options_file']
- Full path to named.conf.options
- Platform specific defaults
-
bind['views_file']
- Full path to named.conf.views
-
bind['vardir']
- var directory for named to write state data, such as zone files.
- Platform specific defaults
-
bind['included_files']
- Files to be included in named.conf, relative to sysconf (/etc/named, /etc/bind) directory. You could, for example, drop off other static files or templates in your sysconf directory. Then include them in your named.conf by overriding this attribute.
- Defaults to named.rfc1912.zones, and named.options
-
bind['var_cookbook_files']
- static cookbook files to drop off in var directory
- defaults to named.empty, named.ca, named.loopback, and named.localhost
-
bind['rndc_keygen']
- command to generate rndc key
- default depends on hardware/hypervisor platform
-
bind['log_options']
- Array listing all specific bind logging options
- default is empty
-
bind['rndc-key']
- Location which rndc.key gets created by rndc-confgen
We store our zone names on Active Directory, and use Ruby to pull these into Chef and configure our Linux BIND servers. If you already have Active Directory, chances are you have an authoritative data source for zone names in LDAP and can use this recipe to query this data, just by setting a few attributes in a role.
-
bind['ldap']['binddn']
- The binddn username for connecting to LDAP
- Default nil
-
bind['ldap']['bindpw']
- The binddn password for connecting to LDAP
- Default nil
-
bind['ldap']['filter']
- The LDAP object filter for zone names
- Defaults to dnsZone class, excluding Root DNS Servers
-
bind['ldap'][server']
- The authoritative directory server for your domain
- Defaults to nil
-
bind['ldap']['domainzones']
- The LDAP tree where your domain zones are located
- Defaults to the Active Directory zone tree for example.com.
The databag2zone and ldap2zone is optional code to fetch DNS zones from a data bag, or Active Directory integrated domain controllers. If you have a proper IP address management (IPAM) solution, you could drop in your own code to query an API on your IPAM server.
Any query should use the <<
operator to push results on to the
bind['zones']
array. Drop your query code in a recipe
named query2zone.rb
, for example. Then include the API query
by overriding the attribute bind['zonesource']
set to the
string query
.
Alternatively, you can just use an override['bind']['zones']
in
a role or environment instead. Or even a mix of both override
attributes, and an API query to populate zones.
The zonefiles is optional recipe to generate complete zone from data bag. It is only generate all zones in specific data bag (currently 'zones'), but not include them to bind config.
To load zones into config set them as array as follows:
bind["zones"]["attribute"] = ['example.com', 'example.org']
An example wrapper cookbook for an internal split-horizon BIND server for example.com, might look like so:
# Configure and install Bind to function as an internal DNS server."
# attributes/default.rb
include_attribute 'bind'
default['bind']['acl-role'] = 'internal-acl'
default['bind']['masters'] = %w(192.0.2.10 192.0.2.11 192.0.2.12)
default['bind']['ipv6_listen'] = true
default['bind']['zonetype'] = 'slave'
default['bind']['zonesource'] = 'ldap'
default['bind']['zones']['attribute'] = %w(example.com example.org)
default['bind']['ldap'] = {
server: 'example.com',
binddn: 'cn=chef-ldap,ou=Service Accounts,dc=example,dc=com',
bindpw: 'ServiceAccountPassword',
domainzones: 'cn=MicrosoftDNS,dc=DomainDnsZones,dc=example,dc=com'
}
default['bind']['options'] = [
'check-names slave ignore;',
'multi-master yes;',
'provide-ixfr yes;',
'recursive-clients 10000;',
'request-ixfr yes;',
'allow-notify { acl-dns-masters; acl-dns-slaves; };',
'allow-query { example-lan; localhost; };',
'allow-query-cache { example-lan; localhost; };',
'allow-recursion { example-lan; localhost; };',
'allow-transfer { acl-dns-masters; acl-dns-slaves; };',
'allow-update-forwarding { any; };',
]
# recipes/default.rb
include_recipe 'bind'
An example wrapper cookbook for an external split-horizon authoritative only BIND server for example.com, might look like so:
# Configure and install Bind to function as an external DNS server."
# attributes/default.rb
include_attribute 'bind'
default['bind']['acl-role'] = 'external-acl'
default['bind']['masters'] = %w(192.0.2.5 192.0.2.6)
default['bind']['ipv6_listen'] = true
default['bind']['zonetype'] = 'master'
default['bind']['zones']['attribute'] = %w(example.com example.org)
default['bind']['options'] = [
'recursion no;',
'allow-query { any; };',
'allow-transfer { external-private-interfaces; external-dns; };',
'allow-notify { external-private-interfaces; external-dns; localhost; };',
'listen-on-v6 { any; };'
]
# recipes/default.rb
include_recipe 'bind'
In order to include an external ACL for the private interfaces of your external nameservers, you can create a data bag like so.
- data_bag name: bind
- id: ACL entry name
- role: search key for bind data_bag
- hosts: array of CIDR addresses, or IP addresses
{
"id": "external-private-interfaces",
"role": "external-acl",
"hosts": [ "192.0.2.15", "192.0.2.16", "192.0.2.17" ]
}
In order to include an internal ACL for the query addresses of your LAN, you might create a data bag like so.
- data_bag name: bind
- id: ACL entry name
- role: search key for bind data_bag
- hosts: array of CIDR addresses, or IP addresses
{
"id": "example-lan",
"role": "internal-acl",
"hosts": [ "192.0.2.18", "192.0.2.19", "192.0.2.20" ]
}
If you have a few number of zones, you can split these up into individual data bag objects if you prefer.
- data_bag name: bind
- zone: string representation of individual zone name.
{
"id": "example",
"zone": "example.com"
}
If you wish to group a number of zones together, you can use the following format to include a number of zones at once.
- data_bag name: bind
- zones: array representation of several zone names.
{
"id": "example",
"zones": [ "example.com", "example.org" ]
}
serial
is generated automagicaly.
- data_bag: zones
{ "id" : "example-com",
"domain" : "example.com",
"type": "master",
"allow_transfer": [ "192.168.0.2", "192.168.0.3" ],
"zone_info": {
"global_ttl": 300,
"soa": "ns.example.com.",
"contact": "admin.example.com",
"nameserver": [ "ns1.example.com." ],
"mail_exchange": [{
"priority": 10,
"host": "ASPMX.L.GOOGLE.COM."
},{
"priority": 20,
"host": "ALT1.ASPMX.L.GOOGLE.COM."
},{
"priority": 20,
"host": "ALT2.ASPMX.L.GOOGLE.COM."
},{
"priority": 30,
"host": "ASPMX2.GOOGLEMAIL.COM."
},{
"priority": 30,
"host": "ASPMX3.GOOGLEMAIL.COM."
},{
"priority": 30,
"host": "ASPMX4.GOOGLEMAIL.COM."
},{
"priority": 30,
"host": "ASPMX5.GOOGLEMAIL.COM."
}],
"records": [
{"name": "www", "type": "A", "value": "192.168.0.4"},
{"name": "ns1", "type": "A", "value": "192.168.0.5"},
{"name": "ns2", "type": "A", "value": "192.168.0.6"}
]
}
}
Attributes example
"bind" => {
"views" => {
"internal" => {
"match-clients" => [ "internals" ],
"allow-transfer" => [ "none" ],
"recursion" => true,
"zones" => ["example-org-internal"]
},
"external" => {
"match-clients" => [ "any" ],
"allow-transfer" => [ "localhost" ],
"zones" => ["example-org-external", "domain.com"]
}
}
}
As the name of the zone, you can use the id of the data_bag item as well as the domain name, the recipe now support both.
Copyright: 2011 Eric G. Wolfe Copyright: 2014 Eugene Alekseev Copyright: 2014 Alexey Mochkin
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.