In a previous blog post I explored IAM roles, with a patched s3cmd. I have since discovered that boto supports IAM roles too, and that makes things even easier. It even comes with a fetch_file command to use without writing any Python code.

So overall, what I want to happen during EC2 instance creation (in a VPC) is:

  1. set the hostname to the EC2 instance ID, and configure /etc/hosts
  2. add minimal packages
  3. register this instance in the DNS
  4. use IAM roles to securely download bootstrap code and data from S3, and execute that

The userdata I use for this looks like this:

Content-Type: multipart/mixed; boundary="===============0933669979118751095=="
MIME-Version: 1.0

--===============0933669979118751095==
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="my-cloudconfig.txt"

#cloud-config

preserve_hostname: true
manage_etc_hosts: false

bootcmd:
- cloud-init-per instance my_set_hostname sh -xc "echo $INSTANCE_ID > /etc/hostname; hostname -F /etc/hostname"
- cloud-init-per instance my_etc_hosts sh -xc "sed -i -e '/^127.0.1.1/d' /etc/hosts; echo 127.0.1.1 $INSTANCE_ID.MYDOMAIN $INSTANCE_ID >> /etc/hosts"

cloud_final_modules:
 - rightscale_userdata
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - [scripts-user, always]
 - keys-to-console
 - phone-home
 - final-message

apt_sources:
- source: deb http://archive.ubuntu.com/ubuntu precise multiverse
- source: deb-src http://archive.ubuntu.com/ubuntu precise multiverse
- source: deb http://archive.ubuntu.com/ubuntu precise-updates multiverse
- source: deb-src http://archive.ubuntu.com/ubuntu precise-updates multiverse
- source: deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse
- source: deb-src http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse

packages:
- language-pack-en
- python-pip

--===============0933669979118751095==
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="my-userdata-userscript.txt"

#!/bin/sh

cd /root

pip install --upgrade boto

python <<PY
import boto
from boto.s3.key import Key

route53 = boto.connect_route53()
changes = ResourceRecordSets(route53, "MY_HOSTED_ZONE_ID")
change = changes.add_change("CREATE", instance_id + ".MY.DOMAIN","A")
change.add_value(local_ipv4)
changes.commit()

c = boto.connect_s3()
b = c.get_bucket('MYBUCKET')
k = Key(b)
k.key = '/MYBOOTSTRAP.sh'
k.get_contents_to_filename('MYBOOTSTRAP.sh')
PY

chmod u+x ./MYBOOTSTRAP.sh
./MYBOOTSTRAP.sh
--===============0933669979118751095==--
EOM

Fun stuff.