How to log in to an EC2 instance without opening up ports?
1. Why Session Manager?
It’s widely known (for hackers as well) that port 22
is used to SSH into Linux EC2 instances (and 3389
for Windows RDP). Although changing the default port to something else and taking additional steps increase the level of protection against port attacks, what could be a better protection than not opening any port at all?
This is what Session Manager allows developers and system administrators to do.
Session Manager is part of a service called Systems Manager, which allows developers to manage operational tasks across their AWS infrastructure.
Below I’ll describe how to log in to an EC2 instance without having port 22
(or any other port) open.
2. Conditions
If you decide to follow along, you’ll need to have an EC2 instance running (free-tier t2.micro is fine), have a key pair downloaded on your machine and have the AWS CLI installed. So if you don’t have any running instances, go and quickly launch one using a Linux2 AMI.
3. Let’s do it
First, logging into the instance through Session Manager only works if the EC2 instance has the Systems Manager Agent (SSM) installed.
3.1. SSM
The current AWS AMIs have the SSM installed on them by default, so you don’t have to worry about that now. If you want to use Session Manager on older instances, it’s possible that SSM is not installed. In this case, it needs to be manually sorted out, so follow this tutorial before moving on.
3.2. Give permissions to Session Manager
In AWS, everything is built around permissions, which is a good thing because it increases security. As such, Session Manager has to have permissions to access the EC2 instance - otherwise how could we log in?
So we need to create a role, add it to an instance profile and then attach the instance profile to the instance.
Create the instance profile. An instance profile is sort of a container that holds roles for EC2 instances. Let’s create one called SessionManagerInstanceProfile
first with the following CLI command:
aws iam create-instance-profile --instance-profile-name SessionManagerInstanceProfile
Instance profiles (along with roles and policies) are part of IAM, which is one of the most important services in AWS.
Create the role. It’s best practice to create a role with the necessary permissions and attach it to the EC2 instance instead of adding user credentials to it. Roles will use temporary credentials to access the relevant services.
We need to create a trust policy defining which service is allowed to assume the role (it’s EC2), and a permission policy, which contains the permissions (both are in JSON format) for the service.
If the CLI is used, it’s easier to create these policies in the editor, then save them in the project folder and refer to them in the terminal.
The trust policy in a file called trust-policy.json
can look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
The ec2.amazonaws.com
in the Service
array refers to the service assuming the role, in this case this service is EC2.
The permissions can be placed in a file called session-manager-policy.json
:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:UpdateInstanceInformation",
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
],
"Resource": "*"
}
]
}
The Action
property contains all allowed operations, which I won’t go into detail about, the names tell what they do.
Now the role can be created:
aws iam create-role --role-name SessionManagerAccessRole \\
--assume-role-policy-document file://trust-policy.json
It’s straightforward; we simply pair up the role and the trust policy here.
Let’s add the policy to the role:
aws iam put-role-policy --role-name SessionManagerAccessRole --policy-name SessionManagerPolicy \\
--policy-document file://session-manager-policy.json
There’s also not much to explain here.
Add the role to the instance profile. Now that the role is created, let’s add it to the instance profile:
aws iam add-role-to-instance-profile --role-name SessionManagerAccessRole \\
--instance-profile-name SessionManagerInstanceProfile
Add the instance profile to the instance. Finally, the instance profile needs to be added to the EC2 instance:
aws ec2 associate-iam-instance-profile --instance-id i-0a62992c8638f8cc5 \\
--iam-instance-profile Name=SessionManagerInstanceProfile
The instance-id
will of course be different for everyone. It can be fetched using the aws ec2 describe-instances
command.
Restart the ssm-agent (optional). Once everything is done, it might be necessary to restart the ssm-agent inside the instance so that Session Manager can see it.
If this is the case, you need to SSH into the instance (so port 22
needs to be open in the security group), and check if the ssm-agent is running (for instances created from the Linux2 AMI):
sudo systemctl status amazon-ssm-agent
Then, you need to restart the service:
sudo systemctl restart amazon-ssm-agent
To SSH into the EC2 instance, go to the EC2 section of the Console, select the running instance, and click Connect, and run that command in the terminal.
Alternatively, grab the public IP-address for the instance using the aws ec2 describe-instances
command, and run the following instruction:
ssh -i ~/.ssh/NAME_OF_THE_PEM_FILE.pem ec2-user@10.20.30.40
where it’s assumed that the .pem
file is located in the .ssh
folder, it has 400
permissions and the public IP-address of the instance is 10.20.30.40
. If the .pem
file has permissions other than 400, it needs to be changed:
chmod 400 NAME_OF_THE_PEM_FILE.pem
3.3. Log in to the instance
Now it’s safe to remove port 22
from the security group, and the Session Manager can be used to log in to the instance:
aws ec2 revoke-security-group-ingress --group-id sg-084e99399003bfa44 --protocol tcp \\
--port 22 --cidr 10.20.30.40/32
Logging in the instance can be done via the Console or CLI.
If you decide to do it from the Console, go to Systems Manager, then select Session Manager, and Start session. The instance should show in the Console by now.
Connecting to the instance through the CLI is more fun though! We can use the CLI with the session manager plugin. Follow the instructions to get the plugin if the AWS CLI has already been installed on your machine.
We can now log in to the instance! Type the following command in the terminal and then be amazed:
aws ssm start-session --target i-0a62992c8638f8cc5
Let’s quickly discuss what target
means before the wow!
feeling spreads in your body. You need to enter the id of the EC2 instance here which you want to log in to. This id starts with i
, and it can be found by looking at the response to the aws ec2 describe-instances
command.
You can wow! now and do anything you would normally do when you SSH in the instance.
4. Clean-up
To avoid any unnecessary costs, it’s a good idea to clean up and delete the resources that have been created.
First, let’s terminate the EC2 instance:
aws ec2 terminate-instances --instance-ids i-0a62992c8638f8cc5
Next, delete all IAM-related resources. They are dependent on each other, so the order matters, otherwise you won’t be able to delete them (AWS doesn’t let account users delete anything that has a dependency).
Remove the role from the instance profile:
aws iam remove-role-from-instance-profile --instance-profile-name SessionManagerInstanceProfile \\
--role-name SessionManagerAccessRole
Then, delete the instance profile:
aws iam delete-instance-profile --instance-profile-name SessionManagerInstanceProfile
Remove the inline policy from the role:
aws iam delete-role-policy --role-name SessionManagerAccessRole --policy-name SessionManagerPolicy
Finally, delete the role itself:
aws iam delete-role --role-name SessionManagerAccessRole
All done!
5. Summary
Securing the port which developers and administrators log in to EC2 instances on is an important and still often overlooked task. It’s even better if no ports are open because this completely eliminates the chance of any port attacks.
Session Manager makes it possible to log in to the instance without opening port 22
(or 3389
). To use the Session Manager, the Systems Manager Agent needs to be installed on the instance and the relevant permissions should be assigned to it.
Thanks for reading and see you next time.