Mastering Secure SSH Access to EC2 Instances: Beyond the Basics
Forget the generic SSH tutorials—learn the nuanced best practices and advanced configurations that real cloud engineers use to lock down EC2 access without sacrificing agility or manageability.
When it comes to managing your EC2 instances, SSH is often the default gateway. But poorly configured SSH access is a giant attack surface waiting to be exploited. The default AWS security guidelines, while a solid starting point, often fall short under serious threat models or at scale. In this post, we’ll dive deeper into securing SSH access to EC2 instances by combining AWS-native features with battle-tested Linux tools and operational workflows.
Why Secure SSH Access to EC2 Matters
Misconfigured SSH isn’t just an inconvenience — it can lead to unauthorized lateral movement, compromised data, or even a full infrastructure breach. Simple mistakes like using default security groups with open port 22 access or relying solely on password authentication remain common pitfalls.
By mastering advanced SSH security techniques, you’ll:
- Minimize attack surface by restricting who and what can connect
- Reduce risk of credential leaks through better key management and multi-factor authentication
- Maintain operational agility without adding friction to daily workflows
- Create auditable and manageable access logs and controls
Step 1: Lock Down Network Access with Security Groups and VPC Features
Use Narrow Security Groups
Avoid wide-open SSH access (0.0.0.0/0
on port 22). Instead, limit inbound SSH traffic to a specific, trusted IP range — such as your office’s static IP or VPN subnet.
Example CLI to update security group:
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 22 \
--cidr 203.0.113.0/24
Consider a Bastion Host or AWS Systems Manager (SSM)
Rather than opening SSH port directly to your instances, route all SSH traffic through a hardened bastion host or better yet, use AWS Systems Manager Session Manager, which provides SSH-like connectivity without exposing port 22 at all.
Bastion host pattern:
- Launch a dedicated instance with strict IAM role and security group allowing SSH only from trusted IPs.
- Restrict internal EC2 instances to allow SSH only from bastion’s private IP.
Step 2: Adopt Key-Based Authentication with Strong Practices
Password-based authentication should be disabled entirely on all EC2 instances once initial setup completes.
Generate and Use Strong SSH Key Pairs
- Use at least 2048-bit RSA or, preferably, Ed25519 keys.
- Protect private keys with a password and store securely (e.g., hardware token, encrypted vault).
Generate Ed25519 key:
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/my-ec2-key
Upload Public Key Securely to EC2
- Use EC2 instance metadata or user-data scripts at launch time.
- Alternatively, manually place your public key in the
~/.ssh/authorized_keys
file for the target user.
Disable Password Authentication and Root Login
Modify SSH daemon config (/etc/ssh/sshd_config
):
PasswordAuthentication no
PermitRootLogin no
ChallengeResponseAuthentication no
And restart sshd:
sudo systemctl restart sshd
Step 3: Harden SSH Daemon Configuration
Beyond disabling root login and password authentication, several other sshd config tweaks enhance security:
-
Change default SSH port (optional; helps reduce noise but not foolproof):
Port 2222
-
Limit users allowed to SSH:
AllowUsers ec2-user ubuntu deployer
-
Enable SSH Connection Rate Limiting using
LoginGraceTime
and MaxAuthTries:LoginGraceTime 30 MaxAuthTries 3
-
Use
AllowTcpForwarding no
andX11Forwarding no
if not needed. -
Enable logging verbosity:
LogLevel VERBOSE
Step 4: Implement SSH Certificate-Based Authentication (Advanced)
For large scale or high-security environments, managing SSH keys becomes cumbersome. Instead, use SSH certificates signed by a trusted CA.
How it works
- You maintain a CA private key (offline).
- Users generate SSH key pairs.
- You sign each user’s public key with your CA key, embedding expiration and other metadata.
- EC2 instances are configured to trust your CA public key.
This way, revoking or rotating access is as simple as controlling certificate issuance.
Basic example workflow
- Generate CA key:
ssh-keygen -f ~/.ssh/ca_user -C "SSH CA"
- Sign user key:
ssh-keygen -s ~/.ssh/ca_user -I user1 -n ec2-user -V +52w user1.pub
- Configure EC2 instance
/etc/ssh/sshd_config
to trust CA keys:
TrustedUserCAKeys /etc/ssh/ca_user.pub
- Restart sshd and provide user with signed cert (
user1-cert.pub
) to connect:
ssh -i ~/.ssh/user1 -i ~/.ssh/user1-cert.pub ec2-user@ec2-instance
Step 5: Integrate Multi-Factor SSH Authentication
For high assurance environments, you can require MFA for SSH sessions:
- Use tools like Google Authenticator PAM module or hardware tokens like YubiKey.
- Configure PAM (
/etc/pam.d/sshd
) to include MFA challenge along with key auth.
Example install Google Authenticator on Amazon Linux 2:
sudo yum install -y google-authenticator qrencode
google-authenticator
Add to sshd PAM config:
auth required pam_google_authenticator.so nullok
And modify sshd_config
:
ChallengeResponseAuthentication yes
Step 6: Monitor and Audit SSH Access
- Enable detailed SSH logs (as above).
- Forward logs to a centralized system (CloudWatch Logs, ELK stack).
- Use AWS CloudTrail for capturing API-level actions.
- Employ intrusion detection tools like fail2ban to block repeated failed attempts.
Bonus: Automating Secure SSH Setup with User Data Script
Here’s a simplified example of a user-data script for launching EC2 instances with hardened SSH:
#!/bin/bash
# Disable password auth and root login
sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# Add trusted public key
mkdir -p /home/ec2-user/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC..." > /home/ec2-user/.ssh/authorized_keys
chown -R ec2-user:ec2-user /home/ec2-user/.ssh
chmod 700 /home/ec2-user/.ssh
chmod 600 /home/ec2-user/.ssh/authorized_keys
systemctl restart sshd
Final Thoughts
Securing SSH access to your EC2 instances goes far beyond opening port 22 and tossing around keys. By implementing a layered approach—network restrictions, strong authentication, hardened daemon settings, certificate-based access, MFA, and auditing—you can significantly reduce the risk of compromise while maintaining manageable, scalable operations.
Start today by tightening your security group rules and disabling password access, then progressively adopt more advanced techniques as your environment grows. Your infrastructure’s security depends on it!
If you’d like a deep dive on any particular step or scripts to automate these controls with Terraform or CloudFormation, let me know in the comments!