Last active
September 23, 2020 21:20
-
-
Save knoxilla/e325bb905788230d7ec37f424147f2fc to your computer and use it in GitHub Desktop.
Useful AWS bash function - resource_exists() - for pre-checking and avoiding collisions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# written and explained by others! | |
# https://blogs.aws.amazon.com/cli/post/Tx93V7O09I96SO/AWS-re-Invent-2015-and-more | |
# https://github.com/awslabs/awscli-reinvent2015-examples/blob/master/scripts/setup-dev-ec2-instance | |
# 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" | |
} | |
## LOOK AT THIS! | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment