SSH over AWS SSM
There is a saying that something is more than sum of it’s parts, meaning it is the specific combination of things that makes it useful or valuable. But it can also be that one those parts is especially useful on it’s own too.
I did post earlier how you can (and should) get rid of bad habbit of using bastion hosts.
The Essense of those can be summarized into one-liner in
Host i-*.* mi-*.* ProxyCommand bash -c "aws ssm start-session --target $(echo %h|/usr/bin/cut -d'.' -f1) --region $(echo %h|/usr/bin/cut -d'.' -f2) --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
Let’s dissect above letter by letter
Host i-*.* mi-*.*
This applies following configuration when remote hostname matches one of the patterns.
i-* is for regular
EC2 instances and
mi-* will match for any managed instances if you have some.
Remember you can manage also non-EC2 VMs from other clouds or data center with SSM, and the same trick works for them too.
ProxyCommand bash -c "aws ssm start-session --target $(echo %h|cut -d'.' -f1) --region $(echo %h|/usr/bin/cut -d'.' -f2) --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
ProxyCommand is what ssh will run to open a connection to target host. Command can be almost anything as
long as it reads from stdin and writes to stdout. Here you will be using
aws ssm start-session to
open a pipe to remote host. Interesting part is how arguments of
start-session are constructed.
---target $(echo %h|/usr/bin/cut -d'.' -f1)
echo %h will send the remote hostname you specified on command line, and it will be
the first dot (.) leaving just the instance ID of it.
--region $(echo %h|/usr/bin/cut -d'.' -f2)
Using the same way the remaining part after the first dot (.) is extracted and passed as region to aws-cli.
Calling your hosts by
InstanceID.Region is just a clever way to make this work for multiple regions
without you having to change
AWS_DEFAULT_REGION environment variable to jump from one region to another.
Another small but important detail is calling
cut with full path. Leaving the path off could cause
problems when ProxyCommand is run with a shell that doesn’t it’s PATH set properly. This is also a bit
of added security so you can be sure what commands are run.
And finally just another parameter substitution where
%p is replaced with port number of remote host.
Please refer to manual for complete list of configuration options in
.ssh/config and tokens
Now you can, not just
ssh to instance without having a network connectivity between your laptop and VPC, but also use
scp and other ssh-tools. This has proven itself extermely useful during ad-hoc troubleshooting for clients I don’t
work with on daily basis. All I need is access to AWS API with key/secret/token, instance-id and region.
% ssh email@example.com Last login: Wed Dec 30 08:23:41 2020 from localhost __| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ [username@ip-10-0-0-91 ~]$
I learned this valuable one-liner from Jim Lamb’s blog.
Edit 19/10/2022; AWS blog has a more visual version of the same use-case with EC2 Instance Connect deploying temporary SSH keys