Connect to your EC2 instance using SSH the modern way
Tags: aws, cloud, security
Published: 2022-02-02 11:26:42

Did you know that establishing an SSH connection with an EC2 instance is possible without configuring a key pair and allowing inbound traffic on port 22? How is that possible? The secret is a combination of EC2 Instance Connect and Systems Manager (SSM). When following this article, connecting with an EC2 instance is as simple as typing `ssh i-059499e6abc8fbe6b` into your terminal.

First of all, the following video demonstrates how to establish an SSH connection with an EC2 instance by using EC2 Instance Connect and Systems Manager.

{% youtube w-yVPzSbb0c %}

The following diagram explains the approach in more detail.

* The user sends her public key to EC2 Instance Connect using the AWS CLI.
* EC2 Instance connect pushes the key to the EC2 instance. The key remains for 60 seconds.
* An SSM agent running on the EC2 instance establishes a bidirectional channel with the SSM backend.
* The user establishes an SSH connection through a Websocket between Terminal and SSM.
* Authentication and authorization for the user and the SSM agent is IAM's job.

![Establishing an SSH connection with an EC2 instance by using EC2 Instance Connect and Systems Manager](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1xn991kc2ktc7aviru2o.png)

How do you make this approach happen on your local machine and EC2 instances?

* Make sure the SSM agent is running on your EC2 instances - which is already the case for Amazon Linux and Amazon Linux 2.
* Double check that the SSM agent running on your machines can connect with the SSM API through an internet gateway, NAT gateway, or VPC endpoint.
* Attach an IAM role - granting the SSM agent access to the SSM API - to each EC2 instance to
* Install the AWS CLI and the session manager plugin on your local machine.
* Configure your SSH client to use EC2 Instance Connect and Systems Manager to establish a tunnel for SSH connections.

> Are you confused about the different options to connect by using EC2 Instance Connect and Systems Manager? Check out Petri's comparision: [EC2 Instance Connect vs. SSM Session Manager](https://carriagereturn.nl/aws/ec2/ssh/connect/ssm/2019/07/26/connect.html)

## IAM role required by SSM agent

As mentioned before, the SSM agent is running on most EC2 instances already. That's because the agent is bundled into Amazon Linux, Amazon Linux 2, SUSE Linux Enterprise Server (12 and 15), and Ubuntu Server (16.04, 18.04, and 20.04) by default. 

> Learn how to [Manually install SSM Agent on EC2 instances for Linux](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-manual-agent-install.html) from the AWS documentation.

However, the SSM agent requires an IAM role attached to the EC2 instance granting access to the SSM API. That's not a default, so you probably need to create a new IAM role or add a policy to existing roles.

You can either use the predefined policy `AmazonSSMManagedInstanceCore` (`arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore`) managed by AWS. Or create your own managed or in-line policy with the following contents.

```
{
 "Version": "2012-10-17",
 "Statement": [
 {
 "Effect": "Allow",
 "Action": [
 "ssmmessages:*",
 "ec2messages:*",
 "ssm:UpdateInstanceInformation"
 ],
 "Resource": "*"
 }
 ]
}
```

## Install the AWS CLI and session manager plugin

You will use the AWS Command Line Interface (CLI) to push your public key via EC2 Instance Connect and establish a tunnel for your SSH connection with the EC2 instance.

Therefore, make sure to install the AWS CLI on your local machine. Besides that, you need to install the session manager plugin.

* [Installing or updating the latest version of the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
* [Install the Session Manager plugin for the AWS CLI](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)

I prefer `brew` to install the AWS CLI and the session manager plugin on macOS.

```
brew install awscli session-manager-plugin
```

## Configuring your SSH client

Next, you need to configure your SSH client. To do so, edit the `~/.ssh/config` file on your local machine. Please add the following snippet configuring connections for all hosts, starting with `i-` at the end of the file. Do not forget to replace `$PRIVATE_KEY` and `$PUBLIC_KEY` with the path to your private and public key.

```
# SSH over Session Manager
host i-*
 IdentityFile $PRIVATE_KEY
 User ec2-user
 ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://$PUBLIC_KEY' --availability-zone '$(aws ec2 describe-instances --instance-ids %h --query 'Reservations[0].Instances[0].Placement.AvailabilityZone' --output text)' && aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
```

For me, the snippet looks as follows.

```
# SSH over Session Manager
host i-*
 IdentityFile ~/.ssh/id_ed25519
 User ec2-user
 ProxyCommand sh -c "aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_ed25519.pub' --availability-zone '$(aws ec2 describe-instances --instance-ids %h --query 'Reservations[0].Instances[0].Placement.AvailabilityZone' --output text)' && aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
```

The `ProxyCommand` contains a one-liner that I'd like to explain in more detail.

First, we need to find out the availability zone the instance is running in. The command `aws ec2 describe-instances` returns the necessary information. Please note that `%h` will be replaced with the host, for example, `i-059499e6abc8fbe6b`.

```
aws ec2 describe-instances --instance-ids %h --query 'Reservations[0].Instances[0].Placement.AvailabilityZone' --output text
```

Next, you need to push your public key to the EC2 instance. That's why you need to execute the `aws ssm start-session` command.

```
aws ec2-instance-connect send-ssh-public-key --instance-id %h --instance-os-user %r --ssh-public-key 'file://~/.ssh/id_ed25519.pub' --availability-zone '$(...)'
```

Last but not least, you need to establish the SSH session through a WebSocket connection. That's the job of the `aws ssm start-session` command.

```
aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'
```

## Connect to your EC2 instance using SSH

You are ready to connect with your EC2 instance using SSH. All you need to do is type `ssh` followed by an EC2 instance ID into your terminal.

```
ssh i-059499e6abc8fbe6b
```

By the way, you can even copy files with `scp`.

```
ssh example.txt i-059499e6abc8fbe6b:/tmp/
```

That's it. I hope you enjoy this approach to connect to your EC2 instances using SSH as much as I do.

*Did you run into any issues while following my instructions? Do you love the approach to connect with your EC2 instances? Please let me know!*