Masterless Puppet with Ubuntu 18.04 Bionic Beaver

Puppet is traditionally used as a centralized configuration management system, with a server-client model. In this tutorial, we’re going to show you how to break away from that model, allowing you to continue using Puppet in a highly scalable cloud environment.

Standard Puppet doesn’t work well with the cloud. A typical cloud environment is highly dynamic where nodes are continuously being spun up and down. Puppet, however, requires that each and every node becomes registered with a Puppet master server, where an administrator then has to manually approve it. Of course, you could always auto-approve all new clients, but that has security implications.

By removing the server, as we are going to do in this tutorial, we no longer worry about having to register our clients to a central server. Instances can be spun up and down on demand quickly and easily with automated configurations.

Puppet Agent

Our biggest dependency for this setup is that a Puppet agent will have to be installed and configured on our instances. Depending on where your instance is being hosted, we can either prepare an image with the agent installed or we can install it when a new instance is brought online.

Should you prepare an image or automate the install during provisioning? That answer depends on the balance you need between managing images and the time it takes to bring a new instance online.

Security Implications

Using the Puppet masterless model means your modules will reside on each and every host.  This can be problematic if your modules contain sensitive information in them, such as passwords and tokens.

Removing SSH access and forcing all configuration changes to be made via Puppet is one solution. However, a security flaw in any network service could grant unauthorized root access to your server.

You could GPG encrypt your files, but you would still need to store the keys on the host to decrypt things.

One of the best solutions is to use Ansible Vault. There are a few Puppet modules available that will allow you to fetch secrets from a vault. This is my recommended approach. It’s what I advocate no matter which configuration management tool you use or where the manifests, recipes, or playbooks reside.

Installing and Configuring the Puppet Agent

  1. Download the Puppet 5 deb file from Puppet
    wget https://apt.puppetlabs.com/puppet5-release-bionic.deb
  2. Install the Deb package to add the Puppet repository.
    sudo dpkg -i puppet5-release-bionic.deb
  3. Install Puppet and Git core.
    sudo apt install puppet git-core
  4. Open the Puppet configuration file into a text editor, such as VI.
    sudo vi /etc/puppet/puppet.conf
  5. Modify the Puppet configuration file to enable masterless. It should resemble the following example, where we have removed the [server] section.
    [main]
    logdir=/var/log/puppet
    vardir=/var/lib/puppet
    ssldir=/var/lib/puppet/ssl
    rundir=/var/run/puppet
    modulepath=/etc/puppet/code/modules
    
  6. Save your changes and exit the text editor.

Running Local Puppet Modules

Automating Puppet Runs

Doing anything manually is a DevOps anti-pattern, so it only makes sense that we are going to want to allow Puppet to apply new configurations to our server automatically. Except, we no longer have a centralized server to kick things off.

A very common solution is to run cron jobs. The first job will pull from a Git repository, downloading or updating our Puppet modules. The second job will then run puppet apply to apply any new configurations.

Create a Git Repository for your Modules

On your local machine, create a new repository to store all of the modules for your masterless puppet agents. This repository will hosted in Github, or some other Git repository, and will be pulled periodically. Any new commits will be pulled down and applied to your servers.

  • Create the directory to hold your modules.
    mkdir puppet-modules
  • Change into your new directory.
    cd puppet-modules
  • Initialize the Git repo.
    git init .

This will be the directory we store all of the modules for our servers.

Cron Module

Our first task will be to create a module that creates our cron jobs.

  1. Create the following directory structure in your modules repo.
    mkdir -p puppet-modules/puppet-cron/manifests
  2. Change into the puppet-cron directory.
  3. Create a file called metadata.json and add the following.
    {
      "name": "puppet-cron",
      "version": "0.1.0",
      "author": "Shane Rainville",
      "summary": "",
      "license": "Apache-2.0",
      "source": "",
      "dependencies": [
    
      ],
      "operatingsystem_support": []
      "requirements": [
        {
          "name": "puppet",
          "version_requirement": ">= 4.7.0 < 6.0.0"
        }
      ],
  4. Create the manifest file. Under modules/puppet-cron/manifests create a filed called init.pp.
  5. Add the following contents to it.