Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save twratl/aa93d89b2f92a636af6ffdc810d927fe to your computer and use it in GitHub Desktop.
Save twratl/aa93d89b2f92a636af6ffdc810d927fe to your computer and use it in GitHub Desktop.
AWS - SSH Over Session Manager to EC2 Instance Using EC2 Instance Connect

NOTE: these instructions are for Mac/Linux - Windows users can perhaps adapt this as required.

Step 1: Create Executable Script

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

Step 2: Add Match Directive to SSH Config

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*

Step 3: Add Host Directive to SSH Config

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

Step 4: Establish the SSH Connection

Now you can SSH as "normal".

ssh bastion

The first time you connect you will have to accept the server fingerprint as normal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment