How to SSH into an EC2 Instance: Key Pairs, Instance Connect and Session Manager
There are three practical ways to get a shell on an EC2 Linux instance:
| Method | Needs inbound port 22 | Access controlled by | Good for |
|---|---|---|---|
| SSH with a key pair | Yes | Whoever holds the private key | Quick start, single instances |
| EC2 Instance Connect | Yes (from you or from an endpoint) | IAM | Teams, no long-lived keys |
| Session Manager | No | IAM | Private instances, audited access |
Plain SSH is the classic method. The other two let you drop shared .pem files and, in the case of Session Manager, close port 22 entirely.
Method 1: SSH with a key pair
Before connecting, check:
- The instance is running and has passed its status checks.
- It has a public IP or public DNS name, or you are on a network that can reach its private IP.
- Its security group allows TCP 22 from your IP address, not from
0.0.0.0/0. - You have the private key of the key pair chosen at launch.
Create or import a key pair if you do not have one:
# Let AWS generate it
aws ec2 create-key-pair --key-name my-key --key-type ed25519 \
--query KeyMaterial --output text > ~/.ssh/my-key.pem
# Or upload a public key you already have
aws ec2 import-key-pair --key-name my-laptop \
--public-key-material fileb://~/.ssh/id_ed25519.pub
Allow SSH from your current IP only:
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 \
--protocol tcp --port 22 --cidr "$(curl -s https://checkip.amazonaws.com)/32"
Find the address and connect:
chmod 400 ~/.ssh/my-key.pem
aws ec2 describe-instances --instance-ids i-0123456789abcdef0 \
--query 'Reservations[].Instances[].PublicIpAddress' --output text
ssh -i ~/.ssh/my-key.pem ec2-user@203.0.113.10
The username depends on the AMI:
| AMI | Username |
|---|---|
| Amazon Linux | ec2-user |
| Ubuntu | ubuntu |
| Debian | admin |
| RHEL, SUSE | ec2-user |
| Fedora | fedora or ec2-user |
| CentOS | centos or ec2-user |
| Rocky Linux | rocky |
| Bitnami | bitnami |
A wrong username gives the same Permission denied (publickey) error as a wrong key, so check it first.
From Windows. Windows 10 and 11 include OpenSSH, so the same ssh -i command works in PowerShell. Instead of chmod, remove inherited permissions on the key:
icacls.exe my-key.pem /inheritance:r
icacls.exe my-key.pem /grant:r "$($env:USERNAME):(R)"
For PuTTY, download the key pair in .ppk format when you create it, or convert the .pem with PuTTYgen.
Save the details in ~/.ssh/config so you only have to type ssh my-app:
Host my-app
HostName 203.0.113.10
User ec2-user
IdentityFile ~/.ssh/my-key.pem
Host private-db
HostName 10.0.2.15
User ec2-user
IdentityFile ~/.ssh/my-key.pem
ProxyJump my-app
ProxyJump reaches an instance in a private subnet through a bastion (ssh -J on the command line). Prefer it over agent forwarding (ssh -A), which lets anyone with root on the bastion use your agent while you are connected.
Method 2: EC2 Instance Connect
Instance Connect pushes a temporary public key to the instance's metadata. The key is valid for 60 seconds, which is enough to open the session. Access is controlled by the IAM permission ec2-instance-connect:SendSSHPublicKey, so there are no shared private keys to hand out or revoke. The software is preinstalled on Amazon Linux and recent Ubuntu AMIs. On other distributions, install the ec2-instance-connect package.
With AWS CLI v2, one command generates a key, pushes it and connects:
aws ec2-instance-connect ssh --instance-id i-0123456789abcdef0 --os-user ubuntu
You can also click Connect > EC2 Instance Connect in the EC2 console. For browser connections, the security group must allow port 22 from the AWS-managed prefix list com.amazonaws.<region>.ec2-instance-connect.
Private instances without a bastion. Create an EC2 Instance Connect Endpoint in the VPC once:
aws ec2 create-instance-connect-endpoint \
--subnet-id subnet-0123456789abcdef0 --security-group-ids sg-0aaa1111
Allow port 22 on the instance's security group from the endpoint's security group, then connect through it:
aws ec2-instance-connect ssh --instance-id i-0123456789abcdef0 --connection-type eice
The instance needs no public IP and no internet-facing SSH port.
Method 3: Session Manager
Session Manager opens a shell through the SSM Agent's outbound HTTPS connection. No inbound rules, no SSH keys, no public IP. It needs:
- SSM Agent on the instance (preinstalled on Amazon Linux, Ubuntu and many other AWS-provided AMIs).
- An instance profile with the
AmazonSSMManagedInstanceCoremanaged policy. - Outbound HTTPS from the instance to Systems Manager, either through a NAT gateway or through Systems Manager VPC endpoints.
- The AWS CLI and the Session Manager plugin on your machine.
aws ssm start-session --target i-0123456789abcdef0
You get a shell as ssm-user. Sessions can be logged to CloudWatch Logs or S3, and IAM policies decide who may connect to which instances.
You can still use normal ssh, scp and port forwarding through Session Manager. Add this to ~/.ssh/config (macOS and Linux):
Host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
User ec2-user
Then ssh -i ~/.ssh/my-key.pem i-0123456789abcdef0 works with port 22 closed in the security group. The SSH key still has to be authorized on the instance. Session logging does not cover these tunneled SSH sessions, because their traffic is encrypted end to end.
Troubleshooting
- Connection timed out: a network problem. The security group does not allow your current IP, the instance has no public IP, the subnet has no route to an internet gateway, or a network ACL blocks the traffic. Remember that your own IP may have changed.
- Permission denied (publickey): wrong username for the AMI, wrong key file, or the instance was launched with a different key pair.
UNPROTECTED PRIVATE KEY FILE: runchmod 400on the key, or fix its ACL on Windows.REMOTE HOST IDENTIFICATION HAS CHANGED: a stopped and started instance gets a new public IP, which may have belonged to another host before. Runssh-keygen -R 203.0.113.10after confirming the instance is yours. Use an Elastic IP if the address must stay fixed.- Lost private key: connect with Instance Connect or Session Manager and add a new public key to
~/.ssh/authorized_keys. As a last resort, use the EC2 serial console, or attach the root volume to another instance and fix the file there.
Locking down SSH access
- Never open port 22 to
0.0.0.0/0. Restrict it to known IPs, or close it and use Session Manager or an Instance Connect Endpoint. - Give every person their own access: IAM-based Instance Connect or Session Manager instead of one shared
.pem. - Keep password authentication and root login disabled. AWS-provided AMIs ship this way, so check that your own images do too.
- Review CloudTrail for
SendSSHPublicKeyandStartSessionevents to see who connected, and when. - For large fleets that still need plain SSH, SSH certificates signed by an internal CA scale better than distributing public keys.
Quick reference
chmod 400 my-key.pem
ssh -i my-key.pem ec2-user@PUBLIC_IP
ssh -J ec2-user@BASTION_IP ec2-user@PRIVATE_IP
aws ec2-instance-connect ssh --instance-id i-xxx --os-user ubuntu
aws ec2-instance-connect ssh --instance-id i-xxx --connection-type eice
aws ssm start-session --target i-xxx
ssh i-xxx # with the AWS-StartSSHSession ProxyCommand in ~/.ssh/config
