Mac – Munkiserver Puppet Module

Forget what you know about the word puppet because when I say Puppet I want you to think of configuration/state management to the extreme, and not marionnettes. What can Puppet do, you ask? Puppet can manage a machine from the beginning to the end of its lifecycle. It can enforce a state on a machine. You want to ensure that the SSH/Apache/MySQL services are always running? No problem, Puppet will do that. And you’ll see this first hand after the jump, but it can also automate repetitive tasks (ex: setting up clients) and quickly deploy additional servers to help load balance a critical service. Alright, this sales pitch is over. If you want to know more, you can learn more learn more about how Puppet works here.

Munkiserver? You know about munki, Greg Neagle’s fantastic software management application, but what is munkiserver? Munkiserver is a Ruby on Rails web application for managing your munki setup, developed by Jordan Raine. It uses munki a little bit differently but adds some neat features. For example, clients are in a 1-1 relationship with the server  (i.e. each client has their own manifest), making it super easy to specify one off installs. However, you can still group clients together using computer groups and apply software bundles to them, thus achieving the same level of functionality as regular manifests in vanilla munki. Another difference is that all configurations (ex: pkginfo, manifests, bundles, etc…) are stored in a backend database; there is no flat repo. This does add some complexity and makes it impossible to add manifest logic. However, munkiserver does give you the ability to add raw tags to a package’s pkginfo file via the web application. Now that I mentioned it, everything is done through the web application:

  • Adding/removing computer clients
  • Uploading/editing packages
  • Editing manifests
  • Assigning user/group permissions
  • Viewing which packages have updates (uses to check)
  • Viewing warranty information
  • The list goes on…

If munkiserver sounds like something you want to try but don’t want to spend the time setting it up, today is your lucky day. I’ve wrote a Puppet module that will automatically configure a new instance of the munkiserver application on any Mac OS X 10.6+ system in 20 minutes or less (depending on your internet connection, and CPU speed). And regardless of whether or not you have any knowledge about Puppet or an existing Puppet server, this writeup will assume you don’t in both cases, I will explain how to deploy a new munkiserver using only a local Puppet manifest (no Puppet server required). This is because if you already have a Puppet server I think you’ll know what to do for the most part. Details after the jump.

First things first. prep your target machine:

  1. Download and install the Puppet (2.7.20) and Facter (1.6.17). This module should work with any version of Puppet and Facter but I’ve only tested with the above versions.
  2. Optional: Download and install the XCode Command Line Tools for your OS version. If you don’t, this module will download a 3rd party GCC compiler for you (provided by kennethreitz).
  3. Create a SSL cert, key, and chain. This web application is secure, yo. There are a variety of ways to do this but a cheap and cheerful way is to use the CA tools provided by dayglojesus, here.
  4. I’ve used the Puppet Homebrew module from bjoernalbers (which was forked from kelseyhightower) to install some necessary packages. So once you’ve installed Puppet on your target machine, install this module by running the following:
    1. sudo puppet module install bjoernalbers-homebrew
  5. And finally download the munkiserver module and place it in /etc/puppet/modules (the homebrew module should also be in that location):
    1. cd /etc/puppet/modules
    2. curl -o '' && unzip ./ && mv ./munkiserver_module-master ./munkiserver_module

Now that you have everything in place we can begin creating our local Puppet manifest. The munkiserver module takes parameters so you can pick and choose some aspects. An example manifest for this module would look like this:

class { ‘munkiserver_module’:
app_pass => ‘12345’,
db_pass => ‘makethishardtoguess’,
user => ‘munkiserver’,
path => ‘/Library/WebServer/Documents’,
munkitools => ‘‘,
xquartz => ‘‘,
gcc => ‘‘,
adapter => ‘mysql2’,
db_host => ‘localhost’,
db_name => ‘munkiserver’,
db_user => ‘munki’,
db_socket => ‘/var/mysql/mysql.sock’,
apache => true,
passenger_vers => ‘3.0.19’,

munkiserver_module::vhost { ‘munkiserver’:
ssl_cert => ‘/etc/apache2/ssl/server.cert.pem’,
ssl_key => ‘/etc/apache2/ssl/server.key.pem’,
ssl_chain => ‘/etc/apache2/ssl/server.chain.pem’,
public_dir => ‘/Library/WebServer/Documents/munkiserver/public’,
pkg_store => ‘/Library/WebServer/Documents/munkiserver/packages’,
vhost => ‘*’, port          => ‘443’,
svr_name => ‘’,
redirect_http => true,

I’ll go over these parameters so you know what you’re specifying. Some of the above parameters have default values, which actually means you don’t need to specify them. However, I’ve specified everything just so I can explain it better:

  • munkiserver_module resource
    • app_pass
      • The password that will be set for the root user of the munkiserver application. Must be between 5-24 characters. This can be changed via the application GUI afterwards.
    • db_pass
      • The password that will be set for the mysql database user. If you will be managing the state of your server with this puppet module afterwards, this cannot be changed once set.
    • apache
      • Boolean flag to specify whether or not to use apache/passenger to handle http requests. If you specify true, ensure you declare a munkiserver_module::vhost resource.
    • user
      • This will be the local user that the application is configured under. If the user does not exist the module will create it (recommended). If the module creates a local user there will be no password for the account. To become the user you’ll need to su to it from root. The default value is ‘munkiserver’.
    • path
      • This is the path at which the munkiserver folder will reside. It defaults to ‘/Library/WebServer/Documents’.
    • munkitools
    • xquartz
    • gcc
      • Download location for the gcc compiler. Will only be installed if the XCode Command Line Tools haven’t been. If you specify your own location make sure it’s a pkg. Defaults to the appropiate package for your Mac OS X version (should never need to set this, unless the download location changes).
    • adapter
      • The database adapter to use for the munkiserver application. Change at your own risk. Defaults to ‘mysql2’.
    • db_host
      • The host of the mysql database. Defaults to ‘localhost’.
    • db_name
      • The name of the mysql database that will be created and used for the munkiserver application. Defaults to ‘munkiserver’.
    • db_user
      • The name of the mysql user that the application will create and use. Defaults to ‘munki’.
    • db_socket
      • The socket location for mysql. Defaults to ‘/var/mysql/mysql.sock’.
    • passenger_vers
      • The version of Phusion Passenger you want to install. This parameter will only be taken into consideration if the apache parameter is set to true. You can also only specify stable versions. Defaults to the latest stable version at this time, ‘3.0.19’.
  • munkiserver_module::vhost resource
    • ssl_cert
      • The location of the SSL crt file.
    • ssl_key
      • The location of the SSL key file.
    • ssl_chain
      • The location of the SSL chain file.
    • public_dir
      • The location of munkiserver’s public directory.
    • pkg_store
      • The location of munkiserver’s package directory.
    • vhost
      • The vhost name. Defaults to ‘*’.
    • port
      • The port you want the web application to listen on. Defaults to ‘443.
    • svr_name
      • The DNS name you want your munkiserver application to respond to. This defaults to the FQDN of the machine.
    • redirect_http
      • Whether or not you want to redirect all http traffic to the server to the munkiserver application. Defaults to ‘false’.

Now that you know what all of the parameters do, you can tailor your manifest to your environment. If you need another manifest example, view the example comment section of this module’s init.pp class. I strongly recommend though that you use apache and passenger to handle the http/https requests. Besides the obvious performance benefits, if you don’t you’ll otherwise need to create a launchd job to fire up your server on every reboot using the following command:

rails s -e production

Next create a munkiserver.pp file, copy the example manifest above, and edit the parameter values where you see fit. Once that’s done tell Puppet to run your local manifest:

sudo puppet apply /path/to/munkiserver.pp

Sit back and watch the magic happen. Depending on your internet connection, CPU speed, and if you have the Xcode Command Line Tools pre-installed, this command should take approximately 15-20 minutes to complete. Now there is a chance it may fail, and this could be for any number of reasons (one of the homebrew packages has been changed unexpectedly, interrupted download, etc…) . This module has a lot of moving parts and each resource specified depends on the resource before it. I’ve tried to take into account almost every scenario and have tested the living daylights out of it, but I’m sure there are still more edge cases I haven’t come across. If this happens to you, I’ve outputted the stdin and stdout of most major commands inside the module to log files located in ‘/tmp/munkiserver’. These are there to assist you in troubleshooting if anything goes wrong. They’re sequentially ordered with the most recently run being at the bottom (if arranged by filename). An example filename for a log is ‘/tmp/munkiserver/1_2_pre_reqs-install-ruby-1.9.3-p0.log’. A breakdown of the name tells us its story:

  • 1_2
    • Means that this resource was ran second in the first stage.
  • _pre_reqs-
    • Means that the resource that generated the log file is located inside the pre_reqs manifest of the module.
  • install-ruby-1.9.3-p0
    • The exact name of the resource that created the log file.

If it fails don’t worry about running the Puppet apply command multiple times. The module has been configured not to run resources that aren’t required. If you do run into problems please feel free to leave a comment or message me, I’ll be happy to assist. I also welcome any suggestions for improvement. Once Puppet finishes your manifest successfully, you should be able to login to the web application at, using root for the username and the app_pass parameter value for the password.


  • Unlike other Puppet modules, I recommend using this module only up until you get a working installation of munkiserver. The reason for this is that the munkiserver environment may change in some way causing one of the resources to run again causing possible issues. It’s also not worth anyone’s time tweaking this module to take into account every instance of change that could happen. If you are applying this module in a local manifest you don’t need to worry about this.
  • If you’re going to let Puppet run this module continually, do not change the db_pass once you’ve set it as it will cause other resources to fail. However, you can change the app_pass through the GUI of the munkiserver application once it’s operational. I recommend this.
  • This module needs to create the root user for the munkiserver application (different than the local user it may create). Unfortunately this process is very picky about its parameters. In some cases it will act like it succeeds but in reality it doesn’t like one of the values, just be aware of this.
  • Make sure you specify a vhost resource type if the apache parameter value is set to true.
  • While munkiserver can use a sqlite database, this module doesn’t allow it. It’s inferior don’t use it.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s