forked from ryanb/dotfiles
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ssh-ec2-connect
executable file
·158 lines (135 loc) · 4.55 KB
/
ssh-ec2-connect
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/bin/bash
#
# Connect to an EC2 instance running ec2-instance-connect via ssh.
#
set -eo pipefail
usage () {
cat <<EOSTR
ssh-ec2-connect [OPTIONS]
-i --instance-id=INSTANCE_ID EC2 Instance ID
-k --private-key=path/to/key SSH private key (optional)
-p --public-key=path/to/key SSH public key (optional)
-r --region=us-tirefire-1 AWS Region
-s --ssm Use AWS SSM for transport
--scp-local FILE Local file for SCP operation
--scp-remote PATH Remote path for SCP operation
-u --user=ssh-user SSH user
N.B. The arguments above _must_ use an '=' for long options, due to portability
issues with 'getopt'.
If a private key is specified but a public key is omitted, the public key is expected
to be in the same location as the private key but with a .pub extension.
Omitting a private key assumes the user has a SSH agent operating.
Environment variables can be set for default keys:
\$SSH_EC2_CONNECT_PRIVATE_KEY
\$SSH_EC2_CONNECT_PUBLIC_KEY
SSM Transport mode expects SSH to be able to handle EC2 instance ID's as hostnames,
e.g. 'ssh i-1234567890'. The SSM docs at:
https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html
Suggest the following in your ~/.ssh/config:
# SSH over Session Manager
Host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
EOSTR
}
verbose () {
if [ $VERBOSE -gt 0 ] ; then
echo $1
fi
}
INSTANCE_ID=""
PRIVATE_KEY="${SSH_EC2_CONNECT_PRIVATE_KEY}"
PUBLIC_KEY="${SSH_EC2_CONNECT_PUBLIC_KEY}"
SSH_OPTS="${SSH_OPTS}"
SSH_USER="ec2-user"
VERBOSE=0
SSM=0
SCP_LOCAL=""
SCP_REMOTE=""
set -u
# See: https://stackoverflow.com/a/28466267/845546
die() { echo "$*" >&2; exit 2; } # complain to STDERR and exit with error
needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$OPT option"; fi; }
while getopts i:k:p:r:su:vh-: OPT; do
if [ "$OPT" = "-" ]; then # long option: reformulate OPT and OPTARG
OPT="${OPTARG%%=*}" # extract long option name
OPTARG="${OPTARG#$OPT}" # extract long option argument (may be empty)
OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=`
fi
case "$OPT" in
i | instance-id)
needs_arg
INSTANCE_ID=$OPTARG ;;
k | private-key)
needs_arg
PRIVATE_KEY=$OPTARG ;;
p | public-key)
needs_arg
PUBLIC_KEY=$OPTARG ;;
r | region)
needs_arg
export AWS_DEFAULT_REGION=$OPTARG AWS_REGION=$OPTARG ;;
u | user)
needs_arg
SSH_USER=$OPTARG ;;
s | ssm)
SSM=1 ;;
scp-local)
needs_arg
SCP_LOCAL=$OPTARG ;;
scp-remote)
needs_arg
SCP_REMOTE=$OPTARG ;;
v | verbose)
set -x
SSH_OPTS="${SSH_OPTS} -v"
VERBOSE=1 ;;
h | help)
usage ; exit ;;
??* )
die "Illegal option --$OPT" ;; # bad long option
? )
exit 2 ;; # bad short option
esac
done
shift $((OPTIND-1)) # remove parsed options and args from $@ list
if [ "${INSTANCE_ID}" = "" ] ; then
echo "No instance id specified!"
exit 2
fi
if [ ! "${PRIVATE_KEY}" = "" ] ; then
SSH_OPTS="${SSH_OPTS} -i ${PRIVATE_KEY}"
if [ "${PUBLIC_KEY}" = "" ] ; then
PUBLIC_KEY="${PRIVATE_KEY}.pub"
fi
if [ ! -f $PRIVATE_KEY ] ; then
echo "SSH private key not found at ${PRIVATE_KEY}"
exit 2
fi
if [ ! -f ${PUBLIC_KEY} ] ; then
echo "SSH public key not found at ${PUBLIC_KEY}"
exit 2
fi
fi
verbose "Fetching metadata..."
INSTANCE_META=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID} --query='Reservations[].Instances[0]')
if [ "${INSTANCE_META}" = "[]" ] ; then
echo "Failed to fetch metadata for ${INSTANCE_ID}. Bad instance id?"
exit 2
fi
AZ=$(echo $INSTANCE_META | jq -r .[].Placement.AvailabilityZone)
if [ "$SSM" -eq 0 ] ; then
IP=$(echo $INSTANCE_META | jq -r .[].PublicIpAddress)
else
# SSM assumes we can ssh to instance id's b/c of their config recommendation at:
# https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started.html
IP=${INSTANCE_ID}
fi
verbose "Sending public key ${PUBLIC_KEY}..."
aws ec2-instance-connect send-ssh-public-key --instance-id ${INSTANCE_ID} --availability-zone ${AZ} --instance-os-user $SSH_USER --ssh-public-key file://${PUBLIC_KEY} > /dev/null
if [ "$SCP_LOCAL" != "" -a "$SCP_REMOTE" != "" ] ; then
verbose "Copying..."
scp ${SSH_OPTS} $SCP_LOCAL ${SSH_USER}@${IP}:${SCP_REMOTE} "$@"
else
verbose "Connecting..."
exec ssh ${SSH_OPTS} ${SSH_USER}@${IP} "$@"
fi