Skip to content

Instantly share code, notes, and snippets.

@mankins
Created January 20, 2025 15:16
Show Gist options
  • Save mankins/dd085823dd5e7aa717ecf9ba3e65a01f to your computer and use it in GitHub Desktop.
Save mankins/dd085823dd5e7aa717ecf9ba3e65a01f to your computer and use it in GitHub Desktop.
jump box ssh
#!/bin/bash
#set -x
# If there's a proxy host set in the environment, pull it in
[ -n $FTAWS_PROXY_HOST ] && PROXYHOST=$FTAWS_PROXY_HOST
# Private is the 'usual' way, subject to override in a few places below. If any code below selects public, then we go with the public address.
PROXYTOIPTYPE="-r"
while getopts "hi:n:R:k:fp:q1vV:x" flag
do
case "$flag" in
h)
echo "SSH to an instance using instance name or ID rather than the IP address"
echo "Usage: $(basename $0) [-h] [-v] [-f] [-i <instance_id_pattern> | -n <instance_name_pattern> ] [-R <region>] [-k <keyfile>] [-p <proxyhost>] [-q] [-x] [\"command\"]"
echo " [-h] display this help"
echo " [-i] <instance_id_pattern> ssh to the instance(s) with this ID or matching this pattern. Do not use with -n."
echo " [-n] <instance_name_pattern> ssh to the instance(s) with this name or matching this pattern. Do not use with -i."
echo " [-R] <region> work on instance(s) in <region>. If omitted, use the default region. Region is, e.g. 'us-east-1'"
echo " [-v] verbose - print instance info when connecting"
echo " [-V <n>] really verbose - <n> may be '1', '2', or '3'. Calls ssh with -v, -vv, or -vvv based on <n>"
echo " [-k] </path/to/privatekey> use this key to login (same as -i in ssh)"
echo " [-f] Forward Agent - use my credentials transitively for subsequent authentication from the host"
echo " [-p] <proxy-through-this-host> (dns hostname, not instance name) to a host in the same region"
echo " [-q] if proxying (FTAWS_PROXY_HOST set, or -p) proxy to the PUBLIC address of the target, not the private address"
echo " [-x] connect directly, even if ia proxy host is set in my environment"
echo " [-1] if instance_name_pattern matches more than one host, operate only on the first in the list"
echo " Useful for connecting to 'any' instance whose name matches a pattern:"
echo " $ ftaws-ssh -1 -n prod-web-402-* connects to the first instance matching the pattern"
echo " If -1 is not used and instance_name_pattern matches more than one instance, then each will be connected in turn."
echo " [\"command\"] run remote command"
echo
echo "If you always use one proxy host, export FTAWS_PROXY_HOST and this script will automatically use it (no need for -p)"
echo "Add to your login script:"
echo " export FTAWS_PROXY_HOST=<hostname> where <hostname> is the DNS name of the proxy"
echo "If FTAWS_PROXY_HOST is set and '-p <hostname>' appears on the command line, -p takes precedence"
echo
exit 1
;;
i)
INST="-i ${OPTARG}"
;;
n)
INST="-n ${OPTARG}"
;;
R)
REGION="${OPTARG}"
;;
f)
FORWARDAGENT="-o ForwardAgent=yes"
;;
k)
KEYFILE="-i ${OPTARG}"
;;
p)
PROXYHOST="${OPTARG}"
;;
q)
PROXYTOIPTYPE="-u"
;;
1)
FIRSTONLY="-1"
;;
v)
VERBOSE="1"
;;
V)
VERBOSE_SSH="${OPTARG}"
;;
x)
NOPROXY="1"
;;
esac
done
# non-labeled args slide over to $1...
shift $(($OPTIND - 1))
if [ -z "$INST" ]
then
echo "Must specify either -n <instance_name_pattern> or -i <instance_id_pattern>"
exit 1
fi
# Set up the verbose-call string for ssh if -V was set
if [ -n "$VERBOSE_SSH" ]
then
VERBOSE_SSH_STRING="-"
while [ $VERBOSE_SSH -gt 0 ]
do
VERBOSE_SSH_STRING+="v"
((VERBOSE_SSH--))
done
fi
# Auto-detect a need to use the target's public IP address (proxy gateway and target are in different regions)
if [ -n "$FTAWS_PROXY_HOST_REGION" ]
then
if [ -n "$REGION" ]
then
# An explicitly-set region (-R <region>) overrides any region settings from the environment
# If an explicitly-set region is not the same as that of the proxy host, use the target's public address
[ "$REGION" == "$FTAWS_PROXY_HOST_REGION" ] || PROXYTOIPTYPE="-u"
# and prefix a -R to make REGION easy to pass to ftaws-get-ip below
REGION="-R $REGION"
else
# Region was not explicitly set. Check the region we're working in by default -- if not the smae
# as the proxy host, use the target's public address
echo "$EC2_URL" | grep "$FTAWS_PROXY_HOST_REGION" > /dev/null
[ $? -eq 0 ] || PROXYTOIPTYPE="-u"
fi
fi
# if no proxy host is set, we are connecting directly. get the public IP
if [ -z "$PROXYHOST" -o -n "$NOPROXY" ]
then
IP_LIST=$(ftaws-get-ip $FIRSTONLY $REGION -u ${INST})
if [ -z "$IP_LIST" ]
then
echo "Instance not found: $INST"
exit 1
fi
for IP in $IP_LIST
do
[ -z "$VERBOSE" ] || echo "$(ftaws-get-name $REGION $IP)"
ssh $VERBOSE_SSH_STRING -t -o CheckHostIP=no -o StrictHostKeyChecking=no -o ConnectTimeout=30 $FORWARDAGENT ec2-user@${IP} ${KEYFILE} "${@}"
done
# otherwise if a proxy host is set, connect to the proxy host's public ip, then to either the public or private IP of the true target
# depending on whether it is in the same region as the proxy host (see the Auto-Detect section above for enlightenment)
else
# OpenSSH pre-version 5.4: ssh ec2-user@INTERNALIP -o "ProxyCommand ssh ec2-user@$PROXYHOST nc %h %p"
# OpenSSH 5.4 and later: ssh ec2-user@INTERNALIP -o "ProxyCommand ssh -W %h:%p ec2-user@$PROXYHOST"
# Versions 5.4 and later have netcat built in - so it's not necessary to call it separately
# That's preferred, but even OS/X 10.6 has a pre-5.4 OpenSSH, so for compatibility we still use the old way
IP_LIST=$(ftaws-get-ip $FIRSTONLY $REGION $PROXYTOIPTYPE ${INST})
if [ -z "$IP_LIST" ]
then
echo "Instance not found: $INST"
exit 1
fi
for IP in $IP_LIST
do
[ -z "$VERBOSE" ] || echo "$(ftaws-get-name $REGION $IP)"
ssh $VERBOSE_SSH_STRING -t -t ec2-user@${IP} ${KEYFILE} -o CheckHostIP=no -o StrictHostKeyChecking=no -o ConnectTimeout=30 $FORWARDAGENT -o "ProxyCommand ssh ec2-user@$PROXYHOST nc %h %p" "${@}"
done
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment