November 14, 2013 / by Torsten Bøgh Köster / CTO / @tboeghk
Provisioning Vagrant using a Puppet master - the reliable way
Vagrant is a great tool to set up local test machines. Puppet is a great tool to deliver unified server configuration to a lot of machines. A Puppet master centralizes the provisioning process. Unfortunately combining Vagrant with a Puppet master will lead you directly into SSL certificate hell. Here’s how we got back out of hell …
A problem of pain
When developing in a team and iteratively launching and destroying your local
Vagrant testing machine, you’ll hit a limitation of the puppet_master
provisioner
in Vagrant. When talking to the Puppet master, the client generates a SSL certificate
based on the local machine fingerprint to sign it’s requests. This certificate is
stored on the Puppet master server.
You can see where we’re heading: As soon as you destroy
and up
your local
Vagrant machine (even on the same physical hardware), the machine fingerprint
and thus the SSL cert changes as well. All requests to the Puppet master are
rejected.
Another limitation we’re hitting is that the puppet_master
provisioner does not
allow to supply custom facts for Facter, who we depend on in the Vagrant machine.
The idea
The solution is (almost) straightforward and inspired by a Github pull request on the Vagrant project:
-
We’re going to use a local puppet run to properly place the project’s SSL certificates in the Vagrant machine and to supply some Facter facts.
-
Then we’re going to start the “real” Puppet master run and are tweaking it to overcome our sometimes pretty messy internet connection
Setting up Vagrant using two provisioners
We’re going to set up Vagrant to run two consecutive provisioners (order
matters!). The first one is a puppet
provisioner, that executes out of
the local project source and prepares the needed SSL puppet certificates.
Then the additional Facter facts given are put in place for the puppet_master
provisioner.
Vagrant.configure("2") do |config|
# 1) prepare certs to connect to puppet server
config.vm.provision :puppet do |puppet|
puppet.manifests_path = "src/test/puppet/manifests"
puppet.manifest_file = "prepare-puppetserver.pp"
puppet.options = "--fileserverconfig=/vagrant/src/test/puppet/fileserver.conf
--templatedir=/vagrant/src/test/puppet/templates
--debug
--verbose
--environment development"
puppet.facter = {
"application_name" => "your-project-role",
"is_vagrant" => "true"
}
end
# 2) Provision services on the system using Puppet Maschta
config.vm.provision "puppet_server" do |puppet|
puppet.puppet_server = "your.puppet.master.server.de"
puppet.puppet_node = "projectname-vagrant.your.fqdn.de"
puppet.options = "--test
--waitforcert=10
--verbose
--debug
--environment development
--pluginsync
--configtimeout=30m"
end
end
Setting up Puppet – using Puppet
The prepare-puppetserver.pp
syncs the puppet ssl
directory and templates facts
into a textfile in /etc/facter/facts.d
. In our projects, the Vagrantfile
resides
in the root directory and puppet sources in src/test/puppet
.
# place puppetserver certs
notice('Preparing puppet master cert files and facts ...')
file { '/var/lib/puppet/ssl':
ensure => 'directory',
owner => 'puppet',
group => 'puppet',
source => 'puppet:///files/ssl',
mode => '0600',
recurse => true;
} ->
# place puppet facts
file { ['/etc/facter', '/etc/facter/facts.d']:
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0644',
} ->
file { '/etc/facter/facts.d/s24_vagrant_facts.txt':
ensure => file,
owner => 'root',
group => 'root',
content => template('s24_vagrant_facts.txt.erb'),
mode => '0644',
} ->
# stop puppet agent
exec { 'stop-puppet-agent': command => '/etc/init.d/puppet stop', }
The get the file source working, you need to place a src/test/puppet/fileserver.conf
in your project, that resolves the files
mountpoint:
[files]
path /vagrant/src/test/puppet/files
allow *
To get it activated, set the --fileserverconfig
and --templatedir
properly in
your Vagrant setup.
Creating Puppet certs on your first run
To obtain the SSL certs to configure through Puppet, your local Vagrant box needs to
contact the Puppet master on it’s very first run. On your first run, comment out your local
puppet
provisioner and let the puppet_master
provisioner connect to the Puppet master
and create a local cert cache in /var/lib/puppet/ssl
.
Copy those script to your project directory conveniently mounted at
/vagrant/src/test/puppet/files
. Put your local puppet
provisioner back into place and
you’re ready to run.