Skip to content

Instantly share code, notes, and snippets.

@pdehlke
Created February 25, 2025 14:36
Show Gist options
  • Save pdehlke/182974a79623b91c08b41a501a230c36 to your computer and use it in GitHub Desktop.
Save pdehlke/182974a79623b91c08b41a501a230c36 to your computer and use it in GitHub Desktop.
Use https://www.granted.dev/ to manage aws credentials. awssh and ssh-ssm.sh to run ssh over ssm without a vpn. Instructions are in ssh-ssm.sh
#!/usr/bin/env zsh
set -o pipefail -o errexit
die() {
echo "$1" >&2
exit 1
}
[[ -z ${AWS_PROFILE} ]] && die "[FATAL]: no AWS_PROFILE set. Assume an indentity please."
aws sts get-caller-identity >/dev/null 2>&1 || die "[FATAL]: You do not seem to have a valid AWS session credential"
# If we're using zsh4humans like God intended, use the builtins for ssh teleportation
[[ ! -z $_Z4H_EXE ]] && SSH_PRE='z4h'
echo "finding instance-id for ${1}"
if [[ $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
INSTANCE=$(aws ec2 describe-network-interfaces --filter Name=private-ip-address,Values=${1} --query 'NetworkInterfaces[].Attachment[].InstanceId' --output text)
else
INSTANCE_IP=$(dig +short ${1})
[[ -z ${INSTANCE_IP} ]] && die "[FATAL]: could not find an IP address for ${1}"
INSTANCE=$(aws ec2 describe-instances --filter Name=private-ip-address,Values=${INSTANCE_IP} --query 'Reservations[].Instances[].InstanceId' --output text)
if [[ -z $INSTANCE ]]; then
INSTANCE=$(aws ec2 describe-network-interfaces --filter Name=private-ip-address,Values=${INSTANCE_IP} --query 'NetworkInterfaces[].Attachment[].InstanceId' --output text)
fi
fi
[[ -z ${INSTANCE} ]] && die "[FATAL]: could not find instance-id for ${1}"
echo "connecting to $INSTANCE"
${SSH_PRE} ssh ${INSTANCE} || die "[FATAL]: failed to ssh to instance ${INSTANCE}, identified by ${1}"
#!/usr/bin/env bash
#
# Use ssm to start an ssh session on an ec2 instance using a short-lived temporary
# key injected into the instance metadata. No long term ssh keys are used or needed.
#
# You should use this with a block in your .ssh/config that looks roughly like this:
#
# Match host i-*
# User pete
# ProxyCommand ssh-ssm.sh %h %r
# IdentityFile ~/.ssh/ssm-ssh-tmp
# StrictHostKeyChecking no
# PasswordAuthentication no
# KbdInteractiveAuthentication no
# ChallengeResponseAuthentication no
# ControlPath ~/.ssh/master-%r@%h:%p
# ControlMaster auto
# ConnectTimeout 10
# ServerAliveInterval 45
# AddKeysToAgent yes
# HostKeyAlgorithms ssh-ed25519
#
# See also the awssh script, which works out an instance ID based on either hostname
# or ip address and calls ssh with the appropriate target, which invokes this script
#
# set -x
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -o nounset -o pipefail -o errexit
function main {
local ssh_pubkey ssm_cmd
local ssh_authkeys='.ssh/authorized_keys'
ssh_dir=~/.ssh
checks "$@" && ssh_pubkey=$(ssh-add -L 2>/dev/null | head -1) || mktmpkey
ssm_cmd=$(
cat <<EOF
"u=\$(getent passwd ${2}) && x=\$(echo \$u |cut -d: -f6) || exit 1
install -d -m700 -o${2} \${x}/.ssh; grep '${ssh_pubkey}' \${x}/${ssh_authkeys} && exit 1
printf '${ssh_pubkey}'|tee -a \${x}/${ssh_authkeys} && sleep 15
sed -i s,'${ssh_pubkey}',, \${x}/${ssh_authkeys}"
EOF
)
# put our public key on the remote server
aws ssm send-command \
--instance-ids "$1" \
--document-name "AWS-RunShellScript" \
--parameters commands="${ssm_cmd}" \
--comment "temporary ssm ssh access" #--debug
# start ssh session over ssm
aws ssm start-session --document-name AWS-StartSSHSession --target "$1" #--debug
}
function checks {
[[ $# -ne 2 ]] && die "Usage: ${0##*/} <instance-id> <ssh user>"
[[ ! $1 =~ ^i-([0-9a-f]{8,})$ ]] && die "ERROR: invalid instance-id"
if [[ $(basename -- $(ps -o comm= -p $PPID)) != "ssh" ]]; then
ssh -o IdentityFile="~/.ssh/ssm-ssh-tmp" -o ProxyCommand="${0} ${1} ${2}" "${2}@${1}"
exit 0
fi
pr="$(grep -sl --exclude='*tool-env' "$1" "${ssh_dir}"/ssmtool-*)" &&
export AWS_PROFILE=${AWS_PROFILE:-${pr##*ssmtool-}}
}
function mktmpkey {
trap cleanup EXIT
ssh-keygen -t ed25519 -N '' -f "${ssh_dir}"/ssm-ssh-tmp -C ssm-ssh-session
ssh_pubkey="$(<"${ssh_dir}"/ssm-ssh-tmp.pub)"
}
function cleanup { rm -f "${ssh_dir}"/ssm-ssh-tmp{,.pub}; }
function die {
echo "[${0##*/}] $*" >&2
exit 1
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment