Puppet Master/Agent Setup
Puppet configuration
/etc/puppet/puppet.conf
is your standard config file. There are 3 sections to take note of.
[main]
- global configuration section
[master]
- master specific configuration
[agent]
- agent specific configuration
SSL Certificate
When the Puppet Master is first started, besides initializing the environment, it also creates a local Certificate Authority along with the certificates and keys for the Master. It will also open the necessary ports so that agents can connect.
Puppet's ssl info and certificates are located at /var/lib/puppet/ssl
As briefly touched on before, Puppet uses SSL certificates to authenticate between the master and agent. When you first run:
sudo puppet agent --test --server=puppet.example.com
The Agent creates a Certificate Signing Request (CSR) and a private key to secure our request. The agent sends the request to the Master/Certificate Authority to sign and return the certificate. The agent will need to be rerun to check if the CA has signed the certificate.
To check the list of certificates waiting to be signed by the Master/CA:
puppet ca list
To sign the certicate:
# Per host
puppet cert sign [hostname]
# Sign all
puppet cert sign --all
Rather than signing each certificate manually you can set puppet to autosign certificates from a certain range.
https://docs.puppetlabs.com/puppet/latest/reference/subsystem_agent_master_comm.html
Manifests dir
Manifests is where Puppet puts files containing configuration information.
Usually this dir contains a file called site.pp which tells Puppet where and which configurations to load for agents.
You can also override the name and location of the manifests directory and site.pp
file using the manifestdir
and manifest
configuration options, respectively. these options are set in the puppet.conf
configuration file in the [master] section. See http://docs.puppetlabs.com/references/stable/configuration.html
Master
Puppet’s agent/master mode is pull-based. Usually, agents are configured to periodically fetch a catalog and apply it, and the master controls what goes into that catalog.
On redhat or Debian systems the Master is started via an init script with the service command:
# Output can be viewed in /var/log/syslog
sudo service puppetmaster start
For testing purposes you can do the following:
# --verbose = gives detailed logging
# --no-daemonize = keeps the output in the foreground
# --debug = this will produce detailed debug output
sudo puppet master --verbose --no-daemonize
Agent
What is an Agent and how it works with the Puppet Master
On redhat or Debian systems the Agent is started via an init script with the service command:
# Output can be viewed in /var/log/syslog
sudo service puppet start
For testing purposes you can do the following:
# --verbose = gives detailed logging
# --test = run the puppet agent, outputs to standard out and exitssudo
# If you don't specify the server, the agent will look for a host called `puppet` (/etc/hosts)
sudo puppet agent --test --server=puppet.server.com
Modules
A Module usually contain everything needed to configure an application. It also has a specific directory structure and init.pp
file which allows Puppet to automatically load the file.
To perform this automatic loading, Puppet checks the directories set in the modulepath
which is set in the [main]
secction of the /etc/puppet/puppet.conf
file.
Dirctory structure
# manifests = init.pp will go here
# files = any files we use will go here
# templates = any templates our module might use
mkdir -p /etc/puppet/modules/<module_name>/{files,templates,manifests}
Or use the following command: puppet module generate <companyName-serviceName>
Resource
Package is a resource type in Puppet. Some example resources are file, package, service etc.
Example:
package {
"httpd":
ensure => present # Install
}
service{
“httpd”:
ensure => true, # Start on boot
enable => true # Needs to be running
}
# Config file
file{
"/etc/httpd/conf/httpd.conf”:
source => "puppet:///modules/httpd/httpd.conf”,
mode => 644,
owner => root,
group => root
}
No two resources of the same type can share the same title. Also, don't forget to always add a colon (:) after the title. That's important to remember and often overlooked!
How can I use common attributes across a resource type?
# Setting default permission on the file resource
File{
owner => 'postfix',
group => 'postfix',
mode => 0644,
}
file { '/etc/postfix/master.cf':
ensure => present,
source => 'puppet:///modules/postfix/master.cf',
require => Class['postfix:install'],
notify => Class['postfix:service'],
}
file { '/etc/postfix/main.cf':
ensure => present,
content => template('postfix/main.cf.erb'),
require => Class['postfix:install'],
notify => Class['postfix:service'],
}
You will notice the File resource typed capitalized without a title. This syntax is referred to as a resource default which allows to specify defaults for a particular resource type. In this example all file resource types will share the owner & group permissions.
How can I use common attributes across multiple resources?
package { ["postfix", "mailx"]:
ensure => present,
}
Check if a resource exists:
puppet resource file
/vagrant/modules/postfix/manifests/service.pp
Look at a resource:
puppet resource package vim
Variables
Puppet is a declarative language so within the same scope you cannot redefine a variable.
What is a variable scope?
Every class, definition or node introduces a scope. Outside of this scope is whats known as 'top scope'.
The top scope can be access by prepending ::
to a variable. Its recommended to use Factor variables in the top scope.
Puppet variables in the current scope are available as ruby instance variables i.e: @myvariable
Puppet Conditionals
- Case example
case $::osfamily{
Solaris: {
$ssh_package_name = 'openssh'
}
Debian: {
$ssh_package_Name = 'open_ssh_server'
}
RedHat: {
$ssh_package_Name = 'open_ssh_server'
}
default: {
fail("Module propuppet-ssh does not support osfamily ${::osfamily}")
}
}
- Selector example
$package_name = $::osfamily ?
'RedHat' => "openssh-server",
'Debian' => "openssh-server",
'Solaris' => "openssh",
default => fail("Module propuppet-ssh does not support osfamily ${::osfamily}")
- Classes
Class Inheritance example
class ssh::params {
case $::osfamily {
'Debian': { $sshd_package = 'ssh' }
'RedHat': { $sshd_package = 'openssh-server' }
default: {fail("Login class does not work on osfamily: ${::osfamily}")}
}
}
class ssh inherits ssh::params {
package { $::ssh::params::sshd_package:
ensure => installed,
}
}
include ssh
The above does not work for prameterized classes (classes that take parameters when they are called)
- Using Variables between Classes
class ssh::params{
case $::osfamily{
Solaris: {
$ssh_package_name = 'openssh'
}
Debian: {
$ssh_package_Name = 'open_ssh_server'
}
RedHat: {
$ssh_package_Name = 'open_ssh_server'
}
default: {
fail("Module propuppet-ssh does not support osfamily ${::osfamily}")
}
}
}
class ssh::install {
include ssh::params
package{ 'ssh':
ensure => present,
name => $::ssh::params::ssh_package_name,
}
Facter
Puppet is an inventory management tool. It returns 'facts' about each node.
Fact variables can be accessed as $::osfamily
.
You can use facter variables within a template. When puppet is run the fact variables will be replaced by fact values.
Here's a snippet:
soft_bounce = no
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
mail_owner = postfix
myhostname = <%= @hostname %>
mydomain = <%= @domain %>
Templates
Puppet provides the ability to template config files. These are in the format of ERB templates which is plain text files with embedded ruby.
If you want to evaluate ruby code inside a template file you need to enclose the code inside <% ruby code %>
however if you want to evaluate a variable values (or expression) it needs to be enclosed within <=% ruby variable %>
tags
We previously saw a file definition which uses a template (See Resources section) like below (condensed version):
file { '/etc/postfix/main.cf':
ensure => present,
content => template('postfix/main.cf.erb'),
require => Class['postfix:install'],
notify => Class['postfix:service'],
}
Here we call the template function and where the template file resides. The values passed is in fact the path to the postfix/templates/main.cf.erb
template file on disk.
The contents attribute will apply the template with the the ruby variables transposed with the values passed (passing a value to class when its invoked) or fact variable values (see Facter section) to /etc/postfix/main.cf
Useful Commands
Validate puppet code:
puppet parser validate service.pp