Installing Puppet on CentOS 6

PLAN

Always plan out your actions on a system before taking them. Think of it like a trial run. By planning out beforehand you are mentally running through the steps and are able to catch any flaws and revise before you start mucking around on a system.

We’re just going to be configuring a stand alone Puppet installation here so this will be pretty short.

  1. Add official Puppet repos
  2. Install Puppet agent
  3. Set up cron job to apply Puppet manifests

ADD OFFICIAL PUPPET REPOS

Puppet helpfully provides their own Yum repository for us to grab what we need. EPEL has it as well, a) their versions of Puppet aren’t typically up to date, b) I try and avoid using EPEL for anything if I can. That second part is a discussion for another time and is only a personal preference.

Adding the Puppet repository is dead simple.

rpm -ivh https://yum.puppetlabs.com/el/6/products/x86_64/puppetlabs-release-6-7.noarch.rpm

This will pull down their RPM and install it. It has the .repo files needed to access their repositories.

INSTALL PUPPET

Again, this is super simple as well. Since we’re only doing a standalone deployment of Puppet here we only need to worry about a single package.

yum install puppet

ADD CRON JOB TO APPLY PUPPET MANIFESTS

In a standalone deployment of Puppet you really only need a cron job to read from the site.pp manifest and apply it on a regular basis. Puppet makes this easy to do without needed to edit crontab directly.

puppet resource cron puppet-agent ensure=present user=root minute=30 command='/usr/bin/puppet agent --onetime --no-daemonize --splay'

Once you run that you’ll see the following output if everything went according to plan.

[root@minimus ~]# puppet resource cron puppet-agent ensure=present user=root minute=30 command='/usr/bin/puppet agent --onetime --no-daemonize --splay'
Notice: /Cron[puppet-agent]/ensure: created
cron { 'puppet-agent':
 ensure => 'present',
 command => '/usr/bin/puppet agent --onetime --no-daemonize --splay',
 minute => ['30'],
 target => 'root',
 user => 'root',
}

And confirm that it was added to the crontab like so.

[root@minimus ~]# crontab -l
# HEADER: This file was autogenerated at Sun Mar 30 15:02:13 -0500 2014 by puppet.
# HEADER: While it can still be managed manually, it is definitely not recommended.
# HEADER: Note particularly that the comments starting with 'Puppet Name' should
# HEADER: not be deleted, as doing so could cause duplicate cron jobs.
# Puppet Name: puppet-agent
30 * * * * /usr/bin/puppet agent --onetime --no-daemonize --splay

Installing BIND as a DNS caching server for your local network.

What’s a caching DNS server and why do I want one?

A caching DNS server’s purpose in life is to pass along DNS requests to an upstream DNS server and then store the response.

This is handy because it shortens the length of time it takes for your browser (or other application) on your local machine to go out and find the associated IP address of the domain you are trying to connect to.

There are some caveats to this of course that mean you may not notice much if any difference in request times.  First, many operating systems cache DNS requests already locally.  Second, if the owner of the domain has set a low TTL (Time To Live) the caching server will still need to lookup DNS requests for that domain frequently.

You’ll likely notice the biggest improvements over time on networks that have multiple systems making DNS requests out as they’ll cause zones to be cached regularly for each other.

Preparing

Whenever you are getting ready to make changes to a system it’s best to plan your steps out as best as possible beforehand.

  1. Configure the DNS servers the server that will be running BIND will send lookups to.
  2. Install the BIND packages.
  3. Edit named.conf.
    Add listen IP.
    Allow only queries from the local network.
  4. Test the changes to named.conf.
  5. Start the service.
  6. Add IP tables rules.
  7. Test both locally from the server and remotely from another device on the same network.
  8. Save firewall changes.
  9. Chkconfig named on.

Installing

Configure Upstream DNS Servers

As noted above we’re first going to configure which DNS servers the server will be sending lookups to.  You can do this by either manually editing /etc/resolv.conf, or better yet to ensure that the changes stay persistent between restarts by editing the network startup scripts.  I’ll be showing by editing the network startup scripts.

On CentOS/RHEL installations you’ll find these in /etc/sysconfig/network-scripts/.  The file we want to modify is whichever one is connecting out to your network connection.  They all start with ifcfg-.

In this case for me I have three network cards on this box so the contents of /etc/sysconfig/network-scripts/ looks like the following.

[root@minimus ~]# ll /etc/sysconfig/network-scripts/ifcfg-*
-rw-r--r--. 1 root root 136 Mar 29 10:24 /etc/sysconfig/network-scripts/ifcfg-eth0
-rw-r--r--. 1 root root 281 Mar 29 10:44 /etc/sysconfig/network-scripts/ifcfg-eth1
-rw-r--r--. 1 root root 136 Mar 29 10:24 /etc/sysconfig/network-scripts/ifcfg-eth2
-rw-r--r--. 1 root root 254 Oct 10 09:48 /etc/sysconfig/network-scripts/ifcfg-lo

Loading the correct file in your editor (vi/emacs/please god don’t use nano) should show something like what is below.

DEVICE=eth1
TYPE=Ethernet
UUID=9dbfacd1-de47-48c2-9825-3f1c2000122f
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=none
HWADDR=50:46:5D:A5:3D:40
IPADDR=192.168.1.149
PREFIX=24
GATEWAY=192.168.1.1
DEFROUTE=yes
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
NAME="System eth1"
DNS1=8.8.8.8
DNS2=8.8.4.4

Now you’ll see two lines at the end DNS1, and DNS2. These may or may not be in there depending on how you’ve set your system up at install, if the network interface is a new one, etc. I personally use the Google DNS service at home. The two you see there, 8.8.8.8 and 8.8.4.4, are Google’s DNS servers.

If you don’t have anything set for those two lines you will want to add at least two entries. They can be your ISP’s servers, Google’s DNS service or OpenDNS. It doesn’t really matter, again though you’ll want to have two there just in case one becomes unavailable at some point.

Install the BIND Packages

Next we’ll need to install the BIND packages.  These are available from the base CentOS repos, and honestly if you have any third party repos enabled on your server, I recommend that you disable lookups to them for BIND.

The packages we’ll be installing are bind, bind-libs, and bind-utils.  Its likely that they’ll already be installed if this is a base CentOS server installation.  Running this though will update the versions on your system and ensure that they are installed.

yum install bind bind-libs bind-utils

Which should output something similar to what is below.

[root@minimus ~]# yum install bind bind-libs bind-utils
Loaded plugins: fastestmirror, security
Determining fastest mirrors
* base: yum.singlehop.com
* extras: mirror.anl.gov
* updates: mirror.es.its.nyu.edu
base | 3.7 kB 00:00
base/primary_db | 4.4 MB 00:02
extras | 3.4 kB 00:00
extras/primary_db | 19 kB 00:00
updates | 3.4 kB 00:00
updates/primary_db | 2.5 MB 00:05
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package bind.x86_64 32:9.8.2-0.23.rc1.el6_5.1 will be installed
---> Package bind-libs.x86_64 32:9.8.2-0.17.rc1.el6_4.6 will be updated
---> Package bind-libs.x86_64 32:9.8.2-0.23.rc1.el6_5.1 will be an update
---> Package bind-utils.x86_64 32:9.8.2-0.17.rc1.el6_4.6 will be updated
---> Package bind-utils.x86_64 32:9.8.2-0.23.rc1.el6_5.1 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

======================================================================================================================================================================================================
Package Arch Version Repository Size
======================================================================================================================================================================================================
Installing:
bind x86_64 32:9.8.2-0.23.rc1.el6_5.1 updates 4.0 M
Updating:
bind-libs x86_64 32:9.8.2-0.23.rc1.el6_5.1 updates 879 k
bind-utils x86_64 32:9.8.2-0.23.rc1.el6_5.1 updates 182 k

Transaction Summary
======================================================================================================================================================================================================
Install 1 Package(s)
Upgrade 2 Package(s)

Total download size: 5.0 M
Is this ok [y/N]: y
Downloading Packages:
(1/3): bind-9.8.2-0.23.rc1.el6_5.1.x86_64.rpm | 4.0 MB 00:06
(2/3): bind-libs-9.8.2-0.23.rc1.el6_5.1.x86_64.rpm | 879 kB 00:01
(3/3): bind-utils-9.8.2-0.23.rc1.el6_5.1.x86_64.rpm | 182 kB 00:00
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total 629 kB/s | 5.0 MB 00:08
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
Updating : 32:bind-libs-9.8.2-0.23.rc1.el6_5.1.x86_64 1/5
Installing : 32:bind-9.8.2-0.23.rc1.el6_5.1.x86_64 2/5
Updating : 32:bind-utils-9.8.2-0.23.rc1.el6_5.1.x86_64 3/5
Cleanup : 32:bind-utils-9.8.2-0.17.rc1.el6_4.6.x86_64 4/5
Cleanup : 32:bind-libs-9.8.2-0.17.rc1.el6_4.6.x86_64 5/5
Verifying : 32:bind-libs-9.8.2-0.23.rc1.el6_5.1.x86_64 1/5
Verifying : 32:bind-9.8.2-0.23.rc1.el6_5.1.x86_64 2/5
Verifying : 32:bind-utils-9.8.2-0.23.rc1.el6_5.1.x86_64 3/5
Verifying : 32:bind-libs-9.8.2-0.17.rc1.el6_4.6.x86_64 4/5
Verifying : 32:bind-utils-9.8.2-0.17.rc1.el6_4.6.x86_64 5/5

Installed:
bind.x86_64 32:9.8.2-0.23.rc1.el6_5.1

Updated:
bind-libs.x86_64 32:9.8.2-0.23.rc1.el6_5.1 bind-utils.x86_64 32:9.8.2-0.23.rc1.el6_5.1

Complete!

Edit named.conf

Now we need to edit named.conf to allow BIND to listen on more than just localhost to allow lookups from other devices on the network as well as allow only queries from on the network.

The file is located at /etc/named.conf.  Before making any changes to a configuration file I always make copy of it as a backup.  This allows me to go back to something that works should something go wrong.

cp -p /etc/named.conf{,.bak}

Now open /etc/named.conf up in your editor and you’ll see something similar to what is below.


//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//

options {
 listen-on port 53 { 127.0.0.1; };
 listen-on-v6 port 53 { ::1; };
 directory "/var/named";
 dump-file "/var/named/data/cache_dump.db";
 statistics-file "/var/named/data/named_stats.txt";
 memstatistics-file "/var/named/data/named_mem_stats.txt";
 allow-query { localhost; };
 recursion yes;

dnssec-enable yes;
 dnssec-validation yes;
 dnssec-lookaside auto;

/* Path to ISC DLV key */
 bindkeys-file "/etc/named.iscdlv.key";

managed-keys-directory "/var/named/dynamic";
};

logging {
 channel default_debug {
 file "data/named.run";
 severity dynamic;
 };
};

zone "." IN {
 type hint;
 file "named.ca";
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

The line’s we’ll want to edit are line 11 where it says listen-on port, and line 17 where it says allow-query.

The line numbers may not match up with what you see in your file so be sure to look for those directives specifically.

For the listen-on port directive you’ll want to add the IP address of your server after the localhost IP (127.0.0.1).  It will end up looking like:

listen-on port 53 { 127.0.0.1; 192.168.1.149; };

Then for the allow-query directive you’ll want to add your network’s range after localhost.  It will end up looking like:

allow-query { localhost; 192.168.1.1/24; };

Test named.conf changes

Like writing out a plan / list of steps prior to getting started its equally important to test everything after you’ve made a change to ensure it’s working properly.

BIND comes named-checkconf to ensure the syntax of your named.conf file is correct.  If there are no errors there will be no output.  It’ll look like this.

[root@minimus ~]# named-checkconf /etc/named.conf
[root@minimus ~]#

If there is an error you will see something like below.

[root@minimus ~]# named-checkconf /etc/named.conf
/etc/named.conf:11: missing ';' before '}'
/etc/named.conf:17: missing ';' before '}'

The above error is saying that you forgot to put the ; following the IP address for the listen-on port directive on line 11, and after the network range for the allow-query directive on line 17.

Start the Service

Now that we’ve tested to ensure our configuration file is correct we’ll now start up BIND’s named service.

[root@minimus ~]# service named start

If everything goes according to plan you’ll see :

[root@minimus ~]# service named start
Generating /etc/rndc.key: [ OK ]
Starting named: [ OK ]

Add iptables Rules

Now we need to allow connections to port 53 to the server from the local network.

[root@minimus ~]# iptables -I INPUT -s 192.168.1.0/24 -p tcp --dport 53 -j ACCEPT
[root@minimus ~]# iptables -I INPUT -s 192.168.1.0/24 -p udp --dport 53 -j ACCEPT

These rules aren’t actually saved permanently to the iptables rule set.  And that’s good we don’t want that yet, we haven’t tested.  But if you restart your server at this point these will be lost.

Testing Locally and Remotely

Now we get to test and prove that everything is working as intended.

From the server itself run the following, make sure to replace 192.168.1.149 with the IP address that BIND is running on.

dig @192.168.1.149 google.com

If everything is working right you should see something similar to what is below.


[root@minimus ~]# dig @192.168.1.149 google.com

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.23.rc1.el6_5.1 <<>> @192.168.1.149 google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29960
;; flags: qr rd ra; QUERY: 1, ANSWER: 11, AUTHORITY: 4, ADDITIONAL: 4

;; QUESTION SECTION:
;google.com. IN A

;; ANSWER SECTION:
google.com. 300 IN A 173.194.115.105
google.com. 300 IN A 173.194.115.102
google.com. 300 IN A 173.194.115.99
google.com. 300 IN A 173.194.115.110
google.com. 300 IN A 173.194.115.104
google.com. 300 IN A 173.194.115.98
google.com. 300 IN A 173.194.115.103
google.com. 300 IN A 173.194.115.97
google.com. 300 IN A 173.194.115.96
google.com. 300 IN A 173.194.115.101
google.com. 300 IN A 173.194.115.100

;; AUTHORITY SECTION:
google.com. 172743 IN NS ns2.google.com.
google.com. 172743 IN NS ns1.google.com.
google.com. 172743 IN NS ns3.google.com.
google.com. 172743 IN NS ns4.google.com.

;; ADDITIONAL SECTION:
ns2.google.com. 172740 IN A 216.239.34.10
ns1.google.com. 172740 IN A 216.239.32.10
ns3.google.com. 172740 IN A 216.239.36.10
ns4.google.com. 172740 IN A 216.239.38.10

;; Query time: 49 msec
;; SERVER: 192.168.1.149#53(192.168.1.149)
;; WHEN: Sat Mar 29 12:13:10 2014
;; MSG SIZE rcvd: 340

Note the query time 49msec.  Run the same command again and you should see the query time like what’s below.

;; Query time: 0 msec

Pretty sweet right?

Now do the same test from another device on the network.  And you should get the same results.

Save iptables Changes

Now we can save our iptables changes since we know everything is working correctly by running:

[root@minimus ~]# iptables-save

 Enable BIND to Run at System Start

Lastly we’re going to turn on BIND to run when the system is re/starterted.

[root@minimus ~]# chkconfig named on

Done

That’s it you’ve not got a running DNS caching server on your network.

I did include a link to a book below by Michael W Lucas which covers securing BIND.  I strongly recommend picking it up and reading it over if you plan on running a publicly accessible DNS server, or even if you aren’t.  Having the extra info on hand and the practice of securing your DNS server doesn’t hurt.