sshuttle and AWS Systems Manager Session Manager

Overview

 

Airwalk was recently asked whether it would be possible to use sshuttle with Session Manager, a part of AWS Systems Manager, so I decided to find out.

What is sshuttle?

If you’re a network administrator or someone concerned with network security, you’re probably thinking this sounds terrible. If you’re an engineer, this probably sounds amazing. I have a foot in both camps.

What is AWS Systems Manager Session Manager?

Session Manager allows you to open a shell on your EC2 instances, either via the browser-based AWS Console or via the AWS CLI. While this sounds just like SSH, there are some great advantages:

  1. You do not need any firewall ports open or any bastion hosts. Session Manager only relies on your instance running the Systems Manager agent, a daemon that runs by default on Amazon Linux and is easily installed on other distributions.
  2. Access is controlled via IAM. You no longer have to manage SSH keys separately from your AWS policies. You can control who has access to which instances using IAM roles and policies. No more cleaning up users’ keys when they move on from your company.
  3. Access is logged to CloudTrail. Your audit trail is all in one place.

Session Manager examples

Starting a Session Manager session
Starting a Session Manager session
A Session Manager session via a web browser
A Session Manager session via a web browser

And here I am starting a Session Manager session from the AWS CLI in my terminal:

A Session Manager session via the AWS CLI
A Session Manager session via the AWS CLI

Making Session Manager a little friendlier

    host i-* mi-*
      ProxyCommand bash -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

…then you can connect to instances by typing something like this:

    ssh ec2-user@i-0456ac191f9f975ec

In case you were wondering, this works transparently for scp as well.

I should also mention that Session Manager can also be used to allow RDP connections to Windows instances, but I won’t discuss that here.

Not all plain sailing between regions

    export AWS_DEFAULT_REGION=eu-west-1

However, if you use resources in multiple regions, you’re going to have a problem and the default error messages aren’t very helpful:

    Airwalk-Jim-Lamb:~ Jim$ ssh ec2-user@i-0456ac191f9f975ec
    kex_exchange_identification: Connection closed by remote host

It’s only when you use ssh -v that you can see the error from the AWS CLI:

    [...]
    debug1: Local version string SSH-2.0-OpenSSH_8.1An error occurred (TargetNotConnected) when calling the StartSession operation: i-0456ac191f9f975eg is not connected.
    kex_exchange_identification: Connection closed by remote host

Even this isn’t super-helpful, but it’s telling us that SSM doesn’t have an agent connection to an instance with that ID, which should make you start thinking about whether that instance (in the current account and region) is the instance you really want to connect to.

Making SSH with transparent Session Manager region-aware

    host i-*.* mi-*.*
      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'"host i-* mi-*
      ProxyCommand bash -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

Now I can add a region suffix to my instance ID, like this:

    ssh ec2-user@i-0456ac191f9f975ec.eu-west-1

And when I don’t add the suffix, it will still fall back to using the standard ways of specifying a region to the AWS CLI, ie the AWS_DEFAULT_REGION environment variable or the value of region in the profile being used in your ~/.aws/config file.

Now I admit my config is a bit nasty, using subshells. If anyone has any better suggestions, please do let me know.

Finally, back to sshuttle

    sshuttle -r ec2-user@i-0456ac191f9f975ec.eu-west-1 192.168.9.0/24

Now I can connect to hosts within the remote network by specifying the IP address and port number.

    curl https://192.168.9.13/donaldwheresyourtroosers

If I choose to add --dns to my sshuttle invocation, I can resolve DNS from the remote network and specify remote hosts by name.

    sshuttle --dns -r ec2-user@i-0456ac191f9f975ec.eu-west-1 192.168.9.0/24

Closing thoughts