This post is more for my own notes so I dont forget how I created this AMI.  It took me a while because the main thing that was missing was the fact that you need to add in a way for the OS to grab your public key info OR to have /etc/passwd set up in the image.  I decided to do the former (grabbing the public key).  Also the other thing people seem to have left off is the fact that you need to install wget or curl in order to run the setup.  Also, a quick thing to note is that to do this tutorial YOU NEED A CENTOS 5 machine to run it on.  Just start one through Amazon and use that.  If you dont have one (if you can’t do that, then this tutorial is probably outta your league anyway).

These are the links that I used to figure this stuff out:

http://www.how-to-linux.com/2009/02/how-to-create-a-centos-52-ec2-amazon-machine-image-ami/

http://www.ioncannon.net/system-administration/115/creating-your-own-fc6-instance-for-ec2/

https://developer.amazonwebservices.com/connect/message.jspa?messageID=76866

Using the first tut. I created my image:

dd if=/dev/zero of=my-image.fs bs=1M count=1024

Then I created my filesystem on the space:

mke2fs -F -j my-image.fs

Create a mount point

mkdir /mnt/ec2-fs
Mount it using a loopback
mount -o loop my-image.fs /mnt/ec2-fs
mkdir /mnt/ec2-fs/dev
Populate /dev some minimal devices
/sbin/MAKEDEV -d /mnt/ec2-fs/dev/ -x console
/sbin/MAKEDEV -d /mnt/ec2-fs/dev/ -x null
/sbin/MAKEDEV -d /mnt/ec2-fs/dev/ -x zero
Create /etc
mkdir /mnt/ec2-fs/etc

Create the yum-xen.conf file.  I modified the ones into the tut to use CentOS5.3 i386 and x86_64.  I listed both below.  For the x86_64 you’ll need to create it on a CentOS 64bit image.

i386

[main]
cachedir=/var/cache/yum
debuglevel=2
logfile=/var/log/yum.log
exclude=*-debuginfo
gpgcheck=0
obsoletes=1
pkgpolicy=newest
distroverpkg=redhat-release
tolerant=1
exactarch=1
reposdir=/dev/null
metadata_expire=1800
[base]
name=CentOS-5.3 – Base
baseurl=http://mirror.centos.org/centos/5.3/os/i386/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
priority=1
protect=1
#released updates
[update]
name=CentOS-5.3 – Updates
baseurl=http://mirror.centos.org/centos/5.3/updates/i386/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
priority=1
protect=1
#packages used/produced in the build but not released
[addons]
name=CentOS-5.3 – Addons
baseurl=http://mirror.centos.org/centos/5.3/addons/i386/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
priority=1
[extras]
name=CentOS 5.3 Extras $releasever – $basearch
baseurl=http://mirror.centos.org/centos/5.3/extras/i386/
enabled=1

x86_64

[main]
cachedir=/var/cache/yum
debuglevel=2
logfile=/var/log/yum.log
exclude=*-debuginfo
gpgcheck=0
obsoletes=1
pkgpolicy=newest
distroverpkg=redhat-release
tolerant=1
exactarch=1
reposdir=/dev/null
metadata_expire=1800
[base]
name=CentOS-5.3 – Base
baseurl=http://mirror.centos.org/centos/5.3/os/x86_64/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
priority=1
protect=1
#released updates
[update]
name=CentOS-5.3 – Updates
baseurl=http://mirror.centos.org/centos/5.3/updates/x86_64/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
priority=1
protect=1
#packages used/produced in the build but not released
[addons]
name=CentOS-5.3 – Addons
baseurl=http://mirror.centos.org/centos/5.3/addons/x86_64/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
priority=1
[extras]
name=CentOS 5.3 Extras $releasever – $basearch
baseurl=http://mirror.centos.org/centos/5.3/extras/x86_64/
enabled=1

Create a proc point for the image and mount it:
mkdir /mnt/ec2-fs/proc
mount -t proc none /mnt/ec2-fs/proc
Run the yum installer and install the Core:
yum -c yum-xen.conf  –installroot=/mnt/ec2-fs -y groupinstall Core
Create a network config script for your new image:
vi /mnt/ec2-fs/etc/sysconfig/network-scripts/ifcfg-eth0
Enter this for file:
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=yes
PEERDNS=yes
IPV6INIT=no
Turn on networking for your image:
vi /mnt/ec2-fs/etc/sysconfig/network
Enter the following:
NETWORKING=yes
Set up the hard drives:
vi /mnt/ec2-fs/etc/fstab
Enter
/dev/sda2  /mnt      ext3    defaults        1 2
/dev/sda3  swap      swap    defaults        0 0
Copy the centos resolv.conf over (if you’re using an Amazon Centos image, if not create one):
cp /etc/resolv.conf /mnt/ec2-fs/etc/resolv.conf
Chroot and start services like sshd:
chroot /mnt/ec2-fs /bin/sh
chkconfig –level 345 sshd on
Install wget or curl
yum install curl (or yum install wget for the bash script below)
Create a startup script to get your private key:
vi /usr/local/sbin/get-credentials.sh
Fill it with this:
#!/bin/bash

# Retreive the credentials from relevant sources.

# Fetch any credentials presented at launch time and add them to
# root’s public keys

PUB_KEY_URI=http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
PUB_KEY_FROM_HTTP=/tmp/openssh_id.pub
PUB_KEY_FROM_EPHEMERAL=/mnt/openssh_id.pub
ROOT_AUTHORIZED_KEYS=/root/.ssh/authorized_keys

# We need somewhere to put the keys.
if [ ! -d /root/.ssh ] ; then
mkdir -p /root/.ssh
chmod 700 /root/.ssh
fi

# Fetch credentials…

# First try http
curl –retry 3 –retry-delay 0 –silent –fail -o $PUB_KEY_FROM_HTTP $PUB_KEY_URI
if [ $? -eq 0 -a -e $PUB_KEY_FROM_HTTP ] ; then
if ! grep -q -f $PUB_KEY_FROM_HTTP $ROOT_AUTHORIZED_KEYS
then
cat $PUB_KEY_FROM_HTTP >> $ROOT_AUTHORIZED_KEYS
echo “New key added to authrozied keys file from parameters”|logger -t “ec2″
fi
chmod 600 $ROOT_AUTHORIZED_KEYS
rm -f $PUB_KEY_FROM_HTTP

elif [ -e $PUB_KEY_FROM_EPHEMERAL ] ; then
# Try back to ephemeral store if http failed.
# NOTE: This usage is deprecated and will be removed in the future
if ! grep -q -f $PUB_KEY_FROM_EPHEMERAL $ROOT_AUTHORIZED_KEYS
then
cat $PUB_KEY_FROM_EPHEMERAL >> $ROOT_AUTHORIZED_KEYS
echo “New key added to authrozied keys file from ephemeral store”|logger -t “ec2″

fi
chmod 600 $ROOT_AUTHORIZED_KEYS
chmod 600 $PUB_KEY_FROM_EPHEMERAL

fi

if [ -e /mnt/openssh_id.pub ] ; then
if ! grep -q -f /mnt/openssh_id.pub /root/.ssh/authorized_keys
then
cat /mnt/openssh_id.pub >> /root/.ssh/authorized_keys
echo “New key added to authrozied keys file from ephemeral store”|logger -t “ec2″

fi
chmod 600 /root/.ssh/authorized_keys
fi

Edit your rc.local:
vi  /etc/rc.local
Add this:
/usr/local/sbin/get-credentials.sh
Exit out of your chroot:
exit
Unmount the image
umount /mnt/ec2-fs/proc
umount -d /mnt/ec2-fs
Time to upload your image and get it registered.  For this, its easiest to just install the ruby scripts that they have to create the image and upload it.  If you dont have ruby, install it:
yum install ruby
Download the EC2 AMI Tools:
wget http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm
Install the EC2 AMI Tools
rpm -Uvh ec2-ami-tools.noarch.rpm
Put both your private key and cert in the same folder as my-image.fs.  This is available in your Amazon account under the X.509 Certificate section.
Use the AMI tools to bundle the your image:
ec2-bundle-image -i my-image.fs -c my-cert.pem -k my-private-key.pem -u 1234-5678-9101 (amazon account id)
This create the bundles the image to an AMI and puts it in /tmp. Now upload the  ec2-bundle to S3.  FYI, you’ll need an S3 account and bucket for this.  (Quick hint:  I use s3Fox plugin in firefox to setup my buckets.)  Much easier this way.
ec2-upload-bundle -b my-bucket -m image.manifest -a my-aws-access-key-id -s my-secret-key-id
After this is done, you need to register the ami before you can use it.  I was using the AWS Management  Console to do this.  It’s located under EC2 Console -> Instances -> Register.
Now you’re done!  Im sure I left some stuff out.  If you have questions, feel free to leave them below.
Update:  Greg pointed out some stuff that I missed (oops!)
I replaced my /etc/fstab with:/dev/sda1 / ext3 user_xattr 0 1
shm /dev/shm tmpfs nodev,nosuid,noexec 0 0

..which made things work better.

Also, I did have to chmod +x /usr/local/sbin/get-credentials.sh

After doing that I could ping and connect to the server, but as soon as I did, ssh told me that I didn’t have access to /bin/bash.

I had created the vm image on a machine with selinux disabled, so I had to do the same on the image by setting SELINUX=disabled in /etc/selinux/config

UPDATE:  missed the /etc/resolv.conf

here is a sample resolv.conf:
search z-2.compute-1.internal
nameserver 172.16.0.23