Resolver Configuration with CFEngine

/etc/hosts | /etc/resolv.conf | Other Configuration

Documentation on Unix name service lookup configuration with CFEngine: Domain Name System (DNS) setup, including /etc/resolv.conf tips, /etc/hosts management, and more. Service lookups may also be handled by a directory service, such as the Lightweight Directory Access Protocol (LDAP), or set automatically by a Dynamic Host Configuration Protocol (DHCP) server.

I recommend managing all configuration related to name service lookups with CFEngine: unexpected changes to any resolver configuration file may result in hard to diagnose problems.

/etc/hosts

Use hosts(5) records as little as possible. Duplicating DNS records into CFEngine policy may lead to one or the other being incorrect, if an administrator forgets to update both after a change. If many /etc/hosts entries must be used, consider writing a script to map selected records from DNS into /etc/hosts.

Minimal Configuration

Incorrect /etc/hosts entries may cause hard to diagnose problems. I recommend using CFEngine to manage the entire /hosts/hosts file, and only setup a localhost entry:

editfiles:
any::
{
/etc/hosts
AutoCreate
Backup "false"
EmptyEntireFilePlease
IfElapsed 59

AppendIfNoSuchLine "# CFEngine manages this file"
AppendIfNoSuchLine "127.0.0.1 localhost.localdomain localhost"
# Enable following if also using IPv6
#AppendIfNoSuchLine "::1 localhost.localdomain localhost"
}

Also configure localhost records in all the local DNS domains. Include records for both IPv4 and IPv6, as done in the following example for Berkeley Internet Name Domain (BIND):

localhost IN A 127.0.0.1
localhost IN AAAA ::1

Some operating systems use localhost.localdomain by default, while others only set the unqualified localhost, or append the local domain name: localhost.example.org. If supporting multiple operating systems, consult each system to ensure the solution set by CFEngine works everywhere. Changes to DNS records may affect defaults set in e-mail server configuration and other software.

Additional Hosts

If systems need to cache DNS records, either setup a localhost caching DNS server, or use software like nscd(8). These will cache frequently used records, and automatically update when DNS records change. Caching will perform poorly should the Time To Live (TTL) values be set too low. Check the TTL in the zone file, or by using the dig(1) utility:

$ dig +noall +answer -t mx @ns1.example.org example.org
example.org. 100 IN MX 10 mx1.example.org.
example.org. 100 IN MX 10 mx2.example.org.

The TTL of 100 seconds should be increased, as the records will expire from cache far too often. If increasing the TTL is not possible, set manual entries in the /etc/hosts file until the zone file can be fixed. For example, systems running Nagios will need to send pages via e-mail, and must be able to locate the mail servers, especially if the DNS services have failed:

editfiles:
any::
{
/etc/hosts
AutoCreate
Backup "false"
EmptyEntireFilePlease
IfElapsed 59

AppendIfNoSuchLine "# CFEngine manages this file"
AppendIfNoSuchLine "127.0.0.1 localhost.localdomain localhost"

# KLUGE the DNS TTL is set too low to cache: manually configure mail
# servers here so on call monkey still gets pages when DNS down
BeginGroupIfDefined "role_nagios_server"
AppendIfNoSuchLine "192.0.2.24 mx1.example.org"
AppendIfNoSuchLine "192.0.2.25 mx2.example.org"
EndGroup
}

If the mail server records change, the above policy must also be updated!

/etc/resolv.conf

While CFEngine has a resolve statement, I prefer to manage /etc/resolv.conf with an editfiles block.

Use an editfiles block to manage resolv.conf(5), or copy a different resolv.conf depending on what DNS servers the system should use. Client systems will need search or domain options if users want to use unqualified hostnames. Servers should limit or eliminate the search and domain statements if possible, to avoid needless lookups. In this case, servers will need to use fully qualified addresses everywhere.

Name servers could also be set by DHCP, which may better suit unmanaged or roaming clients. Larger sites could also use Anycast to route DNS queries.

Deterministic Variation with modulo

Randomize name servers with classes defined by a strategies statement, or use modulo to vary the resolver in a deterministic fashion. In the example below, local_prep_dir referrers to a local directory on each client where CFEngine has copied the base resolve.conf.

control:
any::
# set variable to 0 or 1, depending on modulus of address
# use this to pick different resolver configuration later
resolver_flavor = ( ExecResult(${cf_script_dir}/modulo 2?
${global.ipv4[eth0]}) )
resolver_dir = ( ${local_prep_dir}/etc/resolver )

realm_dev::
resolver_file = ( ${resolver_dir}/resolv.client.${resolver_flavor} )
forwarder_file = ( ${resolver_dir}/forwarder.client.${resolver_flavor} )

realm_prod::
resolver_file = ( ${resolver_dir}/resolv.prod.${resolver_flavor} )
forwarder_file = ( ${resolver_dir}/forwarder.prod.${resolver_flavor} )

The resolv.client.0 and resolv.client.1 and equivalent files for production realm systems vary the order of the name servers:

$ cat resolv.client.0
nameserver 192.0.2.53
nameserver 192.0.2.54
$ cat resolv.client.1
nameserver 192.0.2.54
nameserver 192.0.2.53

Systems modulo caculates to be even will use the first order, and odd systems the other. If templating the CFEngine configuration files, this order variation could easily be done in a template. Use a copy statement to move the proper resolver_file file, and editfiles to add any required search or domain entries.

Caching Nameserver Configuration

If configuring a caching nameserver with BIND, forwarders may need configuration so that internal nameservers are used instead of the external ones via a recursive query. These can also be varied by system with modulo, via the forwarder_file variable shown in the above example. The forwarder.client.0 and forwarder.client.1 and equivalent files for production realm systems contain forwarders statements, and should be included by the base named.conf on the system.

$ cat forwarder.client.0
forwarders { 192.0.2.53; 192.0.2.54; };
$ cat forwarder.client.1
forwarders { 192.0.2.54; 192.0.2.53; };

Use a copy statement to duplicate the correct file for the system into a forwarders file the named.conf configuration file can reference:

options {
?

forward only;
include "/var/cfengine/prep/etc/named/forwarders";
};

Use a template system to produce these different uses for the same addresses without duplicating the same data between /etc/resolv.conf and caching name server configuration.

Other Configuration

Other files and software, such as nsswitch.conf(5) on Linux or lookupd(8) on Mac OS X may affect service resolution. Identify these on all supported platforms, and ensure CFEngine manages them.