Stop Using Bastion Hosts on AWS!

There is now a means of connecting to EC2 instances in private subnets without requiring public IP addresses. As long as the machine can accept a TCP connection, you’re golden. There is no additional cost attached outside of traffic.

What you’re looking for is called EC2 Instance Connect Endpoint. Only ports 22 and 3389 are supported, but of course you can use additional ssh tunnels for port forwarding. You chuck one of these into your private subnet and tunnel through it.

Unfortunately, EC2 Instance Connect Endpoint doesn’t support connections to an instance using IPv6 addresses, but that should not practically impact us too much.

ssh -i my-key-pair.pem ec2-user@i-0123456789example \
    -o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-id i-0123456789example'

Connect using EC2 Instance Connect Endpoint to a Linux instance

That’s it. You don’t even have to remember that, you can just chuck it all into your ssh config.

Host myhost
    HostName i-0123456789example
    User ec2-user
    Port 22
    IdentityFile ~/.ssh/my-key-pair.pem
    ProxyCommand aws ec2-instance-connect open-tunnel --instance-id i-0123456789example

For windows, you just forward the RDP port and then connect to localhost:<local port>

aws ec2-instance-connect open-tunnel \
    --instance-id i-0123456789example \
    --remote-port 3389 \
    --local-port <local port>

Connect using EC2 Instance Connect Endpoint to a Windows instance

If you plan on maintaining a fleet of EC2 machines, and keeping them patched, you should probably look at AWS SSM Fleet Manager, though.