From 20513b6595ff1ae1bf0be4d899bfc83806b5f5d4 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Sun, 24 Dec 2017 03:46:11 +0000 Subject: Initial commit --- LICENSE.txt | 19 ++++++++++++++++ Makefile | 5 +++++ README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++ tiny-ec2-bootstrap | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 README.md create mode 100644 tiny-ec2-bootstrap diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..736d3fe --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2017 Michael Crute + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..394004e --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +PREFIX?=/ + +.PHONY: install +install: + install -Dm 755 tiny-ec2-bootstrap $(PREFIX)/etc/init.d/tiny-ec2-bootstrap diff --git a/README.md b/README.md new file mode 100644 index 0000000..86ebfc5 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# Tiny EC2 Bootstrapper + +This is designed to do the minimal amount of work required to bootstrap an EC2 +instance based on the local settings assigned at boot time as well as the +user's configured settings. This is in-concept similar to +[cloud-init](https://cloudinit.readthedocs.io/en/latest/) but trades features +and cloud platform support for small size and limited external dependencies. + +## Requirements + +The most important feature of this bootstrapper is the very limited set of +dependencies. In-fact this works with just busybox provided the wget applet is +built-in. The only required dependencies are: + +- bash-like shell (e.g. bash, dash, ash) +- wget + +## Supported Features and Environments + +cloud-init has support for many different cloud providers. This project only +supports EC2, specifically the [EC2 metadata +service](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) +is a hard requirement of using this bootstrapper. All of the data for the +supported features below is sourced from the EC2 instance metadata service +which runs on every EC2 instance at IP 169.254.169.254. + +cloud-init also has a very rich feature set with support for adding users, +installing packages, and many other things. This bootstrap does not support +those things. Instead it supports: + +- setting system hostname +- install user's configured SSH keys to the alpine user's authorized_keys file +- run any script-like user data (must start with #!) + +These steps only run once. After the initial bootstrap the bootstrapper script +is a no-op. To force the script to run again at boot time remove the file +`/var/lib/cloud/.bootstrap-complete` and reboot the instance. + +## User Data + +User data is provided at instance boot time and can be any arbitrary string of +data. The bootstrapper will consider any user data that begins with the ASCII +characters '#!' to be a script. It will write the entire contents of the user +data to `/var/lib/cloud/user-data.sh`, make the file executable, and execute +the file piping any output to `/var/log/cloud-bootstrap.log`. + +The user data script can do anything it pleases with the instance. It will be +run as root and networking will be up. No other grantees about system state are +made at the point the script runs. + +## Assumptions + +- This was written for Alpine Linux and thus assumes that the login user is + called alpine. This could be configurable in the future but currently is not. + +- The script is run by OpenRC diff --git a/tiny-ec2-bootstrap b/tiny-ec2-bootstrap new file mode 100644 index 0000000..510f4f7 --- /dev/null +++ b/tiny-ec2-bootstrap @@ -0,0 +1,66 @@ +#!/sbin/openrc-run +# vim:set ft=bash: + +description="Provides EC2 cloud bootstrap" + +depend() { + need net + provide cloud-final +} + +_get_metadata() { + local uri="$1" + wget -qO - "http://169.254.169.254/latest/$uri" 2>/dev/null +} + +_update_hostname() { + local ec2_fqdn="$(_get_metadata meta-data/hostname)" + local short_hostname="${ec2_fqdn%%\.*}" + echo "$short_hostname" > /etc/hostname + hostname -F /etc/hostname + echo -e "127.0.1.1\t$ec2_fqdn $short_hostname" >> /etc/hosts +} + +_set_ssh_keys() { + local user="$1" + local group="$(getent passwd $user | cut -d: -f4)" + local ssh_dir="$(getent passwd $user | cut -d: -f6)/.ssh" + local keys_file="$ssh_dir/authorized_keys" + + if [ ! -d "$ssh_dir" ]; then + mkdir -p "$ssh_dir" + chmod 755 "$ssh_dir" + fi + + [ -f "$keys_file" ] && rm "$keys_file" + + touch "$keys_file" + chmod 600 "$keys_file" + chown -R $user:$group "$ssh_dir" + + for key in "$(_get_metadata meta-data/public-keys/)"; do + echo $(_get_metadata "meta-data/public-keys/${key%=*}/openssh-key/") >> "$keys_file" + done +} + +_run_userdata() { + user_data=$(_get_metadata user-data) + if echo $user_data | grep '^#!/' 2>&1 >/dev/null; then + echo "$user_data" > /var/lib/cloud/user-data.sh + chmod +x /var/lib/cloud/user-data.sh + /var/lib/cloud/user-data.sh > /var/log/cloud-bootstrap.log 2>&1 + fi +} + +start() { + # Don't bootstrap if the host has already been bootstrapped + [ -f "/var/lib/cloud/.bootstrap-complete" ] && return 0 + + [ -d "/var/lib/cloud" ] || mkdir -p /var/lib/cloud + + ebegin "Setting ec2 hostname"; _update_hostname; eend $? + ebegin "Setting ec2 user ssh keys"; _set_ssh_keys "alpine"; eend $? + ebegin "Running ec2 user data script"; _run_userdata; eend $? + + touch "/var/lib/cloud/.bootstrap-complete" +} -- cgit v1.2.3