AWS Session Manager - Zero Trust Access

March 15, 2020 0 Comments

When working with AWS, there are plenty of features that make your life easier, but it's rare to find a feature that feels like magic...

Before we dive into the magic, what's the problem we're trying to solve? When working with servers anywhere, usually there needs to be some sort of remote access to SSH or RDP and install/troubleshoot things as needed. Worst case, your server has a public IP with port 22 (SSH) open to the world, which means theoretically anyone, anywhere in the world could break in. As you get more advanced, you setup VPN tunnels or bastion hosts to secure your remote access. This can increase in complexity very quickly with multiple VPC's across multiple regions, multipied by each AWS account. And with the rise in "Zero Trust" networking, how do you securely provide access without blindly trusting network CIDR's?

Enter AWS Systems Manager Session Manager. While not a very magical name, it does provide a magical experience. Session Manager gives you remote access to your servers without opening any ports in security groups, building any VPN tunnels, or using bastion hosts. All access is based on IAM permissions, and sessions are proxied by AWS Systems Manager. You can either use the AWS Console for web access, or the AWS CLI for a native "terminal" experience.

What are the requirements?
The official documentation has the most detail, but the short answer is:

  1. Verify SSM agent is running on your EC2 instances with an Instance Role that gives access to Systems Manager
  2. If you're using a local terminal:
    a. Verify AWS CLI 1.16.12 or later is installed
    b. Install the Session Manager Plugin for AWS CLI

Once the requirements are met, you can view your managed instances by going to Systems Manager -> Managed Instances in the AWS Console. You can easily start a web-based session by clicking an Instance and then clicking Actions -> Start Session. The same thing can be accomplished from the EC2 console by clicking your instance and then Connect -> Connection Method: Session Manager. While this feels similar to other tools (like a VMware console), the real magic is using the terminal on your local computer.

You can start a remote "SSH" style session with your instances that have zero inbound access with this command:

$ aws ssm start-session --target instance_id

At this point, you have SSH access to your instance, and can go through all your normal installation or troubleshooting steps. The first time you do this feels like magic, as you realize all the time you no longer need to spend with VPN tunnels, bastion hosts, and opening up security groups for remote access.

But wait, there's more! Not only can you initiate remote access sessions for SSH or Powershell, but SSM can also do port-forwarding from your local computer to the remote server! Want to see what a particular web-server is showing on port 80? Just forward a random local port (ex. 9999) to your web-server port 80, and then navigate to http://localhost:9999 in your web-browser. How about Windows RDP access? Session manager only supports SSH or Powershell for remote sessions, but with the port-forwarding feature, we can also get remote RDP access:

$ aws ssm start-session --target instance_id --document-name AWS-StartPortForwardingSession --parameters portNumber="3389",localPortNumber="33389"

Since the "localPortNumber" is set to 33389 above, you would just RDP to 127.0.0.1:33389 to port-forward to your remote instance.

Ok, at this point AWS has provided zero trust remote access, but remembering the AWS CLI SSM commands (especially port-forwarding) aren't the most intuitive. Also, getting the EC2 instance id requires going back and forth between your terminal the AWS web console. I decided to write a Python script that abstracts some of complexity while making it easy to start remote sessions and port-fowarding.

I've called this script AWS Remote: https://github.com/dkuchenski/aws-remote

Some of the main features of AWS Remote:

  • Listing all EC2 instance ids, important attributes, and SSM management status
  • Start remote sessions via instance id or instance name
  • Friendly port-forward syntax via instance id or instance name

So instead of remembering the AWS CLI syntax and finding instance id's, you can do this:

$ aws-remote session instance2-example.domain.com

or

$ aws-remote port-forward 8080 80 instance2-example.domain.com

Note: The instance "name" is referencing the Name tag of the instance

This script uses a combination of the Python Boto3 SDK and the AWS CLI to get information from AWS and start sessions based on your parameters. This is also the first time I've used Click to build the command line interface. Click is great for building easy to use CLI's, and therefore you can use --help at any point to see what your available options are. I've also mimicked the AWS CLI --profile and --region options for a familiar setup.

$ aws-remote --help
Usage: aws-remote [OPTIONS] COMMAND [ARGS]...

  AWS Remote is a simple, command line tool to view and interact with AWS
  instances via SSM. Requires the AWS CLI and Session Manager Plugin to be
  installed locally.

Options:
  --profile TEXT  Specify AWS profile
  --region TEXT   Specify AWS region
  --help          Show this message and exit.

Commands:
  list          List EC2 instances and SSM management status
  port-forward  Start SSM port forward to instance id/name
  session       Start SSM session with instance id/name

I'm still figuring out the best way to distribute scripts like this, but for now there are a couple installation steps that can be found here: https://github.com/dkuchenski/aws-remote/blob/master/README.md

Hope AWS Remote is a useful tool, and if you have any feedback, please let me know!




Amazon Blog about Session Manager:
https://aws.amazon.com/blogs/aws/new-session-manager/

References for using Click in a Python CLI:
https://dbader.org/blog/mastering-click-advanced-python-command-line-apps
https://stackoverflow.com/questions/23626972/how-do-i-pass-variables-to-other-methods-using-pythons-click-command-line-inte