diff --git a/providers/ec2/__init__.py b/providers/ec2/__init__.py index 4caecde..eecf14b 100644 --- a/providers/ec2/__init__.py +++ b/providers/ec2/__init__.py @@ -11,6 +11,7 @@ from tasks import apt from tasks import boot from tasks import security from tasks import network +from tasks import initd def initialize(): @@ -51,7 +52,9 @@ def tasks(tasklist, manifest): security.DisableSSHDNSLookup(), network.RemoveDNSInfo(), network.ConfigureNetworkIF(), - network.ConfigureDHCP()) + network.ConfigureDHCP(), + initd.ResolveInitScripts(), + initd.InstallInitScripts()) from common.tasks import TriggerRollback tasklist.add(TriggerRollback()) diff --git a/providers/ec2/assets/init.d/ec2-get-credentials b/providers/ec2/assets/init.d/ec2-get-credentials new file mode 100644 index 0000000..b304ae2 --- /dev/null +++ b/providers/ec2/assets/init.d/ec2-get-credentials @@ -0,0 +1,45 @@ +#!/bin/bash +### BEGIN INIT INFO +# Provides: ec2-get-credentials +# Required-Start: $network +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: +# Description: Retrieve the ssh credentials and add to authorized_keys +### END INIT INFO +# +# ec2-get-credentials - Retrieve the ssh credentials and add to authorized_keys +# +# Based on /usr/local/sbin/ec2-get-credentials from Amazon's ami-20b65349 +# + +prog=$(basename $0) +logger="logger -t $prog" + +public_key_url=http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key +username='root' +# A little bit of nastyness to get the homedir, when the username is a variable +ssh_dir="`eval printf ~$username`/.ssh" +authorized_keys="$ssh_dir/authorized_keys" + +# Try to get the ssh public key from instance data. +public_key=`wget -qO - $public_key_url` +if [ -n "$public_key" ]; then + if [ ! -f $authorized_keys ]; then + if [ ! -d $ssh_dir ]; then + mkdir -m 700 $ssh_dir + chown $username:$username $ssh_dir + fi + touch $authorized_keys + chown $username:$username $authorized_keys + fi + + if ! grep -s -q "$public_key" $authorized_keys; then + printf "\n%s" -- "$public_key" >> $authorized_keys + $logger "New ssh key added to $authorized_keys from $public_key_url" + chmod 600 $authorized_keys + chown $username:$username $authorized_keys + fi +fi diff --git a/providers/ec2/assets/init.d/ec2-run-user-data b/providers/ec2/assets/init.d/ec2-run-user-data new file mode 100644 index 0000000..17b8b6f --- /dev/null +++ b/providers/ec2/assets/init.d/ec2-run-user-data @@ -0,0 +1,46 @@ +#!/bin/bash +### BEGIN INIT INFO +# Provides: ec2-run-user-data +# Required-Start: ec2-get-credentials +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: +# Description: Run instance user-data if it looks like a script. +### END INIT INFO +# +# Only retrieves and runs the user-data script once per instance. If +# you want the user-data script to run again (e.g., on the next boot) +# then readd this script with insserv: +# insserv -d ec2-run-user-data +# +prog=$(basename $0) +logger="logger -t $prog" +instance_data_url="http://169.254.169.254/2008-02-01" + + +# Retrieve the instance user-data and run it if it looks like a script +user_data_file=$(tempfile --prefix ec2 --suffix .user-data --mode 700) +$logger "Retrieving user-data" +wget -qO $user_data_file $instance_data_url/user-data 2>&1 | $logger + +if [ $(file -b --mime-type $user_data_file) = 'application/x-gzip' ]; then + $logger "Uncompressing gzip'd user-data" + mv $user_data_file $user_data_file.gz + gunzip $user_data_file.gz +fi + +if [ ! -s $user_data_file ]; then + $logger "No user-data available" +elif head -1 $user_data_file | egrep -v '^#!'; then + $logger "Skipping user-data as it does not begin with #!" +else + $logger "Running user-data" + $user_data_file 2>&1 | logger -t "user-data" + $logger "user-data exit code: $?" +fi +rm -f $user_data_file + +# Disable this script, it may only run once +insserv -r $0 diff --git a/providers/ec2/assets/init.d/expand-volume b/providers/ec2/assets/init.d/expand-volume new file mode 100644 index 0000000..3b2d2a6 --- /dev/null +++ b/providers/ec2/assets/init.d/expand-volume @@ -0,0 +1,26 @@ +#!/bin/bash +### BEGIN INIT INFO +# Provides: expand-volume +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: +# Description: Expand the filesystem of the mounted root volume to its maximum possible size +### END INIT INFO + +prog=$(basename $0) +logger="logger -t $prog" + +device_path="/dev/xvda1" + +filesystem=`blkid | grep $device_path | sed 's#\(.*\):.*TYPE="\(.*\)".*#\2#'` + +case $filesystem in + xfs) xfs_growfs / ;; + ext2) resize2fs $device_path ;; + ext3) resize2fs $device_path ;; + ext4) resize2fs $device_path ;; + *) $logger "The filesystem $filesystem was not recognized. Unable to expand size." ;; +esac diff --git a/providers/ec2/assets/init.d/generate-ssh-hostkeys b/providers/ec2/assets/init.d/generate-ssh-hostkeys new file mode 100644 index 0000000..c9efb12 --- /dev/null +++ b/providers/ec2/assets/init.d/generate-ssh-hostkeys @@ -0,0 +1,36 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: generate-ssh-hostkeys +# Required-Start: $local_fs +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: +# Description: Generate ssh host keys if they do not exist +### END INIT INFO + +prog=$(basename $0) +logger="logger -t $prog" + +rsa_key="/etc/ssh/ssh_host_rsa_key" +dsa_key="/etc/ssh/ssh_host_dsa_key" +ecdsa_key="/etc/ssh/ssh_host_ecdsa_key" + +# Exit if the hostkeys already exist +if [ -f $rsa_key -a -f $dsa_key -a -f $ecdsa_key ]; then + exit +fi + +# Generate the ssh host keys +[ -f $rsa_key ] || ssh-keygen -f $rsa_key -t rsa -C 'host' -N '' +[ -f $dsa_key ] || ssh-keygen -f $dsa_key -t dsa -C 'host' -N '' +[ -f $ecdsa_key ] || ssh-keygen -f $ecdsa_key -t ecdsa -C 'host' -N '' + +# Output the public keys to the console +# This allows user to get host keys securely through console log +echo "-----BEGIN SSH HOST KEY FINGERPRINTS-----" | $logger +ssh-keygen -l -f $rsa_key.pub | $logger +ssh-keygen -l -f $dsa_key.pub | $logger +ssh-keygen -l -f $ecdsa_key.pub | $logger +echo "------END SSH HOST KEY FINGERPRINTS------" | $logger diff --git a/providers/ec2/assets/init.d/squeeze/generate-ssh-hostkeys b/providers/ec2/assets/init.d/squeeze/generate-ssh-hostkeys new file mode 100644 index 0000000..148b87d --- /dev/null +++ b/providers/ec2/assets/init.d/squeeze/generate-ssh-hostkeys @@ -0,0 +1,33 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: generate-ssh-hostkeys +# Required-Start: $local_fs +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: +# Description: Generate ssh host keys if they do not exist +### END INIT INFO + +prog=$(basename $0) +logger="logger -t $prog" + +rsa_key="/etc/ssh/ssh_host_rsa_key" +dsa_key="/etc/ssh/ssh_host_dsa_key" + +# Exit if the hostkeys already exist +if [ -f $rsa_key -a -f $dsa_key ]; then + exit +fi + +# Generate the ssh host keys +[ -f $rsa_key ] || ssh-keygen -f $rsa_key -t rsa -C 'host' -N '' +[ -f $dsa_key ] || ssh-keygen -f $dsa_key -t dsa -C 'host' -N '' + +# Output the public keys to the console +# This allows user to get host keys securely through console log +echo "-----BEGIN SSH HOST KEY FINGERPRINTS-----" | $logger +ssh-keygen -l -f $rsa_key.pub | $logger +ssh-keygen -l -f $dsa_key.pub | $logger +echo "------END SSH HOST KEY FINGERPRINTS------" | $logger diff --git a/providers/ec2/tasks/initd.py b/providers/ec2/tasks/initd.py new file mode 100644 index 0000000..4571c4e --- /dev/null +++ b/providers/ec2/tasks/initd.py @@ -0,0 +1,49 @@ +from base import Task +from common import phases +import os.path + + +class ResolveInitScripts(Task): + description = 'Determining which startup scripts to install or disable' + phase = phases.system_modification + + def run(self, info): + init_scripts = {'ec2-get-credentials': 'ec2-get-credentials', + 'ec2-run-user-data': 'ec2-run-user-data', + 'expand-volume': 'expand-volume'} + + init_scripts['generate-ssh-hostkeys'] = 'generate-ssh-hostkeys' + if info.manifest.system['release'] == 'squeeze': + init_scripts['generate-ssh-hostkeys'] = 'squeeze/generate-ssh-hostkeys' + + disable_scripts = ['hwclock.sh'] + if info.manifest.system['release'] == 'squeeze': + disable_scripts.append('hwclockfirst.sh') + + for name, path in init_scripts.iteritems(): + init_scripts[name] = os.path.normpath(os.path.join(os.path.dirname(__file__), '../assets/init.d', path)) + + info.initd = {'install': init_scripts, + 'disable': disable_scripts} + + +class InstallInitScripts(Task): + description = 'Installing startup scripts' + phase = phases.system_modification + after = [ResolveInitScripts] + + def run(self, info): + import stat + rwxr_xr_x = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | + stat.S_IRGRP | stat.S_IXGRP | + stat.S_IROTH | stat.S_IXOTH) + from shutil import copy + from common.tools import log_check_call + for name, src in info.initd['install'].iteritems(): + dst = os.path.join(info.root, 'etc/init.d', name) + copy(src, dst) + os.chmod(dst, rwxr_xr_x) + log_check_call(['chroot', info.root, '/sbin/insserv', '-d', name]) + + for name in info.initd['disable']: + log_check_call(['chroot', info.root, '/sbin/insserv', '-r', name])