Last active
October 20, 2022 01:07
-
-
Save rdkls/f997cdd2c0e95a6cd5bb1241ba8fd834 to your computer and use it in GitHub Desktop.
AWS SSM SSH ProxyCommand
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
#!/usr/bin/env bash | |
# | |
# Description | |
# Bootstrap SSH Session to an SSM-managed instance | |
# by temporarily adding a public SSH key available on the local machine (ssh-agent or in ~/.ssh) | |
# | |
# | |
# Installation | |
# | |
# First run your eye over this script to check for malicious code | |
# Then run this script without arguments to automatically perform all install steps on your client: | |
# | |
# curl -s https://gist.githubusercontent.com/rdkls/f997cdd2c0e95a6cd5bb1241ba8fd834/raw/aws-ssm-ec2-proxy-command.sh | bash | |
# | |
# It will: | |
# | |
# #1 Install the AWS CLI | |
# https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html | |
# | |
# #2 Install the Session Manager Plugin for the AWS CLI | |
# https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html | |
# | |
# #3 Install this script | |
# - Move this script to ~/.ssh/aws-ssm-ec2-proxy-command.sh | |
# - Make it executable (chmod +x ~/.ssh/aws-ssm-ec2-proxy-command.sh) | |
# | |
# #4 Update your SSH config to use this script as ProxyCommand when SSH'ing to EC2 instances: | |
# Host i-* mi-* ssm-jumphost | |
# ProxyCommand ~/.ssh/aws-ssm-ec2-proxy-command.sh %h %r %p | |
# | |
# | |
# Host Requirements | |
# | |
# #1 Ensure SSM Permissions of Target Instance Profile | |
# | |
# https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html | |
# | |
# #2 Ensure latest SSM Agent on Target Instance | |
# | |
# Is preinstalled on all amazon linux AMIs, however may needs to be updated | |
# yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm & service amazon-ssm-agent restart | |
# or | |
# aws ssm send-command --instance-ids i-xxxxxxxxxx --document-name AWS-UpdateSSMAgent | |
# | |
# | |
# Connect to ec2 instance | |
# | |
# ssh ec2-user@i-xxxxxxxxxx | |
# ssh -N -L 5432:myrds.cunh7nydpqk3.ap-southeast-2.rds.amazonaws.com:5432 ubuntu@i-xxjumpboxx | |
# | |
# | |
# TODO | |
# Possibly - replace the SSH key provisioning with ec2 instance connect | |
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-set-up.html | |
# Although 'neater' and using an official AWS Service, | |
# this does increase requirements to having EC2 instance connect installed (scripts + sshd config AuthorizedKeysCommand) | |
# And adding relevant IAM perms to the accessing role (ec2-instance-connect:SendSSHPublicKey) | |
# | |
################################################################################ | |
DEFAULT_SSH_PUBLIC_KEY_PATHS="${HOME}/.ssh/id_rsa.pub ${HOME}/.ssh/id_ed25519.pub" | |
SSH_PUBLIC_KEY_TIMEOUT=5 | |
SSH_USER_DEFAULT=ec2-user | |
SSH_PORT_DEFAULT=22 | |
THIS_SCRIPT_URL="https://gist.githubusercontent.com/rdkls/f997cdd2c0e95a6cd5bb1241ba8fd834/raw/aws-ssm-ec2-proxy-command.sh" | |
main() { | |
args=($@) | |
local cmd=${args[0]-install} | |
local install_location=${args[1]-~/.ssh/aws-ssm-ec2-proxy-command.sh} | |
local ec2_instance_id=${args[0]} | |
local ssh_user=${args[1]-$SSH_USER_DEFAULT} | |
local ssh_port=${args[2]-$SSH_PORT_DEFAULT} | |
usage=" | |
Usage:\n | |
aws-ssm-ec2-proxy-command.sh install [install-location (default ~/.ssh)]\n | |
aws-ssm-ec2-proxy-command.sh i-xxxxxxx [ssh-username] [ssh-port]\n | |
" | |
if [[ "install" == $cmd ]] ; then | |
echo | |
echo | |
install $install_location | |
exit 0 | |
else | |
if [[ -z $ec2_instance_id ]] ; then | |
echo -e $usage | |
exit 1 | |
fi | |
#cleanup | |
connect $ec2_instance_id $ssh_user $ssh_port | |
exit 0 | |
fi | |
} | |
install_aws_cli() { | |
if [[ -n `which aws` ]] ; then | |
return | |
fi | |
echo | |
echo "Installing AWS CLI ..." | |
if [[ -n `which python3` ]] ; then | |
sudo pip3 install --prefix=/usr/local awscli | |
elif [[ -n `which python` ]] ; then | |
sudo pip install --prefix=/usr/local awscli | |
else | |
echo "You need python installed!" | |
exit 1 | |
fi | |
echo | |
} | |
install_aws_cli_session_manager_plugin() { | |
if [[ -n `which session-manager-plugin` ]] ; then | |
return | |
fi | |
echo "Installing AWS CLI session-manager-plugin ..." | |
uname=`uname -a` | |
if [[ -n `echo $uname | grep Darwin` ]] ; then | |
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "/tmp/sessionmanager-bundle.zip" | |
unzip -d /tmp/ /tmp/sessionmanager-bundle.zip | |
sudo /tmp/sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin | |
rm /tmp/session-manager-plugin-bundle.zip | |
elif [[ -n `echo $uname | grep Ubuntu` ]] ; then | |
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb" -o "/tmp/session-manager-plugin.deb" | |
sudo dpkg -i /tmp/session-manager-plugin.deb | |
rm /tmp/session-manager-plugin.deb | |
else | |
echo "Don't know how to install session-manager-plugin for your system - please do so manually then try again. Refer here for instructions: https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html" | |
exit 1 | |
fi | |
} | |
cleanup() { | |
# Cleanup any stale running session managers - these may cause us to hang later when trying to connect | |
pkill session-manager-plugin | |
} | |
install() { | |
local install_location=$1 | |
install_aws_cli | |
install_aws_cli_session_manager_plugin | |
mkdir -p `dirname $install_location` | |
curl -s $THIS_SCRIPT_URL > $install_location | |
chmod +x $install_location | |
# Update ssh config, if needed | |
if [[ -z `grep 'Host i-\*' ~/.ssh/config` ]] ; then | |
echo "Updating ~/.ssh/config to use the script as ProxyCommand for 'ssh i-*'" | |
echo " | |
Host i-* mi-* ssm-jumphost | |
User ${SSH_USER_DEFAULT} | |
ProxyCommand ${install_location} %h %r %p | |
" >> ~/.ssh/config | |
fi | |
echo "Installed to ${install_location}" | |
} | |
get_ssh_public_key() { | |
# Try to get an public ssh key from 'ssh agent' | |
ssh_public_key="$(keys="$(ssh-add -L 2>/dev/null)" && echo $keys | head -1)" | |
if [[ -n "$ssh_public_key" ]]; then | |
ssh_public_key_source='ssh agent' | |
else | |
# Try read public ssh key from '${DEFAULT_SSH_PUBLIC_KEY_PATHS}' | |
for ssh_public_key_path in $DEFAULT_SSH_PUBLIC_KEY_PATHS; do | |
ssh_public_key="$([[ -e "${ssh_public_key_path}" ]] && cat "${ssh_public_key_path}")" | |
if [[ -n "$ssh_public_key" ]]; then | |
ssh_public_key_source="${ssh_public_key_path}" | |
fi | |
done | |
fi | |
# Try getting ANY ssh key in ~/.ssh | |
# If found - start ssh-agent and add it | |
if [[ -z "${ssh_public_key}" ]]; then | |
for ssh_public_key_path in $(ls ~/.ssh/*.pub 2>/dev/null); do | |
# Check we have (what looks like) the corresponding private key | |
ssh_private_key_path="$(dirname $ssh_public_key_path)/$(basename $ssh_public_key_path .pub)" | |
if [[ -e "$ssh_private_key_path" ]] ; then | |
ssh_public_key="$(cat ${ssh_public_key_path})" | |
ssh-agent | |
echo "Adding ${ssh_private_key_path} to ssh-agent ..." | |
ssh-add ${ssh_private_key_path} | |
break | |
fi | |
done | |
fi | |
if [[ -z "$ssh_public_key" ]]; then | |
echo "No ssh key present in ssh agent nor ~/.ssh/" | |
exit 1 | |
fi | |
echo $ssh_public_key | |
} | |
connect() { | |
local ec2_instance_id=$1 | |
local ssh_user=$2 | |
local ssh_port=$3 | |
local ssh_public_key=$(get_ssh_public_key) | |
aws ssm send-command \ | |
--instance-ids "${ec2_instance_id}" \ | |
--document-name 'AWS-RunShellScript' \ | |
--parameters commands="\" | |
sudo su | |
mkdir -p ~${ssh_user}/.ssh | |
chown -R ${ssh_user}:${ssh_user} ~${ssh_user}/.ssh | |
cd ~${ssh_user}/.ssh || exit 1 | |
grep -F '${ssh_public_key}' authorized_keys || echo '${ssh_public_key} ssm-session' >> authorized_keys | |
sleep ${SSH_PUBLIC_KEY_TIMEOUT} | |
grep -v -F '${ssh_public_key}' authorized_keys > .tmp.authorized_keys | |
mv .tmp.authorized_keys authorized_keys | |
\"" \ | |
--comment "grant ssh access for ${SSH_PUBLIC_KEY_TIMEOUT} seconds" | |
# Start SSM SSH session | |
aws ssm start-session \ | |
--target "${ec2_instance_id}" \ | |
--document-name "AWS-StartSSHSession" \ | |
--parameters "portNumber=${ssh_port}" | |
} | |
main "$@" | |
@rdkls I've release a simplified version of proxy command see https://gist.github.com/qoomon/fcf2c85194c55aee34b78ddcaa9e83a1
Nice work thanks @qoomon
@rdkls my gist is deprecated have a look at https://github.com/qoomon/aws-ssm-ec2-proxy-command
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@rdkls I've release a simplified version of proxy command see https://gist.github.com/qoomon/fcf2c85194c55aee34b78ddcaa9e83a1