How To Install Puppet To Manage Your Server Infrastructure on Debian Jessie

Puppet, from Puppet Labs, is a configuration management tool that helps system administrators automate the provisioning, configuration, and management of a server infrastructure. Planning ahead and using config management tools like Puppet can cut down on time spent repeating basic tasks, and help ensure that your configurations are consistent and accurate across your infrastructure. Once you get the hang of managing your servers with Puppet and other automation tools, you will free up time which can be spent improving other aspects of your overall setup.

Puppet comes in two varieties, Puppet Enterprise and open source Puppet. It runs on most Linux distributions, various UNIX platforms, and Windows.

In this tutorial, we will cover how to install open source Puppet in an Agent/Master setup. This setup consists of a central Puppet Master server, where all of your configuration data will be managed and distributed from, and all your remaining servers will be Puppet Agent nodes, which can be configured by the puppet master server.

To follow this tutorial, you must have root access to all of the servers that you want to configure Puppet with. If you do not have an existing infrastructure, feel free to recreate the example infrastructure (described below) by following the prerequisite DNS setup tutorial.

Before we get started with installing Puppet, ensure that you have the following prerequisites:

  • Private Network DNS: Forward and reverse DNS must be configured, and every server must have a unique hostname. If you do not have DNS configured, you must use your hosts file for name resolution. We will assume that you will use your private network for communication within your infrastructure.
  • Firewall Open Ports: The Puppet master must be reachable on port 8140.

We will use the following infrastructure to demonstrate how to set up Puppet:

  • Hostname: host1
    • Role: Generic Debian
    • Private FQDN: host1.douglasqsantos.com.br
    • Private IP: 192.168.25.152
  • Hostname: host2
    • Role: Generic Debian
    • Private FQDN: host1.douglasqsantos.com.br
    • Private IP: 192.168.25.153
  • Hostname: host3
    • Role: Generic CentOS
    • Private FQDN: host3.douglasqsantos.com.br
    • Private IP: 192.168.25.154

The puppet agent will be installed on all of these hosts. These hosts will be referenced by their private network interfaces, which are mapped to the “.douglasqsantos.com.br” subdomain in DNS.

Once you have all of the prerequisites, let's move on to creating the Puppet master server!

Create a new Debian Jessie, using “puppet” as its hostname. Add its private network to your DNS with the following details:

  • Hostname: puppet
    • Role: Generic Debian
    • Private FQDN: puppet.douglasqsantos.com.br

Essentially, you need to add an “A” and “PTR” record, and allow the new host to perform recursive queries. Also, ensure that you configure your search domain so your servers can use short hostnames to look up each other.

Using “puppet” as the Puppet master's hostname simplifies the agent setup slightly, because it is the default name that agents will use when attempting to connect to the master.

If you don't want to use the DNS server configuration you can configure the hosts file and add the entries as follow.

vim /etc/hosts
[...]
192.168.25.151	puppet.douglasqsantos.com.br 	puppet
192.168.25.152	host1.douglasqsantos.com.br 	host1
192.168.25.153	host2.douglasqsantos.com.br 	host2
192.168.25.154	host3.douglasqsantos.com.br 	host3

Now we need to set up NTP.

Because it acts as a certificate authority for agent nodes, the puppet master server must maintain accurate system time to avoid potential problems when it issues agent certificates–certificates can appear to be expired if there are time discrepancies. We will use Network Time Protocol (NTP) for this purpose.

Let's install the ntpdate packet

apt-get update && apt-get install ntpdate -y

First, do a one-time time synchronization using the ntpdate command:

ntpdate pool.ntp.org

Your system time will be updated, but you need to install the NTP daemon to automatically update the time to minimize time drift. Install it with the following apt command:

apt-get update && apt-get -y install ntp

It is common practice to update the NTP configuration to use “pools zones” that are geographically closer to your NTP server. In a web browser, go to the NTP Pool Project and look up a pool zone that is geographically close the datacenter that you are using. We will go with the Brazil pool (http://www.pool.ntp.org/zone/br) in our example, because the servers are located in a Curitiba datacenter.

Open ntp.conf for editing let's add the time servers from the NTP Pool Project page to the top of the file:

vim /etc/ntp.conf
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help

driftfile /var/lib/ntp/ntp.drift


# Enable this if you want statistics to be logged.
#statsdir /var/log/ntpstats/

statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable


# You do need to talk to an NTP server or two (or three).
server 0.br.pool.ntp.org
server 1.br.pool.ntp.org
server 2.br.pool.ntp.org
server 3.br.pool.ntp.org

# pool.ntp.org maps to about 1000 low-stratum NTP servers.  Your server will
# pick a different set every time it starts up.  Please consider joining the
# pool: <http://www.pool.ntp.org/join.html>
server 0.debian.pool.ntp.org iburst
server 1.debian.pool.ntp.org iburst
server 2.debian.pool.ntp.org iburst
server 3.debian.pool.ntp.org iburst


# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for
# details.  The web page <http://support.ntp.org/bin/view/Support/AccessRestrictions>
# might also be helpful.
#
# Note that "restrict" applies to both servers and clients, so a configuration
# that might be intended to block requests from certain clients could also end
# up blocking replies from your own upstream servers.

# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer noquery
restrict -6 default kod notrap nomodify nopeer noquery

# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1

# Clients from this (example!) subnet have unlimited access, but only if
# cryptographically authenticated.
#restrict 192.168.123.0 mask 255.255.255.0 notrust


# If you want to provide time to your local subnet, change the next line.
# (Again, the address is an example only.)
#broadcast 192.168.123.255

# If you want to listen to time broadcasts on your local subnet, de-comment the
# next lines.  Please do this only if you trust everybody on the network!
#disable auth
#broadcastclient

Save and exit. Restart NTP to add the new time servers.

systemctl restart ntp

Now that our server is keeping accurate time, let's install the Puppet master software.

There are a variety of ways to install open source Puppet. We will use the debian package called puppetmaster-passenger, which is provided by Puppet Labs. The puppetmaster-passenger package includes the Puppet master plus production-ready web server (Passenger with Apache), which eliminates a few configuration steps compared to using the basic puppetmaster package.

Download the Puppet Labs package: PuppetLabs Repo

cd ~; wget -c https://apt.puppetlabs.com/puppetlabs-release-jessie.deb

Install the package:

dpkg -i puppetlabs-release-jessie.deb

Update apt's list of available packages:

apt-get update

Install the puppetmaster-passenger package:

apt-get install puppetmaster-passenger -y

The Puppet master, Passenger, Apache, and other required packages are now installed. Because we are using Passenger with Apache, the Puppet master process is controlled by Apache, i.e. it runs when Apache is running.

Before continuing, stop the Puppet master by stopping the apache2 service:

systemctl stop apache2

Next, we want to lock the version of Puppet.

Changes from version to version can occasionally cause your Puppet environment to stop working properly. For this reason, you will want to maintain a consistent Puppet version across your entire infrastructure. If you decide to upgrade to a newer version, make sure that you upgrade your master before any agent nodes, as the master cannot manage agents that have a higher version number.

Let's look up the version of our Puppet installation with the following command:

puppet help | tail -n 1

During the time of writing, the output from the previous command is Puppet v3.7.2. We can use apt's pin feature to lock our Puppet install to 3.7.*, which will prevent apt from upgrading Puppet to a higher major release.

Add the following lines to lock the puppet, puppet-common, and puppetmaster-passenger packages to the 3.7.* (change this to match your installed version):

vi /etc/apt/preferences.d/00-puppet.pref
# /etc/apt/preferences.d/00-puppet.pref
Package: puppet puppet-common puppetmaster-passenger
Pin: version 3.7*
Pin-Priority: 501

Save and exit. Your Puppet version is now locked.

The next step is to set up your Puppet master names and certificates.

Puppet uses SSL certificates to authenticate communication between master and agent nodes. The Puppet master acts as a certificate authority (CA), and must generate its own certificates which is used to sign agent certificate requests. We will setup the master's certificates now.

Delete Existing Certificates

Delete any existing SSL certificates that were created during the package install. The default location of Puppet's SSL certificates is /var/lib/puppet/ssl:

rm -rf /var/lib/puppet/ssl

Configure Certificate

When creating the puppet master's certificate, include every DNS name at which agent nodes can contact the master at. In the case of our example, we will use “puppet” and “puppet.douglasqsantos.com.br”, the short hostname and FQDN, respectively.

Edit the master's puppet.conf file. It will look something like the following:

vim /etc/puppet/puppet.conf
#/etc/puppet/puppet.conf
[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$vardir/lib/facter
prerun_command=/etc/puppet/etckeeper-commit-pre
postrun_command=/etc/puppet/etckeeper-commit-post

# Certificate configuration
certname = puppet.douglasqsantos.com.br
dns_alt_names = puppet,puppet.douglasqsantos.com.br

[master]
# These are needed when the puppetmaster is run by passenger
# and can safely be removed if webrick is used.
ssl_client_header = SSL_CLIENT_S_DN
ssl_client_verify_header = SSL_CLIENT_VERIFY

It is important to use assign certname to “puppet” because the Apache/Passenger configuration expects the certificate to be named “puppet.douglasqsantos.com.br”. If you decide that you want a different certname setting, be sure to edit the Apache config file (/etc/apache2/sites-available/puppetmaster.conf) to change the name of the SSL certificate path.

Save and exit.

Generate New Certificate

Now create new CA certificates by running the following command:

puppet master --verbose --no-daemonize

You will see several lines of output saying that SSL keys and certificates are being created. Once you see Notice: Starting Puppet master version 3.7.2, the certificate setup is complete. Press CTRL-C to return to the shell.

Sample Output:

Info: Creating a new SSL key for ca
Info: Creating a new SSL certificate request for ca
Info: Certificate Request fingerprint (SHA256): B4:75:3F:12:74:8B:29:55:C4:E4:A2:56:20:FC:8A:79:9A:8F:C0:5D:92:FD:96:B2:89:59:45:C2:1B:9B:D0:32
Notice: Signed certificate request for ca
Info: Creating a new certificate revocation list
Info: Creating a new SSL key for puppet.douglasqsantos.com.br
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for puppet.douglasqsantos.com.br
Info: Certificate Request fingerprint (SHA256): 00:29:A7:C0:7C:9C:95:81:CE:C7:BA:C1:6E:66:4E:9D:26:6B:D4:C7:25:FC:0F:1E:23:64:D1:20:42:53:4E:15
Notice: puppet.douglasqsantos.com.br has a waiting certificate request
Notice: Signed certificate request for puppet.douglasqsantos.com.br
Notice: Removing file Puppet::SSL::CertificateRequest puppet.douglasqsantos.com.br at '/var/lib/puppet/ssl/ca/requests/puppet.douglasqsantos.com.br.pem'
Notice: Removing file Puppet::SSL::CertificateRequest puppet.douglasqsantos.com.br at '/var/lib/puppet/ssl/certificate_requests/puppet.douglasqsantos.com.br.pem'
Notice: Starting Puppet master version 3.7.2

If you want to look at the cert info of the certificate that was just created, type in the following:

puppet cert list -all

The previous command actually lists all of the signed certificates and unsigned certificate requests. Currently, only the master cert will display, because no other certificates have been added yet:

+ "puppet.douglasqsantos.com.br" (SHA256) 72:05:6A:9D:1E:1E:94:EE:F8:89:60:5A:34:36:41:77:89:D3:72:95:33:2B:58:F8:F2:FD:A1:E9:83:A5:E4:A0 (alt names: "DNS:puppet", "DNS:puppet.douglasqsantos.com.br")

Our Puppet master service is almost ready to be started. Let's take a look at the master configuration first.

The main puppet configuration file, puppet.conf, consists of three sections: [main], [master], and [agent]. As you may have guessed, the “main” section contains global configuration, the “master” section is specific to the puppet master, and the “agent” is used to configure the puppet agent. Aside from the changes we made earlier, the defaults will work fine for a basic setup.

The configuration file has many options which might be relevant to your own setup. A full description of the file is available at Puppet Labs: Main Config File (puppet.conf).

If you want to edit it, run this command:

vim /etc/puppet/puppet.conf

Let's take a look at the main manifest file.

Main Manifest File

Puppet uses a domain-specific language to describe system configurations, and these descriptions are saved to files called “manifests”, which have a .pp file extension. The default main manifest file is located at /etc/puppet/manifests/site.pp. We will cover some basic manifests later, but we will create a placeholder file for now:

touch /etc/puppet/manifests/site.pp

Start Puppet Master

We are now ready to start the Puppet master. Start it by running the apache2 service:

systemctl start apache2

Your Puppet master is running, but it isn't managing any agent nodes yet. Let's learn how to install and add Puppet agents!

The Puppet agent must be installed on any server that the Puppet master will manage. In most cases, this includes every server in your infrastructure. As mentioned in the introduction, the Puppet agent can run on all major Linux distributions, some UNIX platforms, and Windows. Because the installation varies on each OS slightly, we will only cover the installation Debian servers.

Instructions to install Puppet on other platforms are located in the Puppet Labs Docs – be sure to follow the “Install Puppet on Agent Nodes” section for your OS of choice.

Note: It is assumed that all of your Puppet nodes, including agent nodes, are configured to use your DNS. If you are creating a brand new server, make sure to add it to your DNS before installing the Puppet agent otherwise use the /etc/hosts file to set up the configuration.

Sample of /etc/hosts

vim /etc/hosts
[...]
192.168.25.151	puppet.douglasqsantos.com.br 	puppet
192.168.25.152	host1.douglasqsantos.com.br 	host1
192.168.25.153	host2.douglasqsantos.com.br 	host2
192.168.25.154	host3.douglasqsantos.com.br 	host3

Note: All of our example agent nodes, host1 and host2 are Debian Jessie and only the host3 will be CentOS 7. We will repeat this step for each server, so each can be managed by the Puppet master.

On your Puppet agent node, download the Puppet Labs package:

cd ~; wget -c https://apt.puppetlabs.com/puppetlabs-release-jessie.deb

Install the package:

dpkg -i puppetlabs-release-jessie.deb

Update apt's list of available packages:

apt-get update

Install the Puppet agent package (puppet):

apt-get install puppet -y

The puppet agent is disabled by default. To change this.

puppet agent --enable

Lock the Version

As with the Puppet master, we will want to use the apt pin feature to lock the version of the Puppet agent:

Add the following lines to lock the puppet and puppet-common packages to the 3.7.* (change this to match your installed version):

vim /etc/apt/preferences.d/00-puppet.pref
# /etc/apt/preferences.d/00-puppet.pref
Package: puppet puppet-common
Pin: version 3.7*
Pin-Priority: 501

Save and exit. Your Puppet version is now locked.

Configure Agent

Before running the agent, we must make a few configuration changes.

Edit the agent's puppet.conf. It will look exactly like the Puppet master's initial configuration file.

Assuming that the Puppet master is reachable at “puppet”, the agent should be able to connect to the master. If the master is not available at “puppet”, you will need to add the Puppet master's FQDN. We recommend configuring this regardless (substitute the FQDN with your own):

vim /etc/puppet/puppet.conf
#/etc/puppet/puppet.conf
[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$vardir/lib/facter
prerun_command=/etc/puppet/etckeeper-commit-pre
postrun_command=/etc/puppet/etckeeper-commit-post

[agent]
server = puppet.douglasqsantos.com.br

Save and exit.

The Puppet agent is ready to run. Do so by running the following command:

systemctl restart puppet

If everything is configured properly, you should not see any output. The first time you run the Puppet agent, it generates an SSL certificate and sends a signing request to the Puppet master. After the Puppet master signs the agent's certificate, it will be able to communicate with the agent node.

Note: If this is your first Puppet agent, it is recommended that you attempt to sign the certificate on the Puppet master before adding your other agents. Once you have verified that everything works properly, then you can go back and add the remaining agent nodes with confidence.

Install the package:

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

Update apt's list of available packages:

yum check-update

Install the Puppet agent package (puppet):

yum install puppet -y

Enabling the puppet service into the SystemD

systemctl enable puppet 

The puppet agent is disabled by default. To change this.

puppet agent --enable

Lock the Version

As with the Puppet master, we will want to use the Versionlock feature to lock the version of the Puppet agent:

Let's install the Versionlock

yum install yum-versionlock -y

Now we need to lock the puppet version

yum versionlock puppet

Your Puppet version is now locked.

Configure Agent

Before running the agent, we must make a few configuration changes.

Edit the agent's puppet.conf. It will look exactly like the Puppet master's initial configuration file.

Assuming that the Puppet master is reachable at “puppet”, the agent should be able to connect to the master. If the master is not available at “puppet”, you will need to add the Puppet master's FQDN. We recommend configuring this regardless (substitute the FQDN with your own):

vim /etc/puppet/puppet.conf
#/etc/puppet/puppet.conf
[main]
    # The Puppet log directory.
    # The default value is '$vardir/log'.
    logdir = /var/log/puppet

    # Where Puppet PID files are kept.
    # The default value is '$vardir/run'.
    rundir = /var/run/puppet

    # Where SSL certificates are kept.
    # The default value is '$confdir/ssl'.
    ssldir = $vardir/ssl

[agent]
    # The file in which puppetd stores a list of the classes
    # associated with the retrieved configuratiion.  Can be loaded in
    # the separate ``puppet`` executable using the ``--loadclasses``
    # option.
    # The default value is '$confdir/classes.txt'.
    classfile = $vardir/classes.txt

    # Where puppetd caches the local configuration.  An
    # extension indicating the cache format is added automatically.
    # The default value is '$confdir/localconfig'.
    localconfig = $vardir/localconfig

    # Server configuration
    server = puppet.douglasqsantos.com.br

Save and exit.

The Puppet agent is ready to run. Do so by running the following command:

systemctl restart puppet

If everything is configured properly, you should not see any output. The first time you run the Puppet agent, it generates an SSL certificate and sends a signing request to the Puppet master. After the Puppet master signs the agent's certificate, it will be able to communicate with the agent node.

Note: If this is your first Puppet agent, it is recommended that you attempt to sign the certificate on the Puppet master before adding your other agents. Once you have verified that everything works properly, then you can go back and add the remaining agent nodes with confidence.

The first time Puppet runs on an agent node, it will send a certificate signing request to the Puppet master. Before the master will be able to communicate and control the agent node, it must sign that particular agent node's certificate. We will describe how to sign and check for signing requests.

List Current Certificate Requests

On the Puppet master, run the following command to list all unsigned certificate requests:

puppet cert list

If you just set up your first agent node, you will see one request. It will look something like the following, with the agent node's FQDN as the hostname:

"host1.douglasqsantos.com.br" (SHA256) E8:98:80:47:66:B4:2C:5C:E3:1F:8E:63:5F:59:31:70:DB:93:C5:51:94:95:04:62:F3:31:C0:BC:D0:10:2D:6A

Note that there is no + in front of it. This indicates that it has not been signed yet.

Sign A Request

To sign a certificate request, use the puppet cert sign command, with the hostname of the certificate you want to sign. For example, to sign host1.douglasqsantos.com.br, you would use the following command:

puppet cert sign host1.douglasqsantos.com.br

You will see the following output, which indicates that the certificate request has been signed:

Notice: Signed certificate request for host1.douglasqsantos.com.br
Notice: Removing file Puppet::SSL::CertificateRequest host1.douglasqsantos.com.br at '/var/lib/puppet/ssl/ca/requests/host1.douglasqsantos.com.br.pem'

The Puppet master can now communicate and control the node that the signed certificate belongs to.

If you want to sign all of the current requests, use the -all option, like so:

puppet cert sign --all

Revoke Certificates

You may want to remove a host from Puppet, or rebuild a host then add it back to Puppet. In this case, you will want to revoke the host's certificate from the Puppet master. To do this, you will want to use the clean action:

puppet cert clean hostname

The specified host's associated certificates will be removed from Puppet.

View All Signed Requests

If you want to view all of the requests, signed and unsigned, run the following command:

puppet cert list --all

You will see a list of all of the requests. Signed requests are preceded by a + and unsigned requests do not have the +.

+ "host1.douglasqsantos.com.br"  (SHA256) 46:5F:C2:6F:FE:8A:1B:C0:C7:67:DB:65:83:AF:F1:2A:4F:08:38:3C:3F:22:01:74:63:D5:13:25:E4:90:43:10
+ "host2.douglasqsantos.com.br"  (SHA256) 3A:7B:86:EB:6F:99:D6:48:08:54:99:CD:E5:C5:CB:53:85:44:E1:75:97:88:74:A2:1B:6C:1F:1F:CB:D0:16:59
+ "host3.douglasqsantos.com.br"  (SHA256) 53:39:30:99:71:DF:67:87:BA:9B:33:68:AC:8D:99:04:D2:82:71:21:D1:86:3D:28:1E:40:BB:BD:54:22:D4:90
+ "puppet.douglasqsantos.com.br" (SHA256) 72:05:6A:9D:1E:1E:94:EE:F8:89:60:5A:34:36:41:77:89:D3:72:95:33:2B:58:F8:F2:FD:A1:E9:83:A5:E4:A0 (alt names: "DNS:puppet", "DNS:puppet.douglasqsantos.com.br")

Congrats! Your infrastructure is now ready to be managed by Puppet!

Now that your infrastructure is set up to be managed with Puppet, we will show you how to do a few basic tasks to get you started.

How Facts Are Gathered

Puppet gathers facts about each of its nodes with a tool called facter. Facter, by default, gathers information that is useful for system configuration (e.g. OS names, hostnames, IP addresses, SSH keys, and more). It is possible to add custom facts if you need other facts to perform you configurations.

The facts gathered can be useful in many situations. For example, you can create an web server configuration template and automatically fill in the appropriate IP addresses for a particular virtual host. Or you can determine that your server's OS is “Ubuntu”, so you should run the apache2 service instead of httpd. These are basic examples, but they should give you an idea of how facts can be used.

To see a list of facts that are automatically being gathered on your agent node, run the following command:

facter

How The Main Manifest Is Executed

The puppet agent periodically checks in with the puppet master (typically every 30 minutes). During this time, it will send facts about itself to the master, and pull a current catalog–a compiled list of resources and their desired states that are relevant to the agent, determined by the main manifest. The agent node will then attempt to make the appropriate changes to achieve its desired state. This cycle will continue as long as the Puppet master is running and communicating with the agent nodes.

Immediate Execution on a Particular Agent Node

It is also possible initiate the check for a particular agent node manually, by running the following command (on the agent node in question):

puppet agent --test

Running this will apply the main manifest to the agent running the test. You might see output like the following:

Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for host1.douglasqsantos.com.br
Info: Applying configuration version '1471445385'
Notice: Finished catalog run in 0.03 seconds

One-off Manifests

The puppet apply command allows you to execute manifests that are not related to the main manifest, on demand. It only applies the manifest to the node that you run the apply from. Here is an example:

puppet apply /etc/puppet/modules/test/init.pp

Running manifests in this fashion is useful if you want to test a new manifest on an agent node, or if you just want to run a manifest once (e.g. to initialize an agent node to a desired state).

A Simple Manifest

As you may recall, the main manifest file on the Puppet master is located at /etc/puppet/manifests/site.pp.

On the master, edit it now add the following lines to describe a file resource:

vim /etc/puppet/manifests/site.pp
file {'/tmp/example-ip':                                            # resource type file and filename
  ensure  => present,                                               # make sure it exists
  mode    => 0644,                                                  # file permissions
  content => "Here is my Private IP Address: ${ipaddress_eth0}.\n",  # note the ipaddress_eth0 fact
}

Now save and exit. The inline comments should explain the resource that we are defining. In plain English, this will make ensure that all agent nodes will have a file at /tmp/example-ip, with -rw-r--r-- permissions, and text that contains the node's public IP address.

You can either wait until the agent checks in with the master automatically, or you can run the puppet agent --test command (from one of your agent nodes). Then run the following command to print the file:

cat /tmp/example-ip

You should see output that looks like the following (with that node's IP address):

Here is my Private IP Address: 192.168.25.152.

Specify a Node

If you want to define a resource for specific nodes, define a node in the manifest.

On the master, edit site.pp now add the following lines:

vim /etc/puppet/manifests/site.pp

node 'host2', 'host3' {    # applies to host2 and host3 nodes
  file {'/tmp/hosts':    # resource type file and filename
    ensure => present, # make sure it exists
    mode => 0644,
    content => "Only Hosts 2 and 3 servers get this file.\n",
  }
}

node default {}       # applies to nodes that aren't explicitly defined

Save and exit.

Now Puppet will ensure that a file at /tmp/hosts will exist on host2 and host3. You may want to run the puppet agent --test command (from host2 or host3), if you do not want to wait for the scheduled Puppet agent pull.

Note that if you do not define a resource, Puppet will do its best not to touch it. So if you deleted these resources from the manifest, Puppet will not delete the files it created. If you want to have it delete the files, change ensure to absent.

These examples don't do anything useful, but they do prove that Puppet is working properly.

Let's install the sdtlib module on the puppet Master

puppet module install puppetlabs-stdlib

Now let's create a manifest file that will make sure that every puppet agent has an user called support

vim /etc/puppet/manifests/site.pp
node default {
        user { 'support':
          ensure     => present,
          uid        => '5000',
          groups     => $operatingsystem ? {
	      "Debian" => ['adm','sudo'],
	      "CentOS" => ['adm','wheel'],
          },
          shell      => '/bin/bash',
          home       => '/home/support',
          managehome => true,
          password => pw_hash('password', 'SHA-512', 'mysalt'),
        }
}

When the agents check the puppet master that will apply the new manifest and check if the user support exists or not and will make sure the user is going to be create and add to the groups defined.

We can rewrite the same example with the conditional test outside the user resource

vim /etc/puppet/manifests/site.pp
$admgroups = $operatingsystem ? {
        "Debian" => ['adm','sudo'],
        "CentOS" => ['adm','wheel'],
}

node default {
        user { 'support':
          ensure     => present,
          uid        => '5000',
          groups     => $admgroups,
          shell      => '/bin/bash',
          home       => '/home/support',
          managehome => true,
          password => pw_hash('password', 'SHA-512', 'mysalt'),
        }
}

If you are interesting in get all the possible attributes for the resource user please check out: Resource Type: user

Another great thing that we can use here is to create manifest files by function, so let's take a look.

Let's create a file that will control the users that will going to be created.

vim /etc/puppet/manifests/users.pp
# The groups will be selected by the OS
$admgroups = $operatingsystem ? {
        "Debian" => ['adm','sudo'],
        "CentOS" => ['adm','wheel'],
}

# Mary User
user { 'mary':
  ensure     => present,
  uid        => '6000',
  groups     => $admgroups,
  shell      => '/bin/bash',
  home       => '/home/mary',
  managehome => true,
  password => pw_hash('password', 'SHA-512', 'mysalt'),
}

# John User
user { 'john':
  ensure     => present,
  uid        => '7000',
  groups     => $admgroups,
  shell      => '/bin/bash',
  home       => '/home/john',
  managehome => true,
  password => pw_hash('password', 'SHA-512', 'mysalt'),
}

Let's create a file that will control the groups that will going to be created.

vim /etc/puppet/manifests/groups.pp
group { 'ti-admin':
  ensure => present,
  allowdupe  => false,
}

Now let's create the main manifest file

vim /etc/puppet/manifests/site.pp
# /etc/puppet/manifests/site.pp

# The host3 will only get the information about the new users
node 'host3' {
  import "users.pp"
}

# The host2 will get the information about the new groups and users.
node 'host2' {
  import "groups.pp"
  import "users.pp"
}

# All the nodes that are not explicit defined will get the following configuration
node default {
  import "users.pp"
}

Now after the nodes get the new information from the master they will import the configuration that are explicit for each one, this is only another approach that I thought is a good way to maintain the configuration clear.

Now let's use a module. Modules are useful for grouping tasks together. There are many modules available in the Puppet community, and you can even write your own.

On the Puppet master, install the puppetlabs-apache module from forgeapi:

puppet module install puppetlabs-apache

Warning: Do not use this module on an existing Apache setup. It will purge any Apache configurations that are not managed by Puppet.

Now edit site.pp Now add the following lines to install Apache on host2:

vim /etc/puppet/manifest/site.pp
node 'host2' {
  class { 'apache': }             # use apache module
  apache::vhost { 'dqs.local':  # define vhost resource
    port    => '80',
    docroot => '/var/www/html'
  }
}

Save and exit. Now the next time Puppet updates host2, it will install the Apache package, and configure a virtual host called “dqs.local”, listening on port 80, and with a document root /var/www/html.

On host2, run the following command:

puppet agent --test

You should see a bunch of output indicating that Apache is being installed. Once it is complete, go to host2's private IP address. You should see the default Apache welcome page.

Congrats! You have used your first Puppet module!

Here I will show how to create a simple module to configure the NTP server for the agents.

Let's create the directory structure to store the new module

mkdir -p /etc/puppet/modules/dqs-ntp/{files,manifests}

Now let's create the init.pp file

vim /etc/puppet/modules/dqs-ntp/manifests/init.pp
# Defining the class
class dqs-ntp-server {

  # Checking the OS and selecting the ntp name
	$ntp_service = $operatingsystem ? {
          "Debian" => 'ntp',
          "CentOS" => 'ntpd',
	}

  # Copying the ntp.conf from the puppet Master and configuring the permission
	file { "ntp.conf" :
	  path            => "/etc/ntp.conf",
	  owner           => "root",
	  group           => "root",
	  mode            => 644,
	  source          => "puppet:///modules/dqs-ntp/ntp.conf.$operatingsystem",
	}

  # Making sure the packet is installed
	package { "ntp":
	  ensure          => installed,
	}

  # Making sure the service is working and enable, the File["ntp.conf"] is reference of the file declaration above.
	service { "$ntp_service":
	  require         => File["ntp.conf"],
	  subscribe       => File["ntp.conf"],
	  ensure          => running,
	  enable	  => true,
	}

}

Here we are using the ntp.conf.$operatingsystem that will get the operation system of the node and replace with the correct file, because we are running CentOS and Debian.

Let's create the files, starting with the Debian one.

vim /etc/puppet/modules/dqs-ntp/files/ntp.conf.Debian
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help

driftfile /var/lib/ntp/ntp.drift


# Enable this if you want statistics to be logged.
#statsdir /var/log/ntpstats/

statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable


# You do need to talk to an NTP server or two (or three).
server 0.br.pool.ntp.org
server 1.br.pool.ntp.org
server 2.br.pool.ntp.org
server 3.br.pool.ntp.org

# pool.ntp.org maps to about 1000 low-stratum NTP servers.  Your server will
# pick a different set every time it starts up.  Please consider joining the
# pool: <http://www.pool.ntp.org/join.html>
server 0.debian.pool.ntp.org iburst
server 1.debian.pool.ntp.org iburst
server 2.debian.pool.ntp.org iburst
server 3.debian.pool.ntp.org iburst


# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for
# details.  The web page <http://support.ntp.org/bin/view/Support/AccessRestrictions>
# might also be helpful.
#
# Note that "restrict" applies to both servers and clients, so a configuration
# that might be intended to block requests from certain clients could also end
# up blocking replies from your own upstream servers.

# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer noquery
restrict -6 default kod notrap nomodify nopeer noquery

# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1

# Clients from this (example!) subnet have unlimited access, but only if
# cryptographically authenticated.
#restrict 192.168.123.0 mask 255.255.255.0 notrust


# If you want to provide time to your local subnet, change the next line.
# (Again, the address is an example only.)
#broadcast 192.168.123.255

# If you want to listen to time broadcasts on your local subnet, de-comment the
# next lines.  Please do this only if you trust everybody on the network!
#disable auth
#broadcastclient

Now let's create the file that will be provide to the CentOS Box.

vim /etc/puppet/modules/dqs-ntp/files/ntp.conf.CentOS
# For more information about this file, see the man pages
# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).

driftfile /var/lib/ntp/drift

# You do need to talk to an NTP server or two (or three).
server 0.br.pool.ntp.org
server 1.br.pool.ntp.org
server 2.br.pool.ntp.org
server 3.br.pool.ntp.org

# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
restrict default nomodify notrap nopeer noquery

# Permit all access over the loopback interface.  This could
# be tightened as well, but to do so would effect some of
# the administrative functions.
restrict 127.0.0.1
restrict ::1

# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap

# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst

#broadcast 192.168.1.255 autokey	# broadcast server
#broadcastclient			# broadcast client
#broadcast 224.0.1.1 autokey		# multicast server
#multicastclient 224.0.1.1		# multicast client
#manycastserver 239.255.254.254		# manycast server
#manycastclient 239.255.254.254 autokey # manycast client

# Enable public key cryptography.
#crypto

includefile /etc/ntp/crypto/pw

# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography.
keys /etc/ntp/keys

# Specify the key identifiers which are trusted.
#trustedkey 4 8 42

# Specify the key identifier to use with the ntpdc utility.
#requestkey 8

# Specify the key identifier to use with the ntpq utility.
#controlkey 8

# Enable writing of statistics records.
#statistics clockstats cryptostats loopstats peerstats

# Disable the monitoring facility to prevent amplification attacks using ntpdc
# monlist command when default restrict does not include the noquery flag. See
# CVE-2013-5211 for more details.
# Note: Monitoring will not be disabled with the limited restriction flag.
disable monitor

Now let's chnage the main manifest to import the new configuration.

vim /etc/puppet/manifests/site.pp
# Importing the new module
import 'dqs-ntp'

# Defining the configurations that will be applied to host3
node 'host3' {
	import "groups.pp"
	import "users.pp"
	# This include directive will call the class dqs-ntp-server and apply all the configuration inside
	include dqs-ntp-server
}


# Defining the configurations that will be applied to host2
node 'host2' {
	import "groups.pp"
	import "users.pp"
	# This include directive will call the class dqs-ntp-server and apply all the configuration inside
	include dqs-ntp-server
}

node default {
	import "users.pp"
}

Now we can run the test on the nodes

puppet agent --test

The output of the command will be something like

Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Info: Caching catalog for host3.douglasqsantos.com.br
Info: Applying configuration version '1471460531'
Notice: /Stage[main]/Dqs-ntp-server/File[ntp.conf]/ensure: defined content as '{md5}ffbb3a264866216420055aaae0ab22d4'
Info: /Stage[main]/Dqs-ntp-server/File[ntp.conf]: Scheduling refresh of Service[ntpd]
Notice: /Stage[main]/Dqs-ntp-server/Package[ntp]/ensure: created
Notice: /Stage[main]/Dqs-ntp-server/Service[ntpd]/ensure: ensure changed 'stopped' to 'running'
Info: /Stage[main]/Dqs-ntp-server/Service[ntpd]: Unscheduling refresh on Service[ntpd]
Notice: Finished catalog run in 3.27 seconds

Now we can check if the service is running on CentOS

systemctl status ntpd
● ntpd.service - Network Time Service
   Loaded: loaded (/usr/lib/systemd/system/ntpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2016-08-17 16:02:14 BRT; 48s ago
 Main PID: 22762 (ntpd)
   CGroup: /system.slice/ntpd.service
           └─22762 /usr/sbin/ntpd -u ntp:ntp -g

Aug 17 16:02:14 host3.douglasqsantos.com.br ntpd[22762]: Listen normally on 2 lo 127.0.0.1 UDP 123
Aug 17 16:02:14 host3.douglasqsantos.com.br ntpd[22762]: Listen normally on 3 enp0s3 192.168.25.117 UDP 123
Aug 17 16:02:14 host3.douglasqsantos.com.br ntpd[22762]: Listen normally on 4 lo ::1 UDP 123
Aug 17 16:02:14 host3.douglasqsantos.com.br ntpd[22762]: Listen normally on 5 enp0s3 fe80::a00:27ff:fe1b:45f5 UDP 123
Aug 17 16:02:14 host3.douglasqsantos.com.br ntpd[22762]: Listening on routing socket on fd #22 for interface updates
Aug 17 16:02:14 host3.douglasqsantos.com.br systemd[1]: Started Network Time Service.
Aug 17 16:02:17 host3.douglasqsantos.com.br ntpd[22762]: 0.0.0.0 c016 06 restart
Aug 17 16:02:17 host3.douglasqsantos.com.br ntpd[22762]: 0.0.0.0 c012 02 freq_set kernel 0.000 PPM
Aug 17 16:02:17 host3.douglasqsantos.com.br ntpd[22762]: 0.0.0.0 c011 01 freq_not_set
Aug 17 16:02:17 host3.douglasqsantos.com.br ntpd[22762]: 0.0.0.0 c614 04 freq_mode

Now that you have a basic agent/master Puppet installation, you are now ready to learn more about how to use Puppet to manage your server infrastructure.

References