Red Green Repeat Adventures of a Spec Driven Junkie

Puppet, Manifests, and Direct Application

In my last post, I went over all the different errors I encountered getting Puppet apply working on a system with modules. I will go over this configuration, a manifest to setup Two Factor Authentication on SSH, and applying Puppet manifests directly on a system.

Configuration for Puppet Magic

I have go these items working on a system:

  • puppet 5
  • vagrant 1.9.3
  • Ubuntu 14.04 Trusty Tahr

All of the above are the latest and/or currently supported versions as of this writing.

This is the Vagrantfile, default.pp file, associated modules folder:

Vagrantfile contents

Vagrant.configure("2") do |config|
  config.vm.box = 'ubuntu/trusty64'
  # resolves error: ==> default: Warning: Could not retrieve fact fqdn
  config.vm.hostname = "vagrant.example.com"

  # http://www.terrarum.net/blog/masterless-puppet-with-vagrant.html
  config.vm.provision 'shell', :inline => <<-SHELL
    apt-get purge -y puppet # remove puppet3
    wget https://apt.puppetlabs.com/puppet5-release-trusty.deb
    dpkg -i ./puppet5-release-trusty.deb
    apt-get update
    apt-get install -y puppet-agent # install puppet5
  SHELL

  # https://github.com/mitchellh/vagrant/issues/3740#issuecomment-92106636
  config.vm.provision 'puppet' do |puppet|
    puppet.environment_path = 'environments'
    puppet.environment = 'production'
    puppet.module_path = 'modules'
  end
end

Just to going over things quickly:

  • the shell provisioner removes puppet3 and installs puppet5
  • this configures puppet provisioner to:
    • use the modules folder
    • set the environments variable to production
    • set the environments path to environments/
    • load any manifests from vagrant’s shared directory

Manifest File contents

Location: environments/production/manifests/default.pp:

class { 'apt': }

apt::ppa{ 'ppa:ubuntu-elisp': }

package { 'emacs-snapshot':
  ensure  => 'latest',
  require => Apt::Ppa['ppa:ubuntu-elisp']
}

Note: The Vagrant configuration will provision any manifests file in the “environments/production/manifests/” folder. There’s no need to name the file default.pp. It’s done here as a default.

Configure Modules

I am bootstrapping all the modules for the manifests files into the vagrant/modules directory.

The big problem: puppet modules require a working version of puppet to download puppet modules. This is a problem if the host system does not have a working version of puppet.

One way I worked around this: use another system’s puppet to download modules and copy the modules directory to the shared vagrant directory.

To bootstrap modules from the guest/vagrant system:

$ puppet module install puppetlabs-apt
$ cp -r ~/.puppet/modules /vagrant/              # puppet 3
$ cp -r /opt/puppetlabs/puppet/modules /vagrant  # puppet 5

Time to Provision

Now that the Vagrantfile, manifests, and modules are setup, let’s provision! Provisioning this system will produce these types messages at the end:

$ vagrant up
...
==> default: Notice: /Stage[main]/Apt/Apt::Setting[conf-update-stamp]/File[/etc/apt/apt.conf.d/15update-stamp]/content: content changed '{md5}b9de0ac9e2c9854b1bb213e362dc4e41' to '{md5}0962d70c4ec78bbfa6f3544ae0c41974'
==> default: Notice: /Stage[main]/Main/Apt::Ppa[ppa:ubuntu-elisp]/Exec[add-apt-repository-ppa:ubuntu-elisp]/returns: executed successfully
==> default: Notice: /Stage[main]/Apt::Update/Exec[apt_update]: Triggered 'refresh' from 1 event
==> default: Notice: /Stage[main]/Main/Apt::Ppa[ppa:ubuntu-elisp]/File[/etc/apt/sources.list.d/ppa:ubuntu-elisp.list]/ensure: created
==> default: Notice: /Stage[main]/Main/Package[emacs-snapshot]/ensure: created
==> default: Notice: Applied catalog in 54.07 seconds

If there any other messages that say Error, check my last article for possible solutions. Otherwise, contact me and let’s work through it together.

Manifest: Two Factor Authentication

Now that puppet is provisioning the system, this is another manifest to install two factor authentication on SSH login.

One thing a puppet manifests allows is easy setup of cloud instances with security. I like having two factor authentication on SSH setup, there are three steps and any misstep can lock you out of your own system.

Having a puppet manifest manage this configuration and setup is better than doing it manually.

File: vagrant_home/environments/production/manifests/two_factor_authentication.pp

# uses puppet modules:
#   - ghoneycutt-ssh; https://forge.puppet.com/ghoneycutt/ssh
#   - stdlib (included with the above module)

class { 'stdlib': }

# get google authenticator
package { 'libpam-google-authenticator':
  ensure => 'installed'
}

# add google_authenticator config pamd
file_line { 'pamd config':
  path => '/etc/pam.d/sshd',
  line => 'auth required pam_google_authenticator.so'
}

# config ssh & restart after pamd changes
class { 'ssh':
  sshd_config_challenge_resp_auth => 'yes',
  subscribe                       => File_line['pamd config']
}

Bootstrap all the modules needed for puppet:

modules directory:

$ puppet module install ghoneycutt-ssh
$ cp -r .puppet/modules /vagrant/                # puppet 3
$ cp -r /opt/puppetlabs/puppet/modules /vagrant  # puppet 5

Run vagrant up:

bash-3.2$ vagrant up
...
Notice: /Stage[main]/Ssh/File[sshd_config]/mode: mode changed '0644' to '0600'
Notice: /Stage[main]/Ssh/Service[sshd_service]: Triggered 'refresh' from 3 events
Notice: /Stage[main]/Ssh/File[ssh_known_hosts]/ensure: created
Notice: Applied catalog in 1.53 seconds

Voila! The system is now configured for two factor authentication. To get two factor authentication on login:

bash-3.2$ vagrant ssh
Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-128-generic x86_64)
...
Last login: Wed Aug 30 11:36:56 2017 from 10.0.2.2
vagrant@vagrant:~$ google-authenticator

Do you want authentication tokens to be time-based (y/n) y
...
Do you want to enable rate-limiting (y/n) y
vagrant@vagrant:~$

But, one does not need to have two factor authentication on a virtual machine, a puppet manifest like this would be a lot more useful to apply the manifest directly on a cloud instance, say AWS EC2 or Digital Ocean droplet…

Applying Puppet Directly

Puppet manifests can be directly applied to a cloud instance by executing puppet directly. Configure the system in a similar way as the virtual machine:

  • setup puppet 5
  • install modules (as root/super user)
  • run puppet apply (as root/super user)

Setting up Puppet5

This will be exactly the same as in the Vagrantfile shell provisioner. Main difference: prefix each command with sudo as the shell provisioner is executing commands as root/super user.

From the cloud instance command line, run these commands setup puppet 5:

$ sudo apt-get purge -y puppet # remove puppet3
$ wget https://apt.puppetlabs.com/puppet5-release-trusty.deb
$ sudo dpkg -i ./puppet5-release-trusty.deb
$ sudo apt-get update
$ sudo apt-get install -y puppet-agent # install puppet-agent

Install Modules

Install any modules used in the manifests. On the cloud instance, any changes at the system level usually requires root/super user privileges, puppet needs to execute with the same privileges, modules need to be accessible to puppet as well.

Puppet 3 will install modules in the users’ home directory.

Puppet 5 will install modules in system directory: /etc/puppetlabs/code/environments/production/modules

Install associated modules for recipe (as root!):

$ sudo /opt/puppetlabs/puppet/bin/puppet module install ghoneycutt-ssh
Notice: Preparing to install into /etc/puppetlabs/code/environments/production/modules ...
Notice: Downloading from https://forgeapi.puppet.com ...
Notice: Installing -- do not interrupt ...
/etc/puppetlabs/code/environments/production/modules
└─┬ ghoneycutt-ssh (v3.54.0)
  ├── ghoneycutt-common (v1.7.0)
  ├── puppetlabs-firewall (v1.9.0)
  └── puppetlabs-stdlib (v4.19.0)

Puppet Apply

Run puppet apply as root:

$ sudo /opt/puppetlabs/puppet/bin/puppet apply /full/path/to/file.pp
...
Notice: /Stage[main]/Ssh/File[ssh_config]/content: content changed '{md5}7c3fc0754c5a373bac7b09d9d4f6e403' to '{md5}08cc71e013e8ba01c7d1f03d212f1ee5'
Notice: /Stage[main]/Ssh/File[sshd_config]/content: content changed '{md5}dd54c90b78bdff564b4dd0d20648f0a7' to '{md5}1a79014d4d4a409e854eb18b798e660b'
Notice: /Stage[main]/Ssh/File[sshd_config]/mode: mode changed '0644' to '0600'
Notice: /Stage[main]/Ssh/Service[sshd_service]: Triggered 'refresh' from 3 events
Notice: /Stage[main]/Ssh/File[ssh_known_hosts]/ensure: created
Notice: Applied catalog in 1.53 seconds

To test two factor authentication, see if the google-authenticator has been installed:

$ which google-authenticator
/usr/bin/google-authenticator

Conclusion

Puppet is a magical system. I have presented on how to configure a vagrant system configured with the latest puppet (version 5) and bootstrapping modules so clean manifests can used.

I also have shown how a manifest for a system level configuration, like two factor authentication over SSH.

Finally, I explained how to run puppet manifests on system directly so manifests are useful on cloud instances such as AWS EC2 or Digital Ocean Droplet.