Note: I posted an update about doing the same with chef here.

This is a quickie techie post that summarizes a few hours of learning that I wish someone else had put up on the web before me. I assume some knowledge about Puppet, and recommend the Pro Puppet book and heard good stuff about Puppet 2.7 Cookbook .

So, I wanted to be able to configure via Puppet the way our new instances should be configured, and then be able to easily spawn new instances that will get configured by said puppet. The first part is installing puppetmaster. I decided to manually setup an EC2 instance that will act as the puppet master:

aptitude install puppetmaster echo "127.0.0.1 puppet" >> /etc/hosts

Under /etc/puppet/manifests/site.pp we place the “main” entry point for the configuration. This is the file that is responsible for including the rest of the files. I copied the structure from somewhere where the actual classes were put under /etc/puppet/manifests/classes and import it in site.pp. Do note that currently this setup only supports a single type of node, but supporting more should be doable using external nodes to classify the node types.

import "classes/*" node default { include default_node }

class default_node { package { 'apache2': ensure => installed } service { 'apache2': ensure => true, enable => true, require => Package['apache2'], } }

Auto-signing new instances

A common problem with puppet setups is that whenever a new puppet connects to the puppet master it hands it a certificate which you then have to automatically sign before the puppetmaster will agree to configure it. This is problematic in setups like mine where I want to be able to spawn new instances with a script and don’t hassle with jumping between the machines right after the certificate was sent and approving it. I found two ways to circumvent this:

1. Simply auto-signing everything and relying on firewalls

In case you can allow yourself to firewall the puppetmaster port (tcp/8140) to be only accessible to trusted instances, you do not actually need to sign the certificates, you can tell puppet to trust whatever it gets and leave the security in the hands of your trusty firewall. With EC2 this is extremely easy:

Setup a security group, I’ll call mine “puppets”

Add a security exception to the puppetmaster that allows access to all instances in the “puppets” group

Create all puppet instances in the “puppets” security group

Configure puppet to automatically sign all requests: echo “*” > /etc/puppet/autosign.conf

I decided to go with this solution since it’s simpler and less likely to get broken. I didn’t see it documented anywhere else. The downside is that you’ve got to have your puppetmaster on EC2 too.

2. Automatically identifying new instances and adding them

This is a solution I saw mentioned a few times online. Using the EC2 API tools write a script that gets the DNS names of all the trusted instances you’ve got and write them. Once you have this getting it to run with a cron job every minute will do the trick. This can be done with sophisticated scripts, but for my (very initial) testing, this seemed to work:

* * * * * ec2-describe-instances | grep ^INSTANCE | awk '{print $4}' > /etc/puppet/autosign.conf

Getting new instances to connect to the master

The last piece of the puzzle. Since we use Ubuntu, we could simply use the Canonical-supplied AMIs. These support user-data scripts that are executed as root once the system boots. Below is a simple script that does this:

Update the instance Add the “puppet” entry to DNS – puppet expects the master to be accessible via “puppet” DNS resolution. This little snippet gets the current IP of the master via our DNS name and writes it to /etc/hosts Install & enable puppet and voila!

#!/bin/bash set -e -x # Needed so that the aptitude/apt-get operations will not be interactive export DEBIAN_FRONTEND=noninteractive apt-get update && apt-get -y upgrade # Find the current IP of the puppet master and make "puppet" point to it puppet_master_ip=$(host my_puppet_master.company.com | grep "has address" | head -1 | awk '{print $NF}') echo $puppet_master_ip puppet >> /etc/hosts aptitude -y install puppet # Enable the puppet client sed -i /etc/default/puppet -e 's/START=no/START=yes/' service puppet restart

Once all of this is up and running, creating a new instance is as easy as:

ec2-run-instances -g puppets --user-data-file start_puppet.sh -t m1.small -k key-pair ami-a403f7cd

Happy puppeting!

You should subscribe to my feed and follow me on twitter!