Last active
June 9, 2022 00:26
-
-
Save javipolo/28147cbb5737a082ede27ef7e28ff90a to your computer and use it in GitHub Desktop.
Connect to ec2 instances using either InstanceId, Name tag or Ip address, using multiple ssh keys as identities
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 | |
# Connect to ec2 instances using either InstanceId, Name tag or Ip address | |
# Usage: | |
# - ec2ssh i-123124123123 | |
# - ec2ssh [-n 2] name_tag | |
# - ec2ssh IP | |
username=core | |
keypath=~/.ssh/aws | |
ssh_opts="" | |
# Use awless or awscli (auto tries awless, and if not, awscli) | |
backend=auto | |
ssh_strict=false | |
# Route through VPN | |
add_route=false | |
route='$ip dev tun0 scope link' | |
usage(){ | |
cat << EOF | |
Usage: | |
ec2ssh [options] host [command] | |
Options: | |
-l List only, but do not run ssh | |
-b backend Use backend to query aws [awscli or awless] (Default: $backend) | |
-r region AWS region | |
-u username username (Default: $username) | |
-h hostnum When using a pattern, connect to this number of host on the list | |
-s true/false If true, use ssh strict hostkey mode (Default: $ssh_strict) | |
-d debug. Just echo the ssh command | |
Examples: | |
ec2ssh i-123124123123 | |
ec2ssh -n 2 -s false name_tag | |
ec2ssh -u ubuntu i-123412332 ls / | |
EOF | |
exit 1 | |
} | |
add_route(){ | |
export ip=$1 | |
local ip_route="$(echo ${route} | envsubst) " | |
ip route | grep -qx "$ip_route" || { echo "Adding route to $ip" >&2; sudo ip route add $ip_route; } | |
} | |
backend_auto(){ | |
command -v awless > /dev/null && echo -n awless && return | |
command -v aws > /dev/null && echo -n awscli && return | |
echo "ERROR. No awless or aws commands found in path. Aborting" | |
exit 1 | |
} | |
while getopts "ld:p:r:u:n:s:" o; do | |
case "${o}" in | |
l) listonly=true ;; | |
d) debug="echo" ;; | |
b) backend=${OPTARG} ;; | |
p) profile=${OPTARG} ;; | |
r) region=${OPTARG} ;; | |
u) username=${OPTARG} ;; | |
n) hostnum=$((${OPTARG}-1)) ;; | |
s) ssh_strict=${OPTARG} ;; | |
*) usage ;; | |
esac | |
done | |
shift $((OPTIND-1)) | |
host=$1; shift | |
# Resolve auto backend | |
[ "$backend" == "auto" ] && backend=$(backend_auto) | |
# Generic functions | |
get_running_instances(){ ${backend}_get_running_instances $@; } | |
filter_by(){ ${backend}_filter_by $@; } | |
get_by_id(){ ${backend}_get_by_id $@; } | |
get_by_publicip(){ ${backend}_get_by_publicip $@; } | |
get_by_privateip(){ ${backend}_get_by_privateip $@; } | |
get_instance_id_by_name(){ ${backend}_get_instance_id_by_name $@; } | |
list_instances_by_name(){ echo "Instance list"; ${backend}_list_instances_by_name $@ | cat -n; echo ""; } | |
# awscli stuff | |
awscli_args(){ | |
args="" | |
[ "$profile" ] && args="$args --profile $profile" | |
[ "$region" ] && args="$args --region $region" | |
echo -n "$args" | |
} | |
awscli="aws $(awscli_args)" | |
awscli_get_running_instances(){ | |
$awscli ec2 describe-instances | jq -r '.Reservations[].Instances[] | select(.State.Name=="running")' | |
} | |
awscli_filter_by(){ | |
field=$1 | |
value=$2 | |
echo "$instances" | jq -r 'select(.'$field'=="'$value'") | .PublicIpAddress, .KeyName, (.Tags[] | select(.Key=="Name") | .Value), .InstanceId' | xargs | |
} | |
awscli_get_by_id(){ | |
awscli_filter_by InstanceId $1 | |
} | |
awscli_get_by_publicip(){ | |
awscli_filter_by PublicIpAddress $1 | |
} | |
awscli_get_by_publicip(){ | |
awscli_filter_by PrivateIpAddress $1 | |
} | |
awscli_list_instances_by_name(){ | |
name=$1 | |
echo "$instances" | jq -r 'select((.Tags[]|select(.Key=="Name")|.Value) | contains("'$name'")) | "\(.InstanceId) \((.Tags[] | select(.Key=="Name") | .Value)) \(.PublicIpAddress)"' 2>/dev/null | |
} | |
awscli_get_instance_id_by_name(){ | |
name=$1 | |
num=${2:-0} | |
echo "$instances" | jq 'select((.Tags[]|select(.Key=="Name")|.Value) | contains("'$name'"))' 2>/dev/null | jq -s . | jq -r .[$num].InstanceId | |
} | |
# awless stuff | |
awless_args(){ | |
args="--format=json" | |
[ "$profile" ] && args="$args -p $profile" | |
[ "$region" ] && args="$args -r $region" | |
echo -n "$args" | |
} | |
awless="awless $(awless_args)" | |
awless_get_running_instances(){ | |
$awless list instances | jq '.[] | select(.State=="running")' | |
} | |
awless_filter_by(){ | |
field=$1 | |
value=$2 | |
echo "$instances" | jq -r 'select(.'$field'=="'$value'") | .PublicIP, .KeyPair, .Name, .ID' | xargs | |
} | |
awless_get_by_id(){ | |
awless_filter_by ID $1 | |
} | |
awless_get_by_publicip(){ | |
awless_filter_by PublicIP $1 | |
} | |
awless_get_by_privateip(){ | |
awless_filter_by PrivateIP $1 | |
} | |
awless_list_instances_by_name(){ | |
name=$1 | |
echo "$instances" | jq -r 'select(.[] | contains("'$name'")) | "\(.ID) \(.Name) \(.PublicIP)"' 2>/dev/null | |
} | |
awless_get_instance_id_by_name(){ | |
name=$1 | |
num=${2:-0} | |
echo "$instances" | jq 'select(.[] | contains("'$name'"))' 2>/dev/null | jq -s . | jq -r .[$num].ID | |
} | |
# Common code | |
instances=$(get_running_instances) | |
# This is a instance ID | |
if echo $host | grep -e "^i-" -q; then | |
read -r i_ip i_key i_name i_id <<<$(get_by_id $host) | |
# Or an IP address | |
elif echo $host | grep -P "^([0-9]+\.){3}[0-9]+" -q; then | |
read -r i_ip i_key i_name i_id <<<$(get_by_publicip $host) | |
[ "$i_ip" ] || read -r i_ip i_key i_name i_id <<<$(get_by_privateip $host) | |
# or a DNS name that resolves | |
elif [ "$(dig +short $host)" ]; then | |
hostIP=$(dig +short $host) | |
read -r i_ip i_key i_name i_id <<<$(get_by_publicip $hostIP) | |
# Everything else should be an instance name | |
elif [ "$listonly" == "true" ]; then | |
list_instances_by_name $host | |
exit 0 | |
else | |
desired_num_instance_id=$(get_instance_id_by_name $host $hostnum) | |
read -r i_ip i_key i_name i_id <<<$(get_by_id $desired_num_instance_id) | |
fi | |
# Disable strict host key checking if needed | |
[ "$ssh_strict" == "false" ] && ssh_opts="$ssh_opts -o StrictHostKeyChecking=false" | |
if [ "$i_ip" ]; then | |
echo -e "ec2ssh to $i_id $i_name $i_ip\n" >&2 | |
[ "$listonly" == "true" ] && exit 0 | |
[ "$add_route" == "true" ] && add_route $i_ip | |
$debug ssh $ssh_opts -i $keypath/$i_key $username@$i_ip "$@" | |
else | |
echo "ERROR. Host '$host' not found" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment