NOTE: these instructions are for Mac/Linux - Windows users can perhaps adapt this as required.
Create an executable script called aws-ssh-proxy
in a location in your path (or add a new location to your path).
#!/usr/bin/env bash
set -o nounset
set -o errexit
ONE_TIME_KEY_FILE_NAME=$1
ONE_TIME_PUB_FILE_NAME="${ONE_TIME_KEY_FILE_NAME}.pub"
USER=$2
HOSTNAME=$(echo $3 | cut -d . -f 1)
PROFILE=$(echo $3 | cut -d . -f 2)
echo "Generating Ephemeral SSH key ..." >&2
yes | ssh-keygen -t rsa -b 2048 -f "${ONE_TIME_KEY_FILE_NAME}" -N ''
echo "Pushing SSH public key to EC2 instance ..." >&2
INSTANCE_AZ=none
if [ "$HOSTNAME" = "$PROFILE" ]; then # if no profile was given, assume the user means that the AWS CLI will automatically figure out which credential source to use
INSTANCE_AZ=$(aws ec2 describe-instances --instance-ids "${HOSTNAME}" --query 'Reservations[*].Instances[*].Placement.AvailabilityZone' --output text)
aws ec2-instance-connect send-ssh-public-key \
--availability-zone "${INSTANCE_AZ}" \
--instance-id "${HOSTNAME}" \
--instance-os-user "${USER}" \
--ssh-public-key "file://${ONE_TIME_PUB_FILE_NAME}"
else
INSTANCE_AZ=$(aws ec2 describe-instances --instance-ids "${HOSTNAME}" --query 'Reservations[*].Instances[*].Placement.AvailabilityZone' --output text --profile "$PROFILE")
aws ec2-instance-connect send-ssh-public-key \
--availability-zone "${INSTANCE_AZ}" \
--instance-id "${HOSTNAME}" \
--instance-os-user "${USER}" \
--ssh-public-key "file://${ONE_TIME_PUB_FILE_NAME}" \
--profile "$PROFILE"
fi
echo "Connecting using SSM tunnel ..." >&2
Edit ~/.ssh/config
and add the following Match
directive.
If you are using a different User
you can change it here. You can also add these commands to individual Host
directives instead if each EC2 instance has different users, configs, etc.
Match host i-*,mi-* exec "aws-ssh-proxy /tmp/aws-ssh-eic-ssm-key.%h.ssm-user ssm-user %h"
User ssm-user
IdentityFile /tmp/aws-ssh-eic-ssm-key.%h.ssm-user
ProxyCommand aws ssm start-session --profile $(echo %h | cut -d . -f 2) --target $(echo %h | cut -d . -f 1) --document-name AWS-StartSSHSession --parameters portNumber=%p
# Remove ephemeral key
PermitLocalCommand yes
LocalCommand rm /tmp/aws-ssh-eic-ssm-key.%h.ssm-user*
Edit ~/.ssh/config
and add 1 or more Host
directives, using the following format.
Only the HostName
is required. Add additional SSH config options as needed. A couple LocalForward
configs are provided
as reference so that you can tunnel connections over SSH.
Change bastion
to whatever is meaningful to you.
The HostName
is provided in the format <instance id>.<aws profile>
. The AWS profile should represent credentials that allow you to
connect to the provided instance id via Session Manager and EC2 Instance Connect.
Host bastion
HostName i-024xxxxxxxxxxex99.default
LocalForward 8080 10.0.0.6:8080
LocalForward 8443 internal.vpc.dns.name:443
Now you can SSH as "normal".
ssh bastion
The first time you connect you will have to accept the server fingerprint as normal.