Search icon CANCEL
Cart icon
Close icon
You have no products in your basket yet
Save more on your purchases!
Savings automatically calculated. No voucher code required
Arrow left icon
All Products
Best Sellers
New Releases
Learning Hub
Free Learning
Arrow right icon
Save more on purchases! Buy 2 and save 10%, Buy 3 and save 15%, Buy 5 and save 20%
Learning Puppet Security
Learning Puppet Security

Learning Puppet Security: Secure your IT environments with the powerful security tools of Puppet

$35.99 $9.99
Book Mar 2015 236 pages 1st Edition
$35.99 $9.99
$15.99 Monthly
$35.99 $9.99
$15.99 Monthly

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now
Table of content icon View table of contents Preview book icon Preview Book

Learning Puppet Security

Chapter 1. Puppet as a Security Tool

Imagine you're sitting at home one day after a long day of work. Suddenly, you get a phone call that a new security vulnerability was found and all 300 of your servers will need to be patched. How would you handle it?

With Puppet, finding which one of your servers was vulnerable would be an easier task than doing so by hand. Furthermore, with a little additional work, you could ensure that every one of your servers is running a newer nonvulnerable version of the Puppet package.

In this chapter, we will touch on the following concepts:

  • What is Puppet?

  • Declarative versus imperative systems

  • The Puppet client-server model

  • Other components of the Puppet ecosystem used for security

  • Installing Puppet

  • How Puppet fits into a security role

Once this is complete, we will build the environment we'll use to run examples in this book and then run our first example.

Much of the information in this chapter is presented as a guide to what we will accomplish later on in this book.

What is Puppet?

The Puppet Labs website describes open source Puppet as follows:

Open source Puppet is a configuration management system that allows you to define the state of your IT infrastructure, then automatically enforces the correct state.

What does this mean, though?

Puppet is a configuration management tool. A configuration management tool is a tool that helps the user specify how to put a computer system in a desired state. Other popular tools that are considered as configuration management tools are Chef and CFEngine. There are also a variety of other options that are gaining a user base, such as Bcfg2 and Salt.

Chef is another configuration management tool. It uses pure Ruby Domain-specific Language (DSL) similar to Puppet. We'll cover what a domain-specific language is shortly. This difference allows you to write the desired state of your systems in Ruby. Doing so allows one to use the features of the Ruby language, such as iteration, to solve some problems that can be more difficult to solve in the stricter domain-specific language of Puppet. However, it also requires you to be familiar with Ruby programming. More information on Chef can be found at

CFEngine is the oldest of the three main tools mentioned here. It has grown into a very mature platform as it has expanded. Puppet was created out of some frustrations with CFEngine. One example of this is that the CFEngine community was formally quite closed, that is, they didn't accept user input on design decisions. Additionally, there was a focus in CFEngine on the methods used to configure systems. Puppet aimed to be a more open system that was community-focused. It also aimed to make the resource the primary actor, and relied on the engine to make necessary changes instead of relying on scripts in most cases.


Many of these issues were addressed in CFEngine 3, and it retains a very large user base. More information on CFEngine can be found at

Bcfg2 and Salt are both tools that are gaining a user base. Both written in Python, they provide another option for a user who may be more familiar with Python than other languages. Information on these tools, as well as a list of others that are available, can be found at

Configuration management tools were brought about by a desire to make system administration work repeatable, as well as automate it.

In the early days of system administration, it was very common for an administrator to install the operating system needed as well as install any necessary software packages. When systems were simple and few in number, this was a low effort way of managing them.

As systems grew more complex and greater numbers of them were installed, this became much more difficult. Troubleshooting an application as it began to run on multiple systems also became difficult. The difference in software versions on installed nodes and other configuration differences created inconsistencies in the behavior of multiple systems that were running the same application. Installation manuals, run books, and other forms of documentation were often deployed to try to remedy this, but it was clear that we needed a better way.

As time moved on, system administrators realized that they needed a better way to manage their systems. A variety of methods were born, but many of them were home built. They often used SSH to manage remote hosts. I also built several such systems at various places before coming across Puppet.

Puppet sought to ease the pain and shortcomings of the early days. It was a big change from anything that was present at the time. A large part of this was because of its declarative nature.

Declarative versus imperative approaches

At the core of Puppet is software that allows you to specify the state of the system and let Puppet get the system there. It differs from many of the other products in the configuration management space due to its declarative nature.

In a declarative system, we model the desired state of the resources (things being managed).

Declarative systems have the following properties:

  • Desired state is expressed, not steps used to get there

  • Usually no flow control, such as loops; it may contain conditional statements

  • Actions are normally idempotent

  • Dependency is usually explicitly declared


The concept of actions being idempotent is a very important one in Puppet. It means that actions can be repeated without causing unnecessary side effects. For example, removing a user is idempotent, because removing it when it doesn't exist causes no side effects. Running a script that increments to the next user ID and creates a user may not be idempotent, because the user ID might change.

Imperative systems, on the other hand, use algorithms and steps to express their desired state. Most traditional programming languages, such as C and Java, are considered imperative. Imperative systems have the following properties:

  • They use algorithms to describe the steps to the solution

  • They use flow control to add conditionals and loops

  • Actions may not be idempotent

  • Dependency is normally executed by ordering

In Puppet, which is declarative, the users can describe how they want the system to look in the end, and leave the implementation details of how to get there up to the types and providers within Puppet. Puppet uses types, which represent resources, such as files or packages. Each type can optionally be implemented by one or more provider.

Types provide the core functionality available in Puppet. The type system is extensible, and additional types can be added using pure Ruby code. Later on in this chapter, we'll use the file and package types in our example.

Providers include the code for the type that actually does the low level implementation of a resource. Many types have several providers that implement their functionality in different ways. An example of this is the package type. It has providers for RPM, Yum, dpkg, Windows using MSI, and several others. While it is not a requirement that all types have multiple providers, it is not uncommon to see them, especially for resources that have different implementation details across operating systems.

This system of types and providers isolates the user from having to have specific knowledge of how a given task is done. This allows them to focus on how the system should be configured, and leave specific implementation details, such as how to put it in that state, to Puppet.

A few tools, such as Chef, actually use more of a hybrid approach. They can be used in a declarative state, but also allow the use of loops and other flow control structures that are imperative. Puppet is slowly starting to gain some support for this in their new future parser, however these are experimental and advanced features at this point.

While the declarative approach may have a larger learning curve, especially around dependency management, many sysadmins find it a much better fit with their way of thinking once they learn how it works.

The Puppet client-server model

Puppet uses a client-server model in the most common configurations. In this mode, one or more systems, called Puppet Masters, contain files called manifests. Manifests are code written in the Puppet DSL. A DSL is a language designed to be used for a specific application. In this case, the language is used to describe the desired state of a system. This differs from more general purpose languages, such as C and Ruby, in that it contains specialized constructs for the problem being solved. In this case, the resources in the language are specific to the configuration management domain.

Manifests contain the classes and resources which Puppet uses to describe the state of the system. They also contain declarations of the dependencies between these resources.

Classes are often bundled up into modules which package up classes into reusable chunks that can be managed separately. As your system becomes more complicated, using modules helps you manage each subsystem independently of the others.

The client systems contain the Puppet agent, which is the component that communicates with the master. At specified run intervals (30 minutes by default), the agent will run and the following actions will take place:

  1. Custom plugins, such as facts, types, and providers, are sent to the client, if configured.

  2. The client collects facts and sends them to the master.

  3. The master compiles a catalog and sends it to the client.

  4. The client processes the catalog sent by the master.

  5. The client sends the reporting data to the master, if configured.

The catalog, sent to the client by the master, contains a compiled state of the system resources of the client. The client then applies this information using types and providers to bring the system into the desired state. The following illustration shows how data flows between the components:

It is also possible to run Puppet in a masterless mode. In this mode, the Puppet manifests and other needed components, such as custom facts, types, and providers, are distributed to each system using an out of band method, such as scp or rsync. Puppet is then applied on the local node using cron or some other tool.

cron has the advantage of not requiring the server setup with open ports that the master-based setup has. In some organizations, this makes it easier to get past information security teams. However, many of the reporting and other benefits we will explore in this book are less effective when run in this fashion. The book Puppet 3: Beginners Guide, John Arundel, Packt Publishing, has a good amount of information about such a masterless setup.

Other Puppet components

Puppet has a number of other components that form part of the Puppet ecosystem, which are worth exploring due to their use as security tools. The specific components we are going to explore here include PuppetDB and Hiera.


PuppetDB is an application used to store information on the Puppet infrastructure. Released in 2012, PuppetDB solved performance issues present in the older storeconfigs method that stored information about Puppet runs.

PuppetDB allows you to store facts, catalogs, reports, and resource information (via exported resources). Mining this data, using one of the reporting APIs, is an easy and powerful way to get a view of your infrastructure. More information on PuppetDB will be presented in Chapter 3, Puppet for Compliance, as well as Chapter 4, Security Reporting with Puppet.


Hiera was a new feature introduced in Puppet 3. It is a hierarchal data store, which helps to keep information about your environment. This allows you to separate data about the environment from code that acts on the environment. By doing so, you can apply separate security policies to the code that drives the environment and data about the systems.

Before Hiera, it was not uncommon to see large sections of Puppet code dedicated to maintaining sites or installation of specific information on the systems under management. This area was often difficult to maintain if the ability to override parameters using many different factors was needed.

By adding a hierarchy that can depend on any facts, it becomes much easier to store the data needed for the systems under management. A model of most specific to least specific can then be applied, which makes it much easier to override the default data at a site, environment, or system level.

For example, let's say you had a set of development environments where a certain group of development accounts needed to get created, and SSH access to those accounts was granted. However, these accounts and the access granted should only exist in the development machines, and not in production. Without Hiera, there would likely be site-specific information in the modules to manage the SSH configuration, and perhaps in the user creation module to manage the users. Using Hiera, we can add a fact for the type of system (production or development) and store which users get created there, or have access. This moves the list of users with access to the system out of the code itself, and into a data file.

As our examples get more complicated later in this book, we will explore using Hiera to store some system data.


Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at If you purchased this book elsewhere, you can visit and register to have the files e-mailed directly to you.

Installing and configuring Puppet

Puppet can be installed in a variety of ways. Since this book is focused on the security-related aspects of Puppet and is not a beginner's guide, we will cover the most common way it is installed on our target system. There are many good reference books available for more in-depth information on installing Puppet, including Puppet 3: Beginner's Guide, John Arundel, Packt Publishing.

In our examples, we'll be using CentOS 6 as our operating system. If you are using a different operating system and following along on your own, please see the installation instructions for your operating system at, or follow along using Vagrant as outlined later.

Since we will be using Vagrant for our examples, the base box we are using already has the Puppet repository installed on it as well as the Puppet agent. We'll provide instructions for the installation of these elements for those who wish to use CentOS without using Vagrant.

Installing the Puppet Labs Yum repository

The currently recommended way to install Puppet on CentOS machines is to use the Puppet Labs Yum repository. This repository, which can be found at, contains all the Puppet Labs software as well as the dependencies required to install them, such as several Ruby gems not present in the main CentOS repository. On installation, Ruby and these dependencies will also be installed.

Adding this repository is relatively simple. Execute the following command as a root (or using sudo, as shown here):

sudo rpm -ivh

After running this command, you will see an output similar to this:

Preparing...                ########################################### [100%]
   1:puppetlabs-release     ########################################### [100%]

Once this is complete, you're done! The Puppet Labs repository is added and we can use it to install the current version of any of the Puppet Labs products.

Installing the Puppet Master

The next step is to install the Puppet Master. As mentioned earlier, this system acts as the controller that all of your client agents will then use to communicate with to receive catalog information. This package is normally installed on only a few systems that act as servers for configuration management information.

Installing the master with the repository is as easy as executing the following command:

sudo yum -y install puppet-server

This will instruct yum to install the Puppet server without confirmation. The output will be as follows:

Installing the Puppet agent

On all the systems that we wish to manage by using Puppet, we'll need to install the Puppet agent. This agent is a piece of software that is responsible for communicating with the master and applying changes.

Installing the Puppet agent is very easy and similar to installing the master in the preceding section. You simply run the following:

sudo yum -y install puppet

After this is complete, you'll see that the the Puppet agent is installed on the local machine and is ready to talk to the master.

Configuring Puppet

Now that we have a perfectly working Puppet Master, we need to configure it. Installation of the packages will include a base level configuration. There are some changes we will want to make to the base Puppet configuration to enable some features that we'll use in the future. As we go through this book, we'll make changes to these files several times.

The main configuration files in use by Puppet are present in the /etc/puppet directory.

In this directory, there are a number of configuration files that control how Puppet behaves. Information on these files can be found at For now, we only need to concern ourselves with the Puppet configuration file.

Open the /etc/puppet/puppet.conf file with your favorite editor (make sure that you use sudo) and edit it to look similar to the following:

    # 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

    # 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
    report = true
    pluginsync = true
    reports = store

We've made a handful of changes to the file from the default version and will cover them here.

The first change is adding the report = true section to the agent configuration section. This will cause clients to send reports containing information about the Puppet run. We'll use these reports for later analysis in Chapter 4, Security Reporting with Puppet.

The second change is to add pluginsync = true to the agent section. While this has become the default in the more recent versions of Puppet, it does not hurt to add it in. This causes the clients to sync custom facts, providers, and other Puppet libraries from the master. We will see how this is used in later chapters.

The final change we have made is to add the master section and add reports = store. This causes the master to save reports to the local filesystem on the Puppet Master. We'll use this later to do analysis of our Puppet runs for security-related purposes.

Puppet services

Both the Puppet Master and the agent are usually run as services. This allows the agent to check its run frequency and apply any changes. We've not explicitly started the services here, although we'll need to start the master in order to use it from our agent. To do this, we run the following command:

sudo service puppetmaster start

In order for the Puppet Master to start at boot, we'll also issue the following command to enable it to autostart:

sudo chkconfig puppetmaster on

It's pretty common to use Puppet to manage Puppet, and in a later chapter, we'll do this to show how we can use Puppet to secure the Puppet Master.


It's worth noting that Puppet running with a default web server configuration will not scale beyond a few dozen hosts. Scaling Puppet is outside the scope of this book. More information on scaling Puppet can be found at

Preparing the environment for examples

As mentioned in the preface, we're going to use Vagrant to run our examples. In case you missed it, Vagrant is a tool that helps you automate the creation of virtual machines for testing. In this case, it's a great tool for us to use to quickly build-out our build and example environments.

We'll be using CentOS 6 in these examples, but most of them should run without much modification on other platforms. You will need to adjust the package names and perhaps configure the filenames for other operating systems. Many community modules, which we will explore in later chapters, support multiple flavors of Linux as well as other Unix-like systems. The powerful descriptive language of Puppet makes this easy to do.

While the use of Vagrant is not required, it will help us to maintain a clean environment for each of the examples we run, and will also ease the creation of virtual machines. If you choose not to use Vagrant for this, you can still run the examples using the manifests and modules provided with the source accompanying this book.

Installing Vagrant and VirtualBox

In order for us to use Vagrant, we must first install it. To do this, we need to install the required dependencies followed by Vagrant itself. We'll be using VirtualBox to host the virtual machines in these examples, since it is the most supported virtual machine provider.

VirtualBox can be downloaded from On this site, you will find packages for installing a variety of operating systems. You simply need to pick the package for your chosen operating system and install it using the instructions found on the site.

Once we have VirtualBox installed, we can approach installing Vagrant. Vagrant has several methods of installation. These methods include OS packages for Linux, as well as installers for OS X and Windows. Older versions of Vagrant supported installation via the Ruby gem utility, but this has been removed in later versions.

Vagrant can be found at Once you're there, you can download the package or installer for your OS. Once downloaded, you can install the package using your operating system's package manager, or by executing the downloaded package. In Windows and OS X, this is sufficient to have a working installation of Vagrant.

More in-depth installation instructions can be found on the Documentation tab on the Vagrant website; however, the package or installer will do most of the work.

It is worth noting that if you are using Windows, you will perform most of the work we're doing in a command shell on the DOS command box. However, if you use a local editor, you should be able to follow along with no issues.

Creating our first Vagrantfile

Now that we have Vagrant installed, we'll create our first Vagrant configuration. Vagrant uses a file called Vagrantfile to control its operation.

First, we start by creating a directory for our project. In this case, we'll call it puppetbook. We'll end up building on this setup in later chapters to automate configuration of our examples. This will allow us to focus on the Puppet tasks, and not so much on getting our test systems into the desired state.

Inside this directory, we'll create a directory called master_manifests. The purpose of this directory is to hold the Puppet manifests that we'll use to provision the base VM.

We'll be using the Puppet provisioner to do our work. This is one of a handful of methods you can use to provision a Vagrant virtual machine. Using this provisioner, we'll write a Puppet manifest that will describe the desired state of our machine. Vagrant will then use this manifest to run Puppet locally and configure the system.

Next, we'll create a Vagrantfile. In your favorite editor, go ahead and open Vagrantfile. Add the following contents. We'll cover what each one does in a moment:

Vagrant.configure(2) do |config|
  config.vm.define :puppetmaster do |master| = "centos65-x64-puppet"
    master.vm.box_url = ""
    master.vm.hostname = "" "private_network", ip: "", netmask: ""

    master.vm.provision "shell", inline: "yum –y update puppet"

    master.vm.provision "puppet" do |puppet|
      puppet.manifests_path = "master_manifests"
      puppet.manifest_file = "init.pp"



It's possible that by the time you read this, the Vagrant box referenced in the preceding code will be deprecated. This book was written using the Puppet Labs CentOS 6 machine images. You can go to and find a replacement. You want a CentOS 6 x86_64 box with Puppet (called plain there) and VirtualBox addons.

Go ahead and save the file. We'll cover what each file does here:

Vagrant.configure(2) do |config|

This line sets up Vagrant using configuration version 2. It uses Ruby blocks to create a Vagrant configuration with the config variable:

config.vm.define :puppetmaster do |master|

This line defines a virtual machine called puppetmaster. Vagrant supports multimachine setups, which is a feature we'll use later on in the book. For now, we'll define a single machine. Much like the preceding code, we use a block called master: = "centos65-x64-puppet"

This defines the box we'll use for our Puppet Master. It is a symbolic name, but it makes sense to name it according to what it is. If you refer to the same box later, it'll use the same base and not download the box files an additional time:

master.vm.box_url = ""

This defines the URL we'll download our box file from. In this case, we're grabbing it from the hosted Puppet Vagrant boxes on Puppet Labs. We could get a box from any number of other places, but the Puppet Labs boxes come with the Puppet agent preinstalled and the Puppet repository is already available and ready for use. If you wish to explore other box options, there is a directory of them available at

master.vm.hostname = ""

This command simply sets the host name of our machine. It is important for the master as it influences the certificate name that gets created at installation: "private_network", ip: "", netmask: ""

This line creates a private network for our virtual machines to use. We assign it the IP address (78 is PU on a phone dial pad):

master.vm.provision "shell", inline: "yum –y update puppet

"Wait," you say, "I thought we were using the Puppet provisioner?"

As it turns out, the Puppet Labs base box comes with Puppet 3.4 installed. The current version we wish to use in this book is 3.7.3. We use the yum statement to upgrade Puppet before the provisioner starts. Otherwise, we get issues when the Puppet run updates the agent:

master.vm.provision "puppet" do |puppet|

Here, we tell Vagrant we're going to use the Puppet provisioner, and open a block called puppet to do so:

puppet.manifests_path = "master_manifests"

Here, we give the path to the manifest directory. This is relative to the path that the Vagrantfile is in. As you can recall, we created this directory earlier:

puppet.manifest_file = "init.pp"

We define the Puppet manifest to be called init.pp. This is the default name of a Puppet manifest. Vagrant defaults to default.pp if it's not specified:


These lines undo each of the preceding blocks and close out the file.

If we run Vagrant now, it will throw an error because it cannot find the init.pp file, so let's go ahead and create it inside the master_manifests directory. To save space, we'll call out each block and describe its function rather than giving the entire file and explaining it:

package { 'puppet-server':
  ensure => 'present',

The preceding resource declaration will install the Puppet Master. By specifying the ensure value of present, we make sure it's installed; however, we tell Puppet that we do not care about the version and do not wish to upgrade it:

file { '/etc/puppet/puppet.conf':
  ensure  => 'present',
  owner   => 'root',
  group   => 'root',
  mode    => '0644',
  source  => '/vagrant/master_manifests/files/puppet.conf',
  require => Package['puppet-server'],

The preceding resource declaration has a good amount more going on. Here, we're going to manage a file called /etc/puppet/puppet.conf. We ensure that it is present, then set the owner, group, and mode to set the values. Using the source parameter, we source the file from the local filesystem. Vagrant, by default, will mount the directory containing the Vagrantfile as /vagrant, so we can take advantage of that mount to get the file without otherwise copying it.

The last line here shows off the explicit dependency management of Puppet. We require that the puppet-server package is installed before we install the configuration file. This will ensure that the directory is created, and the package installation does not overwrite the configuration file:

service { 'puppetmaster':
  ensure  => 'running',
  require => File['/etc/puppet/puppet.conf'],

This last resource declaration ensures that the Puppet Master service is running. It depends on the configuration file being there.

In a real-world example, we're likely to use subscribe instead of require here. This would restart the service if the configuration file changed. However, since we're using the local Puppet provisioner and not running this code under a Puppet Master, this code will only be run once, so it is unnecessary to use subscribe.

We need one last file to make the system work. The file resource depends on a file called master_manifests/files/puppet.conf. We've covered the contents of this file in the Puppet installation section, so we will not repeat them here. You simply need to copy the file to the directory for the provisioner to use.

When we're done, the complete directory structure of this setup will look as follows:

├── Vagrantfile
└── master_manifests
    ├── files
    │   └── puppet.conf
    └── init.pp

Once we're set up, we're in a good position to run the examples that we'll present in this book. As these examples get more complex, we'll add the necessary data to this structure to add things such as client machines.

Puppet for security and compliance

Puppet is a perfect tool for security and compliance. So much security work involves ensuring that a given version of a service is on every server, or whether a user account exists or not.

Much of this work is also very tedious and repetitive. When work such as this is done across many servers, the likelihood that some of them will be different grows. These snowflakes, or systems that are unique and unlike other systems, can cause security issues or can be hard to troubleshoot.

On top of being able to maintain a system in a fixed state, we can use some Puppet resources, such as PuppetDB, to do some fairly in-depth reporting. Using custom facts, you can collect any information you wish to send to a central place. This can include things such as software versions, hardware configuration, and much more. By using this information, we can start to work toward creating a full configuration management and security platform.

Through Puppet, you will be able to centrally manage the major configuration aspects of all of your systems. Keeping this configuration in version control and treating it as code gives you all the benefits that developers have been able to enjoy for years. You'll quickly be able to see how the state of a system has evolved over time, as well as look where bugs might have been introduced and have caused security issues.

Additionally, there is an increasing movement to use Puppet for compliance and auditing. By demonstrating that Puppet is indeed running on a system and showing the manifests running on it, you can ensure that a system is in a given state. This information can be shown to auditors as documentation on how systems are configured.

Getting to the point of 100-percent coverage in system configuration using Puppet requires commitment and time. Using community modules, as we'll explore later, can lessen that work. However, the results of doing this are very high. Disaster recovery can be made simpler because systems can quickly be rebuilt. Installing the latest tripwire on all systems becomes as simple as updating the manifests and letting the systems check in. These benefits can make the job of a security professional much easier.

As we progress through this book, we will explore many of these abilities in-depth, but for now, let's look at a simple example we can use to learn some of the Puppet concepts and language.

Example – using Puppet to secure openssh

Now that we've got the system set up for our use, we can finally approach the main example for this chapter. In this example, we're going to use what has traditionally been one of the first things used to show off Puppet and install SSH. However, in this case, we're going to use a hardened configuration utilizing some options recommended by the security community.

The example of securing SSH is one that we will return to several times in this book as we expand upon our configuration management toolkit and branch out into things such as firewall management.

Starting the Vagrant virtual machine

Since this is our first time using Vagrant, we'll cover how to start a virtual machine. In the directory with the Vagrantfile, run the following command:

vagrant up

Once this is done, you'll see the output from Vagrant indicating the actions it's taking, as well as output from the commands it runs—this includes the Shell provisioner and the Puppet provisioner. When it's done, you'll end up with something that is similar to the following:

You'll notice some warnings on the screen here. These are options that are changing with the newer version of Puppet. Our manifest could add an allow_virtual setting to get rid of the second warning. The first warning, however, is a result of how Vagrant is calling Puppet.

Connecting to our virtual machine

Once your machine has booted, simply issue the following command to connect:

vagrant ssh

This will connect you to the machine using ssh. Once this is complete, we can start working on our module.

Creating the module

We'll be using a Puppet module to secure SSH. As such, we should go ahead and create the directory to hold our module. You can issue the following commands to create the module skeleton on the guest virtual machine:

sudo mkdir –p /etc/puppet/modules/openssh/manifests
sudo mkdir –p /etc/puppet/modules/openssh/files

These directories will hold the manifests for Puppet to compile as well as our configuration file. For our first simplistic example, we will use a static SSH configuration file. In later chapters, we will build upon it and make it dynamic with the various options that are available.


It's also possible to make the /etc/puppet/modules/openssh directory a symlink to a directory in /vagrant. If you create the directory in /vagrant, you can use any editor on your host system to edit the files and have it immediately available in the guest. This saves you the trouble of having to configure a good editing environment on the guest machine.

Building the module

Now that we have the framework, we'll build our first module. Much like the preceding code, we'll go through it section by section covering what each resource does. The manifest we're building will be very similar to the one we used to provision the Puppet Master for the use of.

First, we'll edit the /etc/puppet/modules/openssh/manifests/init.pp file to create the module's main manifest. This manifest is the main unit of the Puppet code, which is invoked when we include the module. As we go through each of the sections, we'll go through what they do. A complete manifest file can be found on this book's website, but you should really build it along with us. This will help you with understanding and memorization:

class openssh {

The preceding line defines the class. The class in the init.pp file is always named after the module. It's a new construct we've not seen before that is unique to creating modules:

  package { 'openssh-server':
    ensure => 'latest',

The preceding section is similar to the puppetmaster section. The only difference is that we're using latest instead of present. Being a security-related package, it may make sense to make sure that you keep openssh up to date.

Alternatively, if your environment requires it, you could specify a fixed version to install. This might be useful if you require pretested versions or have validated versions. You must weigh the benefits, ensuring that you run the most recent version of the software, including the risk of almost immediately installing it when it is available, and that you're using the latest tag:

  file { '/etc/ssh/sshd_config':
    ensure => 'present',
    owner  => 'root',
    group  => 'root',
    mode   => '0600',
    source => 'puppet:///modules/openssh/sshd_config',


As your Puppet code becomes more complex, care must be taken on how you name your files inside your module. It can sometimes be useful to create the full path to the file under the modules directory, so there is no confusion as to the destination of the time. We omit these here only because our modules are simple, and it makes the examples easier to follow.

This is similar to the Puppet Master configuration file, but we introduced a new construct here. We're sourcing the file from puppet master by using the special puppet:// uniform resource identifier (URL). When Puppet runs, it will fetch the file from the master for use on the agent. The source file should be present in the /etc/puppet/modules/openssh/files directory on the master:

  service { 'sshd':
    ensure => 'running',

Here, as before, we ensure that ssh is running when we run Puppet:

  -> File['/etc/ssh/sshd_config']
  ~> Service['sshd']

This is also a new construct called resource chaining. It is an alternative way to specify that we do things in the order listed: first, the package, followed by the file, and then the service. Note the tilde on the service dependency. This shows that we're notifying the service. It means that if the configuration file changes, the service will be restarted.


In a declarative system, there needs to be a way to ensure that things are run in the correct order. One of the more difficult things for new Puppet users is to grasp the concept that their manifests don't necessarily run in a top-down order. This concept is so hard that in recent versions of Puppet, the default has been changed to a process in the manifest order by default. More information on resource ordering and this change can be found at

The openssh configuration file

To build the configuration file we're going to use, we'll start with the openssh configuration file shipped with CentOS and make a few changes. First, we'll copy the existing configuration file with the following command:

sudo cp /etc/ssh/sshd_config /etc/puppet/modules/openssh/files/

Next, we'll edit the file with your favorite editor. Make sure you run it in sudo as you won't have permission to edit the file. We'll uncomment and change the following lines in the file:

PermitRootLogin no
MaxAuthTries 3

We'll start with these changes to demonstrate how the process works. Then, save the file.

Next, we need to make sure the Puppet agent can read it. We'll set the permissions in such a manner that the Puppet user can read it. Execute the following:

sudo chgrp puppet /etc/puppet/modules/openssh/files/sshd_config
sudo chmod 640 /etc/puppet/modules/openssh/files/sshd_config

The site.pp file

Now, we need to bring it all together to tell Puppet to use our module. By default, Puppet runs a file called site.pp on the master to determine what actions to take when a node checks in. We need to add the new module to the file for Puppet to run it.

The file lives in /etc/puppet/manifests on our Vagrant guest. Go ahead and open it in your favorite editor and add the following section:

node default {
  include openssh

This adds a default node declaration and includes our openssh module on that node. It will ensure that our new module gets used.

Running our new code

Now that we've got it all built, let's go ahead and see the fruits of our labor. Execute the following command:

sudo puppet agent --test

You should see the output as follows:


If you're running these examples outside Vagrant, you will have a bit more work to do. We're using Vagrant to set our hostname to Puppet, and the master by default has its own certificate signed. If you are running without Vagrant, you will need to add a host file entry or DNS pointing to your master, and you may need to sign the certificate. We'll cover certificate singing in Chapter 5, Securing Puppet.

Victory! You can see that Puppet changed the file to disallow root logins and change the maximum authentication attempts to 3.

As with any new technology, the learning curve can seem somewhat overwhelming at first. We've now gone through a rather lengthy example to effectively make a two-line edit to a configuration file on a single machine. This was a short and simple example to explore some base concepts of Puppet. Using this concept, we could apply this same edit to hundreds or even thousands of machines in our infrastructure with very little additional effort. We'll also be exploring more in-depth examples as we gain a skillset. With some practice, you will find that applying changes across one of many machines becomes second nature with Puppet.


In this chapter, we built a foundation for things we will do in chapters to come. First, we covered what Puppet is, and how it differs from other tools in its space. We gave a brief introduction to some of the other Puppet components we'll be using in this book as well.

Moving on from this, we covered how to install Puppet on CentOS. We went through a full installation example and covered the basics of configuration files.

Then, we covered the configuration and installation of Vagrant and used it to run our first example. In this example, we configured SSH with a secure configuration file.

Finally, we introduced how Puppet fits into a security ecosystem. While keeping with the basics, we've begun exploring how Puppet can be used to process simple configuration tasks to secure your systems.

This chapter focused on several high-level concepts. As we get further into the book, we'll go more in-depth in examples and they will get much more powerful. As an introductory chapter, the hope was to get you up and running with a working manifest. In future chapters, we will assume a base level of knowledge and link to references you can use if needed.

Additionally, if you wish to get some more information on the base Puppet language before we proceed, there are several books available. Some of them were mentioned earlier in this chapter, and we'll cover more as we proceed through the book. The documentation at is also very informative, if a little dry at times.

In the next chapter, we'll begin to use our knowledge gained here to explore how Puppet can be used to track changes to resources on our filesystems.

Left arrow icon Right arrow icon

Key benefits

What you will learn

Use Puppet manifests to show system compliance and track changes to the operating system resources Generate security reports using PuppetDB to show that the systems are up to date Automate CIS compliance using community modules Configure firewalls automatically based on roles Demystify the Puppet SSL stack Set up centralized logging with dashboard search functionality using Elasticsearch, Logstash, and Kibana Configure your systems to be secure automatically using SELinux with Puppet Use Puppet to assist with PCI DSS compliance

Product Details

Country selected

Publication date : Mar 27, 2015
Length 236 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781784397753
Category :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details

Publication date : Mar 27, 2015
Length 236 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781784397753
Category :

Table of Contents

17 Chapters
Learning Puppet Security Chevron down icon Chevron up icon
Credits Chevron down icon Chevron up icon
About the Author Chevron down icon Chevron up icon
About the Reviewers Chevron down icon Chevron up icon Chevron down icon Chevron up icon
Preface Chevron down icon Chevron up icon
1. Puppet as a Security Tool Chevron down icon Chevron up icon
2. Tracking Changes to Objects Chevron down icon Chevron up icon
3. Puppet for Compliance Chevron down icon Chevron up icon
4. Security Reporting with Puppet Chevron down icon Chevron up icon
5. Securing Puppet Chevron down icon Chevron up icon
6. Community Modules for Security Chevron down icon Chevron up icon
7. Network Security and Puppet Chevron down icon Chevron up icon
8. Centralized Logging Chevron down icon Chevron up icon
9. Puppet and OS Security Tools Chevron down icon Chevron up icon
Going Forward Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Empty star icon Empty star icon Empty star icon Empty star icon Empty star icon 0
(0 Ratings)
5 star 0%
4 star 0%
3 star 0%
2 star 0%
1 star 0%
Filter icon Filter
Top Reviews

Filter reviews by

No reviews found
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial


How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to
  • To contact us directly if a problem is not resolved, use
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.