Configuration and change management are extremely important in keeping a production environment running smoothly with high uptime. Puppet does a fantastic job of distributing and enforcing configurations, while Subversion is good for keeping an audit trail of configuration changes. Putting the two together gives you a world-class solution that easily scales into the tens of thousands of servers.
First, setup a Subversion repository and server. This can be done in under four minutes by following this excellent guide. For purposes of brevity, hereafter we'll just assume that svn://svnserve/var/svn/puppet is where all the Puppet files are being kept. The Subversion server does not need to be on the same server that will become the Puppetmaster; it can be anywhere. For the rest of this document we'll assume your Subversion repository exists as /var/svn.
Next, add a user account to Subversion that Puppet will use to checkout files. Edit the /var/svn/conf/passwd file and add the following line to the end of the file:
puppet=puppet
For added security, this user should only be able to checkout files, and not checkin files.
Configure svnserve to start on boot, and start the daemon (this assumes a Red Hat-ish system with Subversion installed from RPMs):
$ sudo chkconfig svnserve on $ sudo service svnserve start
Now install Puppet on the server that is to become the Puppetmaster:
$ sudo yum install puppet-server
You'll want to install the client RPM (puppet) everywhere, including on the Puppetmaster server (it can be a client of itself.) Only install the server RPM (puppet-server) on the Puppetmaster.
Once Puppet is installed, go to the /etc directory and setup an initial module for controlling the /etc/sudoers file (it's as good a starting place as any other):
$ sudo mkdir -p /etc/puppet/modules/sudo/manifests
Create the /etc/puppet/modules/sudo/manifests/init.pp file with the following contents:
class sudo { file { "/etc/sudoers": owner => root, group => root, mode => 440, source => "puppet:///sudo/sudoers", } }
The block of code instructs Puppet to create the file /etc/sudoers if it does not exist; ensure that it is owned by root:root at all times; is always read-only to the owner and group, with no access to the world; and that the file's contents exactly match puppet:///sudo/sudoers, which we'll create next.
Create the directory that will hold our master sudoers file:
$ sudo mkdir -p /etc/puppet/modules/sudo/files
Grab a copy of sudoers from somewhere (the local server unless you have a more authoritative copy) and put it in the directory you just created:
$ sudo cp /etc/sudoers /etc/puppet/modules/sudo/files/
WARNING: this is the file that will shortly overwrite every single other sudoers file in your environment. If nothing else, make sure you yourself exist in it!
For the sake of convenience, change the permissions on the file (remember, the permissions that the file is given when it is deployed by Puppet are governed by the configuration file init.pp, and not by the permissions found on the source file):
$ sudo chmod 644 /etc/puppet/modules/sudo/files/sudoers
We will now instruct Puppet to import our shiny new module. Create and edit the /etc/puppet/manifests/modules.pp file, and place the following line in it:
import "sudo"Let's also create the /etc/puppet/manifests/nodes.pp file, which we'll use in the future as we add more files beyond sudoers to Puppet:
node basenode { include sudo }
Last but not least, we will now create the /etc/puppet/manifests/site.pp file with the following content:
import "modules" import "nodes" filebucket { main: server => puppet } File { backup => main } Exec { path => "/usr/bin:/usr/sbin/:/bin:/sbin:/usr/local/bin:/usr/local/sbin" } node default { include sudo }
At this point you should have a /etc/puppet directory structure that looks like this:
$ find /etc/puppet /etc/puppet /etc/puppet/manifests /etc/puppet/manifests/site.pp /etc/puppet/manifests/modules.pp /etc/puppet/manifests/nodes.pp /etc/puppet/puppet.conf /etc/puppet/fileserver.conf /etc/puppet/modules /etc/puppet/modules/sudo /etc/puppet/modules/sudo/manifests /etc/puppet/modules/sudo/manifests/init.pp /etc/puppet/modules/sudo/files /etc/puppet/modules/sudo/files/sudoers
Import put the entire /etc/puppet directory and its contents into Subversion:
$ cd /etc $ svn import ./puppet svn://svnserve/var/svn/puppet -m "Add initial Puppet configuration directories"
Make sure the directories and files were successfully imported:
$ svn list -vR svn://svnserve/var/svn/puppet 24507 puppet 381 May 22 18:47 fileserver.conf 24507 puppet May 22 18:47 manifests/ 24507 puppet 14 May 22 18:47 manifests/modules.pp 24507 puppet 32 May 22 18:47 manifests/nodes.pp 24507 puppet 177 May 22 18:47 manifests/site.pp 24507 puppet May 22 18:47 modules/ 24507 puppet May 22 18:47 modules/sudo/ 24507 puppet May 22 18:47 modules/sudo/files/ 24507 puppet 151 May 22 18:47 modules/sudo/files/sudoers 24507 puppet May 22 18:47 modules/sudo/manifests/ 24507 puppet 129 May 22 18:47 modules/sudo/manifests/init.pp 24507 puppet 979 May 22 18:47 puppet.conf
You'll note that I checked them in as myself; it's a good idea to never use the puppet Subversion user for anything other than checkout.
Next, rename or delete the existing directory:
$ sudo mv /etc/puppet /etc/puppet.orig
Now edit the /etc/crontab file and add the following line to the bottom of the file:
* * * * * root cd /etc && svn --username puppet --password puppet checkout svn://svnserve/var/svn/puppet
Wait a moment, and the /etc/puppet directory should reappear. If it does not, check the cron line and verify that you correctly setup the puppet user in Subversion.
It's a good idea at this point to create a DNS alias (CNAME) record named puppet that points to your Puppetmaster's FQHN. Both the Puppet client and server strongly prefer to talk to a host named puppet as the master, and it's a lot of fighting to get it to behave otherwise. Throw the alias in, and your life will be a lot easier.
Initialize the Puppetmaster for the first time by running:
$ sudo puppetmasterd --mkusers
Enable starting the Puppetmaster at boot, and then restart the daemon (the above command will have started it):
$ sudo chkconfig puppetmaster on $ sudo service puppetmaster restart
We now need to setup our first Puppet client. The mechanism for adding a client to the Puppetmaster is as follows:
- Have the client contact the server and ask to be authorized
- Instruct the server to authorize the client
- The client will discover that it is now authorized and begin policy enforcement
Install Puppet on the server that is to become a Puppet client:
$ sudo yum install puppet
Now have the Puppet client send its certificate to the Puppetmaster:
$ sudo puppetd --waitforcert 90 --test
Go to the server, and run:
$ sudo puppetca --list
This should list the hostname of the new Puppet client. To sign the client's certificate, run:
$ sudo puppetca --sign hostname
Note: If you have many clients, you can accomplish this step in one line by running:
$ for client in `sudo puppetca --list`; do sudo puppetca --sign $client; done
Test the Puppet client connection by running:
$ sudo puppetd --test
You should see output like the following:
notice: Ignoring cache
info: Caching configuration at /var/lib/puppet/localconfig.yaml
notice: Starting configuration run
notice: Finished configuration run in 0.11 secondsFurthermore, if everything is working correctly, the /etc/sudoers file on your client should have been overwritten with the master copy. You can try altering it (for example, by adding a comment to it) and then running puppetd --test again:
notice: Ignoring cache
info: Caching configuration at /var/lib/puppet/localconfig.yaml
notice: Starting configuration run
notice: /Class[main]/Node[default]/Class[sudo]/File[/etc/sudoers]/checksum: checksum changed '{md5}4dbc63b33c8a8f5ff3e41f3d6a996576' to '{md5}46b4b281acb865468616f3208f111c3c'
info: /Class[main]/Node[default]/Class[sudo]/File[/etc/sudoers]: Filebucketed to main with sum 46b4b281acb865468616f3208f111c3c
notice: /Class[main]/Node[default]/Class[sudo]/File[/etc/sudoers]/source: replacing from source puppet:///sudo/sudoers with contents {md5}4dbc63b33c8a8f5ff3e41f3d6a996576
notice: Finished configuration run in 0.30 secondsLast but not least, enable the Puppet client to start at system boot:
$ sudo chkconfig puppet on $ sudo service puppet restart
That's it! You now have a working Subversion, Puppetmaster, and Puppet client network setup, with your /etc/sudoers file under Puppet control. For more information, see the Puppet recipes here and read the Puppet documentation here.
Good luck!
