Skip to content

Instantly share code, notes, and snippets.

@knoxilla
Last active September 23, 2020 21:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knoxilla/e325bb905788230d7ec37f424147f2fc to your computer and use it in GitHub Desktop.
Save knoxilla/e325bb905788230d7ec37f424147f2fc to your computer and use it in GitHub Desktop.
Useful AWS bash function - resource_exists() - for pre-checking and avoiding collisions
#!/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