Notes on installing Puppet6 on Ubuntu 18.04
This is a compilation of notes that leads to an installation of a Puppet server on an Ubuntu server 18.04.A node with a Puppet agent was created on an Ubuntu server 18.04.
Examples in this guide don’t care about OSes, everything is done to work on Ubuntu.
These notes were heavily inspired by various articles and documentation pages, notably:
Virtual machines
Links:
Use snapshots to save your work (i.e: when a new puppet configuration is successful). It’s quicker than a reinstall.
Puppet server
Virtual hardware:
- Ram: 4Gb or more
- Network:
- A card with “NAT” to access internet
- A card with “Private host network” to access the VirtualBox local network, on 192.168.56.1/24, no DHCP
OS:
- Host name: puppet (A lot of puppet actions will use this as a default)
- SSH enabled
Puppet node
Virtual hardware:
- RAM: 2Gb
- Network connection:
- A card with “NAT” to access internet
- A card with “Private host network” to access the VirtualBox local network, on 192.168.56.1/24, no DHCP
OS:
- Host name: puppet-node
- SSH enabled
Preparation
Links:
Once the VMs are ready and booted, configure Netplan to have static IP addresses on the private host network.
I used 192.168.56.5
for Puppet server and 192.168.56.6
for the puppet node
# sudo vim /etc/netplan/50-cloud-init.yaml
network:
ethernets:
enp0s3:
dhcp4: true
enp0s8: # Interface connected to the private host network
dhcp4: no
addresses: [192.168.56.6/24]
version: 2
Apply configuration:
netplan try
# If it's fine, validate to save the changes
Add hosts to your ~/.ssh/config
:
# Puppet-server
host puppet
hostname 192.168.56.5
user <the_ubuntu_user>
forwardagent yes
# Puppet-node, obviously
host puppet-node
hostname 192.168.56.6
user <the_ubuntu_user>
forwardagent yes
Use forwardagent yes
to be able to connect to your outside stuff (i.e.: git repos)
You should be able to access your two virtual machines using SSH from the host:
ssh puppet
ssh puppet-node
/etc/hosts
The first time I used Puppet server, I had certificates issues, so I had to specify the Puppet server host in the two VMs host file:
192.168.56.5 puppet puppet.lan
Puppet-release
Links:
- Documentation: Puppet platform
For both server and node, you will need to activate the “puppet release” package sources.
On ubuntu 18.04 server, the “multiverse” repository is already active, in other cases, activate it:
sudo apt-add-repository multiverse && sudo apt-get update
Install Puppet Release
wget https://apt.puppet.com/puppet6-release-bionic.deb
sudo dpkg -i puppet6-release-bionic.deb # Adds source in sources.list.d
sudo apt update
Note: If the download is stuck when using IPv6, force IPv4: use --inet4-only
Install puppet server
Links:
- Documentation: Install from packages
Install the server:
sudo apt install puppetserver
You need a root and intermediate signing CA for Puppet Server, in order to identify it to the nodes:
sudo /opt/puppetlabs/server/bin/puppetserver ca setup
Start the service
service puppetserver start
Configure
Links:
- Documentation: Configuring Puppet Server
Puppet server needs 2Gb of memory; for testing purpose you can tweak it down (check this section of the documentation).
For other options, check the documentation, this is not the point of these notes.
Puppet agent
You should have installed the puppet-release and activated the “multiverse” repository.
Installing the agent
Links:
- Documentation: Install agents
sudo apt install puppet-agent
# Start the service
sudo /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
Connect the first agent to Puppet server
Try to connect to puppet server:
sudo /opt/puppetlabs/bin/puppet agent --test
# [...]
# Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate (puppet-agent). Exiting now because the waitforcert setting is set to 0.
The agent contacted Puppet server, but the server don’t know it. It should sign its certificate first to add it to its list of managed nodes.
On the master, list certificates:
sudo /opt/puppetlabs/bin/puppetserver ca list
# Requested Certificates:
# puppet-node.lan (SHA256) FC:20:C6:A9:12:F4:40:4D:A6:A3:74:E8:5B:19:84:0A:54:33:16:C9:7A:C0:18:52:75:C9:94:E0:8A:61:29:95
Then, once the SHA is verified, sign the certificate:
sudo /opt/puppetlabs/bin/puppetserver ca sign --certname puppet-node.lan
If you work in a closed environment in which you’re sure about the machines you’re going to certify, you may want to sign all the pending ones in a batch:
sudo /opt/puppetlabs/bin/puppetserver ca sign --all
Re launch the agent on the node and you’re done: Puppet agent fetches the catalog from Puppet server and applies it (does nothing right now).
Now, we have a very basic Puppet server and a node, which is linked to it.
Notes on certificates
Remove the agent’s certificates if you messed up (I generated mine forgotting to sudo…):
# On the node:
sudo /opt/puppetlabs/bin/puppet ssl --localca clean
# On the server:
sudo /opt/puppetlabs/bin/puppetserver ca list --all sudo /opt/puppetlabs/bin/puppetserver ca clean --certname puppet-node
First node configuration
Here comes the fun: we’re going to write a manifest file to configure our nodes !
Puppet environments are different configurations for your conformation system: you may want to test things before applying it on the nodes.
The default environment is “production”, and we’ll use it for now.
Files are located under /etc/puppetlab/code/environments
Edit /etc/puppetlab/code/environments/production/manifests/site.pp
Message of the day
Links:
- Documentation: Resources
- Documentation: Types
- Documentation: Facts and vars
- Documentation: Agent manual
- Article: Customize your MOTD login message in Debian and Ubuntu
A simple thing we can try to have quick results is to change the message of the day (MOTD), which is displayed when we login on a node.
The MOTD used to be a single file in /etc/motd
, but Ubuntu came in and now we have a message of the day composed of fragments of messages, scattered across multiple files in /etc/update-motd.d/
:
/etc/update-motd.d/
|-- 00-header
|-- 10-help-text
|-- 50-landscape-sysinfo -> /usr/share/landscape/landscape-sysinfo.wrapper
|-- 50-motd-news
|-- 80-esm
|-- 80-livepatch
|-- 90-updates-available
|-- 91-release-upgrade
|-- 95-hwe-eol
|-- 97-overlayroot
|-- 98-fsck-at-reboot
`-- 98-reboot-required
We’ll change the header to tell user that the node is managed by Puppet.
# resource "file"
file { '/etc/update-motd.d/00-header':
ensure => file,
owner => root,
group => root,
mode => '0755', # file has mode rwxr-xr-x
content => "#!/bin/sh\nprintf \"This is ${facts['fqdn']}\n\n\"printf \"This node is managed by Puppet.\"\n",
}
What will it do ? Well, Puppet will ensure that file or folder /etc/update-motd.d/00-header'
exists and is a file, owned by root:root
, with given mode and content.
Save the file and run the agent on the node:
sudo /opt/puppetlabs/bin/puppet agent --test --noop
Note the --noop
option: the changes will not be applied. If no errors shows up, run the command again, without the “noop” option.
Base packages
Of all the things we want to automate, the system packages are a good start too. You can add packages or remove them with something like:
# We don't want cloud-ini
package { 'cloud-init':
ensure => purged
}
package { 'tree':
ensure => installed,
}
package { 'vim':
ensure => installed,
}
package { 'fail2ban':
ensure => installed,
}
package { 'htop':
ensure => installed,
}
# ...
As before, run with --noop
first.
Modules: SSH configuration
Links:
- Documentation: Modules
- Puppet Forge
- Zach Leslie’s SSH module - Git repo
Puppet modules are classes meant to do something. You can find existing modules on the Puppet forge, and it goes from managing SSH configuration to setup a GitLab instance.
We’ll focus on the SSH configuration, in order to:
- Only allow logins with public keys
- Disable root login
- Allow only some cyphers
- Allow only users from the admin group (
adm
for Ubuntu) - Ensure the server is running
The first thing to do is to choose a module in the 470+ SSH modules from the Forge. I was told by a trusted source that the one from Zach Leslie is a good start.
Tell Puppet to use the module. On the server:
sudo /opt/puppetlabs/bin/puppet module install zleslie-ssh --version 1.2.0
Edit site.pp
and add the following configuration:
# SSH configuration
class { 'ssh::server::config':
authenticationmethods => 'publickey',
ciphers => 'chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr',
kexalgorithms => 'curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256',
log_level => 'VERBOSE',
macs => 'hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com',
passwordauthentication => 'no',
permitrootlogin => 'no',
}
# Allowed groups
ssh::allowgroup { 'adm': }
# Activate the server
class { 'ssh::server':
}
If we don’t want to be able to login, we have to add the allowed SSH keys to the user before applying anything.
Users
You may want to configure users on all your systems, allowing them to login with their SSH keys:
user { 'johndoe':
ensure => present,
groups => [
'adm',
'sudo',
],
shell => '/bin/bash',
home => '/home/johndoe',
managehome => true,
password => '*',
purge_ssh_keys => true, # We only want the keys we declare
}
$ssh_key = 'ssh-rsa SOMELONGSTRING johndoe@example.com'
$ssh_elements = $ssh_key.split(' ')
# The key will be added, allowing us to login, as the SSH policy is "publickey" only
ssh_authorized_key { $ssh_elements[2]:
ensure => present,
user => 'johndoe',
type => $ssh_elements[0],
key => $ssh_elements[1],
}
In this example, we used variables and functions (split
), which is nice.
Now you can apply the configuration on the node. Logout and login to see how it’s working.
Per-node configuration
We applied the configuration on the puppet-node
virtual machine, but we may want to apply it to the Puppet server too.
# On puppet-server:
sudo /opt/puppetlabs/bin/puppet agent --test
Now, all our nodes have the same configuration. But what if we wanted to have specific elements on a specific node ?
We can define a per-node configuration in site.pp
:
# Global configuration
# ...
# Specific node
node puppet-node {
package { 'cowsays':
ensure => installed,
}
}
# Specific node
node puppet {}
Conclusion
We learned how to set up a Puppet server to manage hosts with shared and custom configuration.
I encourage you to play with a few nodes, document yourself on the Puppet server configuration.
What’s next?
- Learn how to configure the Puppet server.
- Learn how to manage our configuration with a control repo and r10k (see [article:puppet6-and-ubuntu18-04-control-repo-with-r10k-and-hiera]).
- Learn how to use Hiera and create reusable profiles.
- Create configurations that applies to different OSes.