#!/bin/bash # Note: you need "jp" installed # to run this command. You can # brew tap jmespath/jmespath && brew install jp # to install on a Mac. # Or you can download prebuilt binaries # from: https://github.com/jmespath/jp/releases docs="usage: setup-dev-ec2-instance This command will set up the necessary resources needed to run dev-ec2-instance. You can also use this script to check that all the necessary resources are setup. If any resources are missing, it will prompt you to set up the necessary parts. " TRUST_POLICY='{ "Version": "2008-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "ec2.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] }' errexit() { echo "ERROR: $(basename "$0") (line ${LINENO}): ${1:-"Unknown Error"}" 1>&2 exit 1 } usage() { echo "$docs" } resource_exists() { # Run a command with an added --query length(...) # and check if it results in at least a 1 element list. local command local num_matches set -e if [[ -z "$2" ]] then command="$1 --query length(*[0])" else command="$1 --query length($2)" fi num_matches=$($command) if [[ "$?" -ne 0 ]] then echo "Could not check if resource exists, exiting." exit 2 fi set +e if [[ "$num_matches" -gt 0 ]] then # RC of 0 mean the resource exists, "success" return 0 else return 1 fi } has_new_enough_openssl() { # This is a quirk of openssl. # RC of 1 (an error) means the command # exists. Otherwise an RC of 0 means # the command does *not* exist. So # we have to reverse this because we want # RC 0 -> success/true # RC 1 -> fail/false openssl pkey -foobar 2>/dev/null if [[ "$?" -eq 0 ]]; then return 1 fi return 0 } import_key_pair() { echo -n "Would you like to import ~/.ssh/id_rsa.pub? [y/N]: " read confirmation if [[ "$confirmation" != "y" ]] then return fi aws ec2 import-key-pair \ --key-name id_rsa \ --public-key-material file://~/.ssh/id_rsa.pub } create_instance_profile() { echo -n "Would you like to create an IAM instance profile? [y/N]: " read confirmation if [[ "$confirmation" != "y" ]]; then return fi aws iam create-role --role-name dev-ec2-instance \ --assume-role-policy-document "$TRUST_POLICY" || errexit "Could not create Role" # Use a managed policy policies=$(aws iam list-policies --scope AWS) admin_policy_arn=$(jp -u \ "Policies[?PolicyName=='AdministratorAccess'].Arn | [0]" <<< "$policies") aws iam attach-role-policy \ --role-name dev-ec2-instance \ --policy-arn "$admin_policy_arn" || errexit "Could not attach role policy" # Then we need to create an instance profile from the role. aws iam create-instance-profile \ --instance-profile-name dev-ec2-instance || \ errexit "Could not create instance profile." # And add it to the role aws iam add-role-to-instance-profile \ --role-name dev-ec2-instance \ --instance-profile-name dev-ec2-instance || \ errexit "Could not add role to instance profile." } compute_key_fingerprint() { # Computes the fingerprint of a public SSH key given a private # RSA key. This can be used to compare against the output given # from aws ec2 describe-key-pair. openssl pkey -in ~/.ssh/id_rsa -pubout -outform DER | \ openssl md5 -c | \ cut -d = -f 2 | \ tr -d '[:space:]' } tag_security_group() { aws ec2 describe-security-groups --query "SecurityGroups[].[GroupName,GroupId,VpcId]" --output text | column -t echo -n "Enter the security group ID to tag: " read response if [ -z "$response" ]; then return fi echo "Tagging security group" aws ec2 create-tags --resources "$response" --tags Key=dev-ec2-instance,Value=linux } do_setup() { echo "Checking for required resources..." echo "" # 1. Check if a security group is found for # both windows and non-windows tags. # If not, we'll eventually give the option to # configure this. if resource_exists "aws ec2 describe-security-groups \ --filter Name=tag:dev-ec2-instance,Values=linux"; then echo "Security groups exists." else echo "Security group not found." tag_security_group fi # 2. Make sure the keypair is imported. if [[ ! -f ~/.ssh/id_rsa ]]; then echo "Missing ~/.ssh/id_rsa key pair." elif has_new_enough_openssl; then fingerprint=$(compute_key_fingerprint ~/.ssh/id_rsa) if resource_exists "aws ec2 describe-key-pairs \ --filter Name=fingerprint,Values=$fingerprint"; then echo "Key pair exists." else echo "~/.ssh/id_rsa key pair does not appear to be imported." import_key_pair fi else echo "Can't check if SSH key has been imported." echo "You need at least openssl 1.0.0 that has a \"pkey\" command." echo "Please upgrade your version of openssl." fi # 3. Check that they have an IAM role called dev-ec2-instance. # There is no server side filter for this like we have with the EC2 # APIs, so we have to manually use a --query option for us. if resource_exists "aws iam list-instance-profiles" \ "InstanceProfiles[?InstanceProfileName=='dev-ec2-instance']"; then echo "Instance profile exists." else echo "Missing IAM instance profile 'dev-ec2-instance'" create_instance_profile fi echo "Setup complete, you can now run: ./dev-ec2-instance" } do_setup