Install and Configure Puppet
Traducciones al EspañolEstamos traduciendo nuestros guías y tutoriales al Español. Es posible que usted esté viendo una traducción generada automáticamente. Estamos trabajando con traductores profesionales para verificar las traducciones de nuestro sitio web. Este proyecto es un trabajo en curso.
DeprecatedThis guide has been deprecated and is no longer being maintained. Please refer to the updated version of this guide.
Puppet is a configuration automation platform that simplifies various system administrator tasks. Puppet uses a client/server model where the managed servers, called Puppet agents, talk to and pull down configuration profiles from the Puppet master.


Puppet is written in its own custom language, meant to be accessible to system administrators. A module, located on the Puppet master, describes the desired system. The Puppet software then translates the module into code and alters the agent servers as needed when the puppet agent command is run on an agent node or automatically at designated intervals.
Puppet can be used to manage multiple servers across various infrastructures, from a group of personal servers up to an enterprise level operation. It is intended to run on Linux and other Unix-like operating systems, but has also been ported to Windows. For the purpose of this guide, however, we will be working with an Ubuntu 16.04 LTS master server and two agent nodes: one Ubuntu 16.04, and one CentOS 7.
root user. A limited user with administrative privileges will be configured in later steps.Before You Begin
You should have three available Linodes, one of which has at least four CPU cores for the Puppet master. A Linode 8GB plan is recommended. The two other nodes can be of any plan size, depending on how you intend to use them after Puppet is installed and configured.
Follow the Setting Up and Securing a Compute Instance guide and ensure your Linodes are configured to use the same timezone.
Note For ease of use, set the Puppet master server’s hostname to
puppet, and have a valid fully-qualified domain name (FQDN).To check your hostname, run
hostnameand to check your FQDN, runhostname -f.
Puppet Master
Install Puppet Master
Install the
puppetlabs-releaserepository into Ubuntu 16.04 and update your system. This process downloads a.debfile that will configure the repositories for you:wget https://apt.puppet.com/puppetlabs-release-pc1-xenial.deb dpkg -i puppetlabs-release-pc1-xenial.deb apt updateNote If you wish to run another Linux distribution as your master server, the initial
.debfile can be substituted for another distribution based on the following formats:Red Hat-based systems:
wget https://yum.puppet.com/puppetlabs-release-pc1-OS-VERSION.noarch.rpmDebian-based systems:
wget https://apt.puppet.com/puppetlabs-release-pc1-VERSION.debAny Ubuntu-specific commands will then have to be amended for the proper distribution. More information can be found in Puppet’s Installation Documentation or our guide to package management.
Install the
puppetmaster-passengerpackage:apt install puppetmaster-passengerThe default Puppet installation may start Apache and configure it to listen on the same port as Puppet. Stop Apache to avoid this conflict (if using CentOS7, change
apache2in this example tohttpd):systemctl stop apache2Ensure you have the latest version of Puppet by running:
puppet resource package puppetmaster ensure=latest
Configure Puppet Master
Update
/etc/puppet/puppet.confand add thedns_alt_namesline to the section[main], replacingpuppet.example.comwith your own FQDN:- File: /etc/puppet/puppet.conf
1 2[main] dns_alt_names=puppet,puppet.example.com
Start the Puppet master:
systemctl start puppetmasterBy default, the Puppet master process listens for client connections on port 8140. If the
puppetmasterservice fails to start, check that the port is not already in use:netstat -anpl | grep 8140
Puppet Agents
Install Puppet Agent
On agent nodes running Ubuntu 16.04 or other Debian-based distributions, use this command to install Puppet:
apt install puppet
On agent nodes running CentOS 7 or other Red Hat systems, follow these steps:
For CentOS 7 only, add the Puppet Labs repository:
rpm -ivh https://yum.puppet.com/el/7/products/x86_64/puppetlabs-release-22.0-2.noarch.rpmNote If you’re on a Red Hat system other than CentOS 7, skip this step.Install the Puppet agent:
yum install puppet
Configure Puppet Agent
Modify your Puppet Agent’s host file to resolve the Puppet master IP as
puppet:- File: /etc/hosts
1198.51.100.0 puppet
Add the
servervalue to the[main]section of the node’spuppet.conffile, replacingpuppet.example.comwith the FQDN of your Puppet master:- File: /etc/puppet/puppet.conf
[main] server=puppet.example.com
Restart the Puppet service:
systemctl restart puppet
Generate and Sign Certificates
On each agent, generate a certificate for the Puppet master to sign:
puppet agent -tThis will output an error, stating that no certificate has been found. This error is because the generated certificate needs to be approved by the Puppet master.
Log in to your Puppet master and list the certificates that need approval:
puppet cert listIt should output a list with your agent node’s hostname.
Approve the certificates, replacing
hostname.example.comwith the hostname of each agent node:puppet cert sign hostname.example.comReturn to the Puppet agent nodes and run the Puppet agent again:
puppet agent -t
Add Modules to Configure Agent Nodes
Both the Puppet master and agent nodes configured above are functional, but not secure. Based on concepts from the Setting Up and Securing a Compute Instance guide, a limited user and a firewall should be configured. This can be done on all nodes through the creation of basic Puppet modules, shown below.
Add a Limited User
From the Puppet master, navigate to the
/etc/puppet/modulesdirectory and create your new module for adding user accounts, thencdinto that directory:mkdir /etc/puppet/modules/accounts cd /etc/puppet/modules/accountsCreate the following directories, which are needed to have a functioning module:
mkdir {examples,files,manifests,templates}The
examplesdirectory allows you to test the module locally.filescontains any static files that may need to be edited or added.manifestscontains the actual Puppet code for the module, andtemplatescontains any non-static files that may be needed.Move to the
manifestsdirectory and create your first class, calledinit.pp. All modules require aninit.ppfile to be used as the main definition file of a module.cd manifestsWithin the
init.ppfile, define a limited user to use instead ofroot, replacing all instances ofusernamewith your chosen username:- File: /etc/puppet/modules/accounts/manifests/init.pp
1 2 3 4 5 6 7 8 9 10 11class accounts { user { 'username': ensure => present, home => '/home/username', shell => '/bin/bash', managehome => true, gid => 'username', } }
The
init.ppfile initially defines theaccountsclass. It then calls for theuserresource, where ausernameis defined. Theensurevalue is set to ensure that the user exists (is present). Thehomevalue should be set to the user’s home directory path.shelldefines the shell type, in this instance the bash shell.managehomenotes that the home directory should be created. Finally,gidsets the primary group for the user.Although the primary group is set to share the username, the group itself has not been created. Save and exit
init.pp. Then, create a new file calledgroups.ppand add the following contents. This file will be used to create the user’s group. Again, replaceusernamewith your chosen username:- File: /etc/puppet/modules/accounts/manifests/groups.pp
1 2 3 4 5 6 7class accounts::groups { group { 'username': ensure => present, } }
Include this file by adding
include groupsto theinit.ppfile, within theaccountsclass:- File: /etc/puppet/modules/accounts/manifests/init.pp
1 2 3 4 5class accounts { include groups ... }
This user should have privileges so that administrative tasks can be performed. Because we have agent nodes on both Debian- and Red Hat-based systems, the new user needs to be in the
sudogroup on Debian systems, and thewheelgroup on Red Hat systems. This value can be set dynamically through the use of a selector and facter, a program included in Puppet that keeps track of information, or facts, about every server. Add a selector statement to the top of theinit.ppfile within the accounts class brackets, defining the two options:- File: /etc/puppet/modules/accounts/manifests/init.pp
1 2 3 4 5 6 7 8 9 10 11 12class accounts { $rootgroup = $osfamily ? { 'Debian' => 'sudo', 'RedHat' => 'wheel', default => warning('This distribution is not supported by the Accounts module'), } user { 'username': ... }
This command sequence tells Puppet that within the accounts module the variable
$rootgroupshould evaluate, using facter, the operating system family ($osfamily), and if the value returned isDebian, to set the$rootgroupvalue tosudo. If the value returned isRedHat, this same value should be set towheel; otherwise, thedefaultvalue will output a warning that the distribution selected is not supported by this module.Note Theuserdefinition will include the$rootgroup, and the Puppet Configuration Language executes code from top to bottom. You must define the$rootgroupbefore theuserso that it can be accessed.Add the
groupsvalue to the user resource, calling to the$rootgroupvariable defined in the previous step:- File: /etc/puppet/modules/accounts/manifests/init.pp
1 2 3 4 5 6 7 8user { 'username': ensure => present, home => '/home/username', shell => '/bin/bash', managehome => true, gid => 'username', groups => "$rootgroup", }
The value
"$rootgroup"is enclosed in double quotes (") instead of single quotes (’) because it is a variable. Any value enclosed within single quotes will be added as typed in your module; anything enclosed in double quotes can accept variables.The final value that needs to be added is the
password. Since we do not want to use plain text, it should be fed to Puppet as a SHA1 digest, which is supported by default. Set a password from the terminal:openssl passwd -1You will be prompted to enter your password and confirm. A hashed password will be output. This should then be copied and added to the
userresource:- File: /etc/puppet/modules/accounts/manifests/init.pp
1 2 3 4 5 6 7 8 9 10 11 12 13class accounts { user { 'username': ensure => present, home => '/home/username', shell => '/bin/bash', managehome => true, gid => 'username', groups => "$rootgroup", password => '$1$07JUIM1HJKDSWm8.NJOqsP.blweQ..3L0', } }
Important The hashed password must be included in single quotes (’).After saving your changes, use the puppet parser to ensure that the code is correct:
puppet parser validate init.ppAny errors that need to be addressed will be logged to standard output. If nothing is returned, your code is valid.
Before the module can be tested further, navigate to the
examplesdirectory and create anotherinit.ppfile, this time to call to theaccountsmodule:cd ../examples- File: /etc/puppet/modules/accounts/examples/init.pp
1include accounts
After adding this line, save and exit the file.
While still in the
examplesdirectory, test the module without making changes:puppet apply --noop init.ppNote The--noopparameter prevents Puppet from actually running the module.It should return:
Notice: Compiled catalog for puppet.example.com in environment production in 0.26 seconds Notice: /Stage[main]/Accounts::Groups/Group[username]/ensure: current_value absent, should be present (noop) Notice: Class[Accounts::Groups]: Would have triggered 'refresh' from 1 events Notice: /Stage[main]/Accounts/User[username]/ensure: current_value absent, should be present (noop) Notice: Class[Accounts]: Would have triggered 'refresh' from 1 events Notice: Stage[main]: Would have triggered 'refresh' from 2 events Notice: Finished catalog run in 0.02 secondsAgain from the
examplesdirectory, runpuppet applyto make these changes to the Puppet master server:puppet apply init.ppLog out as
rootand log in to the Puppet master as your new user. The rest of this guide will be run by this user.
Edit SSH Settings
Although a new user has successfully been added to the Puppet master, the account is still not secure. Root access should be disabled for the server before continuing.
Navigate to
fileswithin theaccountmodule directory:cd /etc/puppet/modules/accounts/filesCopy the
sshd_configfile to this directory:sudo cp /etc/ssh/sshd_config .Open the file with
sudo, and set thePermitRootLoginvalue tono:- File: /etc/puppet/modules/accounts/files/sshd_config
1PermitRootLogin no
Navigate back to the
manifestsdirectory and, usingsudo, create a file calledssh.pp. Use thefileresource to replace the default configuration file with the one managed by Puppet:cd ../manifests- File: /etc/puppet/modules/accounts/manifests/ssh.pp
1 2 3 4 5 6 7 8class accounts::ssh { file { '/etc/ssh/sshd_config': ensure => present, source => 'puppet:///modules/accounts/sshd_config', } }
Note Thefiledirectory is omitted from thesourceline because thefilesfolder is the default location of files. For more information on the format used to access resources in a module, refer to the official Puppet module documentation.Create a second resource to restart the SSH service and set it to run whenever
sshd_configis changed. This will also require a selector statement because the SSH service is calledsshon Debian systems andsshdon Red Hat:- File: /etc/puppet/modules/accounts/manifests/ssh.pp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18class accounts::ssh { $sshname = $osfamily ? { 'Debian' => 'ssh', 'RedHat' => 'sshd', default => warning('This distribution is not supported by the Accounts module'), } file { '/etc/ssh/sshd_config': ensure => present, source => 'puppet:///modules/accounts/sshd_config', notify => Service["$sshname"], } service { "$sshname": hasrestart => true, } }
Include the
sshclass withininit.pp:- File: /etc/puppet/modules/accounts/manifests/init.pp
1 2 3 4 5class accounts { include groups include ssh ...
Your complete
init.ppwill look similar to this:- File: /etc/puppet/modules/accounts/manifests/init.pp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21class accounts { include groups include ssh $rootgroup = $osfamily ? { 'Debian' => 'sudo', 'RedHat' => 'wheel', default => warning('This distro not supported by Accounts module'), } user { 'example': ensure => present, home => '/home/username', shell => '/bin/bash', managehome => true, gid => 'username', groups => "$rootgroup", password => '$1$07JUIM1HJKDSWm8.NJOqsP.blweQ..3L0' } }
Run the Puppet parser, then navigate to the
examplesdirectory to test and runpuppet apply:sudo puppet parser validate ssh.pp cd ../examples sudo puppet apply --noop init.pp sudo puppet apply init.ppNote You may see the following line in your output when validating:
Error: Removing mount "files": /etc/puppet/files does not exist or is not a directoryThis refers to a Puppet configuration file, not the module resource you’re trying to copy. If this is the only error in your output, the operation should still succeed.
To ensure that the
sshclass is working properly, log out and then try to log in asroot. You should not be able to do so.
Add and Configure IPtables
In this section, we’ll configure firewall rules using iptables. However, these rules will not persist across reboots by default. To avoid this, install the appropriate package on each node (both master and agents) before proceeding:
Ubuntu/Debian:
sudo apt install iptables-persistent
CentOS 7:
CentOS 7 uses firewalld by default as a controller for iptables. Be sure firewalld is stopped and disabled before starting to work directly with iptables:
sudo systemctl stop firewalld && sudo systemctl disable firewalld
sudo yum install iptables-services
On your Puppet master node, install Puppet Lab’s firewall module from the Puppet Forge:
sudo puppet module install puppetlabs-firewallThe module will be installed in your
/etc/puppet/modulesdirectory.Navigate to the
manifestsdirectory under the newfirewallmodule:cd /etc/puppet/modules/firewall/manifests/Create a file titled
pre.pp, which will contain all basic networking rules that should be run first:- File: /etc/puppet/modules/firewall/manifests/pre.pp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55class firewall::pre { Firewall { require => undef, } # Accept all loopback traffic firewall { '000 lo traffic': proto => 'all', iniface => 'lo', action => 'accept', }-> #Drop non-loopback traffic firewall { '001 reject non-lo': proto => 'all', iniface => '! lo', destination => '127.0.0.0/8', action => 'reject', }-> #Accept established inbound connections firewall { '002 accept established': proto => 'all', state => ['RELATED', 'ESTABLISHED'], action => 'accept', }-> #Allow all outbound traffic firewall { '003 allow outbound': chain => 'OUTPUT', action => 'accept', }-> #Allow ICMP/ping firewall { '004 allow icmp': proto => 'icmp', action => 'accept', } #Allow SSH connections firewall { '005 Allow SSH': dport => '22', proto => 'tcp', action => 'accept', }-> #Allow HTTP/HTTPS connections firewall { '006 HTTP/HTTPS connections': dport => ['80', '443'], proto => 'tcp', action => 'accept', } }
Each rule is explained via commented text. More information can also be found on the Puppet Forge Firewall page.
In the same directory create
post.pp, which will run any firewall rules that need to be input last:- File: /etc/puppet/modules/firewall/manifests/post.pp
1 2 3 4 5 6 7 8 9class firewall::post { firewall { '999 drop all': proto => 'all', action => 'drop', before => undef, } }
These rules will direct the system to drop all inbound traffic that is not already permitted in the firewall.
Run the Puppet parser on both files to ensure the code does not return any errors:
sudo puppet parser validate pre.pp sudo puppet parser validate post.ppMove up a directory, create a new
examplesdirectory, and navigate to it:cd .. sudo mkdir examples cd examplesWithin
examples, create aninit.ppfile to test the firewall on the Puppet master:- File: /etc/puppet/modules/firewall/examples/init.pp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16resources { 'firewall': purge => true, } Firewall { before => Class['firewall::post'], require => Class['firewall::pre'], } class { ['firewall::pre', 'firewall::post']: } firewall { '200 Allow Puppet Master': dport => '8140', proto => 'tcp', action => 'accept', }
This code block ensures that
pre.ppandpost.pprun properly, and adds a firewall rule to the Puppet master to allow nodes to access it.Run the
init.ppfile through the Puppet parser and then test to see if it will run:sudo puppet parser validate init.pp sudo puppet apply --noop init.ppIf successful, run the
puppet applywithout the--noopoption:sudo puppet apply init.ppOnce Puppet is done running, check the iptables rules:
sudo iptables -LIt should return:
Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere /* 000 lo traffic */ REJECT all -- anywhere 127.0.0.0/8 /* 001 reject non-lo */ reject-with icmp-port-unreachable ACCEPT all -- anywhere anywhere /* 002 accept established */ state RELATED,ESTABLISHED ACCEPT icmp -- anywhere anywhere /* 004 allow icmp */ ACCEPT tcp -- anywhere anywhere multiport ports ssh /* 005 Allow SSH */ ACCEPT tcp -- anywhere anywhere multiport ports http,https /* 006 HTTP/HTTPS connections */ ACCEPT tcp -- anywhere anywhere multiport ports 8140 /* 200 Allow Puppet Master */ DROP all -- anywhere anywhere /* 999 drop all */ Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination ACCEPT tcp -- anywhere anywhere /* 003 allow outbound */
Add Modules to the Agent Nodes
Now that the accounts and firewall modules have been created, tested, and run on the Puppet master, it is time to add them to the Puppet agent nodes created earlier.
From the Puppet master, navigate to
/etc/puppet/manifests.cd /etc/puppet/manifestsList all available agent nodes:
sudo puppet cert list -allCreate the file
site.ppto define which nodes will take what modules. Replaceubuntuagent.example.comandcentosagent.example.comwith the FQDNs of your agent nodes:- File: /etc/puppet/manifests/site.pp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31node 'ubuntuagent.example.com' { include accounts resources { 'firewall': purge => true, } Firewall { before => Class['firewall::post'], require => Class['firewall::pre'], } class { ['firewall::pre', 'firewall::post']: } } node 'centosagent.example.com' { include accounts resources { 'firewall': purge => true, } Firewall { before => Class['firewall::post'], require => Class['firewall::pre'], } class { ['firewall::pre', 'firewall::post']: } }
This includes the
accountsmodule and uses the same firewall settings as above to ensure that the firewall rules are applied properly.On each Puppet agent node, enable the
puppet agentcommand:puppet agent --enableRun the Puppet agent:
puppet agent -tTo ensure the Puppet agent worked, log in as the limited user that was created and check the iptables:
sudo iptables -L
Congratulations! You’ve successfully installed Puppet on a master and two agent nodes. Now that you’ve confirmed everything is working, you can create additional modules to automate configuration management on your agent nodes. For more information, see Puppet module fundamentals. You can also install and use those modules others have created on the Puppet Forge.
More Information
You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.
This page was originally published on
