Skip to content

Instantly share code, notes, and snippets.

@Maks3w
Forked from skorfmann/_AWS_SSM_SSH_Tunnel.md
Last active February 26, 2024 20:25
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Maks3w/de72b0160d5e6af958adc42eab014624 to your computer and use it in GitHub Desktop.
Save Maks3w/de72b0160d5e6af958adc42eab014624 to your computer and use it in GitHub Desktop.

Both things have been introduced recently, and let you access even private ec2 instances

  1. Without VPN
  2. No open SSH port
  3. Authentication / Authorization is fully delegated to IAM
# Assumes valid AWS Credentials in ENV
# Important. Always set the username
ssh ec2-user@i-002afb820244e392f

What this will do (through the aws-proxy script below):

  • Generate a single use ssh key
  • Push the generated publich key to AWS for the given user of the provided ec2 instance id
  • Create a tunnel through Session Manager
  • Establish an SSH session

The host has to be configured to run:

  • SSM Agent
  • ec2-instance-connect

Locally, you'll have to have a recent version of the AWS cli and the SSM plugin

#!/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=$3
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=$(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}"
echo "Connecting using SSM tunnel ..." >&2
# SSH over Session Manager and EC2 Instance Connect
# Example with User from command line
Match host i-*,mi-* exec "aws-proxy /tmp/aws-proxy.%h.%r %r %h"
# USER MUST BE ALWAYS SET IN COMMAND ARGUMENTS
# %r (user) is used earlier. Unless you opt for replace %r with your own fixed value (see the same example below)
# User ec2-user
IdentityFile /tmp/aws-proxy.%h.%r
ProxyCommand aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p
# Remove ephemeral key
PermitLocalCommand yes
LocalCommand rm /tmp/aws-proxy.%h.%r*
# Example with a fixed User (note there are many places where is needed to set)
Match host i-*,mi-* exec "aws-proxy /tmp/aws-proxy.%h.ec2-user ec2-user %h"
# Example with all (for simplicity) %r replaced with "ec2-user" (5 occurrences)
User ec2-user
IdentityFile /tmp/aws-proxy.%h.ec2-user
ProxyCommand aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p
# Remove ephemeral key
PermitLocalCommand yes
LocalCommand rm /tmp/aws-proxy.%h.ec2-user*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment