AWS Environment Details:
- AMI: Ubuntu 22.04 LTS
- Instance Type: t2.micro (or any available free tier)
- Login User: ubuntu
- Introduction to SSH Hardening
- Setting Up AWS EC2 Instance
- Key-based Authentication
- Hardening SSH Configuration
- Setting Up Fail2Ban
- Implementing Two-Factor Authentication
- Testing Your Hardened SSH Configuration
- Final Security Checklist
SSH (Secure Shell) is a cryptographic network protocol used for secure remote system administration and file transfers. SSH hardening is the process of strengthening SSH configurations to enhance security and protect against unauthorized access, brute force attacks, and other security threats.
- SSH is often the primary entry point to servers
- Default SSH configurations can be vulnerable to various attacks
- Properly hardened SSH can prevent most common attack vectors
- A single compromised server can lead to lateral movement across your infrastructure
SSH hardening is not just a good practice; it's essential for any server exposed to the internet.
Amazon EC2 (Elastic Compute Cloud) provides scalable computing capacity in the AWS cloud. We'll use an EC2 instance as our server to practice SSH hardening techniques.
Cloud servers are common targets for attackers due to their public accessibility. Proper setup of security groups and network settings is the first line of defense.
- Log in to the AWS Management Console
- Navigate to EC2 Dashboard and click "Launch Instance"
- Name your instance (e.g., "SSH-Hardening-Practice")
- Select "Ubuntu" for the AMI (specifically Ubuntu 22.04 LTS)
- Choose "t2.micro" as the instance type
- Create a new key pair (e.g., "ssh-hardening-key")
- Select RSA as the key pair type
- Select .pem file format
- Download the key pair file
- Create a new security group with the following inbound rule:
- Type: SSH
- Protocol: TCP
- Port Range: 22
- Source: My IP (this restricts SSH access to your current IP address)
- Configure storage (default 8GB is sufficient)
- Click "Launch Instance"
On your local machine, set appropriate permissions for your key pair file:
# For macOS/Linux
chmod 400 ~/Downloads/ssh-hardening-key.pem
# For Windows (using Git Bash or similar)
chmod 400 /path/to/ssh-hardening-key.pemssh -i ~/Downloads/ssh-hardening-key.pem ubuntu@your-instance-public-ipVerify successful connection to your EC2 instance. You should see the Ubuntu welcome message and have command-line access.
- The initial connection is not yet hardened; we'll improve its security throughout this guide
- Keep your .pem key file secure; anyone with this file can access your instance
- EC2 charges apply while your instance is running; remember to stop or terminate it when done
Key-based authentication uses cryptographic key pairs (public/private keys) instead of passwords for SSH authentication. The private key remains on your local machine, while the public key is stored on the server.
- Significantly more secure than password authentication
- Resistant to brute force attacks
- No password to forget or share
- Can be combined with other security measures for defense in depth
First, let's create a regular user that we'll use instead of the default ubuntu user:
# Create a new user (replace 'student' with your preferred username)
sudo adduser student
# Add user to sudo group for administrative privileges
sudo usermod -aG sudo student
# Switch to the new user
sudo su - student
# Create .ssh directory with proper permissions
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysOn your local machine (not the EC2 instance), generate a new SSH key pair:
ssh-keygen -t ed25519 -f ~/.ssh/aws-ssh-hardening -C "student@ssh-hardening"This will create:
- Private key:
~/.ssh/aws-ssh-hardening - Public key:
~/.ssh/aws-ssh-hardening.pub
Now, copy the public key content to your server's authorized_keys file:
# On your local machine, display your public key
cat ~/.ssh/aws-ssh-hardening.pubCopy the output, then on the EC2 instance (as the student user):
# Paste the public key into the authorized_keys file
echo "paste-your-public-key-here" >> ~/.ssh/authorized_keys
# Verify the key was added
cat ~/.ssh/authorized_keysAlternatively, use the ssh-copy-id command if available:
ssh-copy-id -i ~/.ssh/aws-ssh-hardening.pub student@your-instance-public-ipTest the key-based authentication by opening a new terminal and connecting with your new key:
ssh -i ~/.ssh/aws-ssh-hardening student@your-instance-public-ipYou should connect successfully without being prompted for a password.
- Store your private key securely; anyone with this key can access your server
- Consider using a passphrase when generating your key for additional security
- The key generation process shown uses ED25519, which is more secure than older RSA-based keys
SSH configuration hardening involves modifying the SSH daemon settings to enhance security by disabling unnecessary features, limiting access, and enforcing stronger security policies.
- Default SSH settings prioritize compatibility over security
- Proper configuration can prevent many common attack vectors
- Restricting access methods reduces the attack surface
- Each hardening measure adds a layer of security
Before making changes, create a backup of the original configuration:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backupOpen the SSH daemon configuration file:
sudo nano /etc/ssh/sshd_configMake the following changes to the configuration file. Look for existing lines and modify them, or add new lines if they don't exist:
# Disable root login
PermitRootLogin no
# Disable password authentication
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
# Allow public key authentication
PubkeyAuthentication yes
# Change default SSH port (example: 2222)
Port 2222
# Limit user access (replace 'student' with your username)
AllowUsers student
# Set idle timeout (disconnect after 10 minutes of inactivity)
ClientAliveInterval 300
ClientAliveCountMax 2
# Use Protocol 2 only
Protocol 2
# Enable verbose logging
LogLevel VERBOSE
# Restrict SSH to IPv4 only (if needed)
AddressFamily inet
# Disable tunneling and port forwarding (if not needed)
AllowTcpForwarding no
X11Forwarding no- Go to the EC2 Dashboard
- Click on "Security Groups" in the left menu
- Select the security group attached to your instance
- Click "Edit inbound rules"
- Add a new rule:
- Type: Custom TCP
- Protocol: TCP
- Port range: 2222 (or your chosen port)
- Source: My IP
- Keep the existing rule for port 22 until we verify the new port works
- Click "Save rules"
After making changes, check the configuration for syntax errors and restart the SSH service:
# Check configuration syntax
sudo sshd -t
# If no errors, restart SSH
sudo systemctl restart sshdOpen a new terminal and try connecting to the new port:
ssh -i ~/.ssh/aws-ssh-hardening -p 2222 student@your-instance-public-ipAlso test that the security measures are working:
# Try logging in as root (should fail)
ssh -i ~/.ssh/aws-ssh-hardening -p 2222 root@your-instance-public-ip
# Try logging in with password (should fail)
ssh -p 2222 student@your-instance-public-ip- Important: Do not close your current SSH session until you've verified you can connect with the new settings
- If you get locked out, you can use the AWS console's EC2 Instance Connect as a backup
- After confirming the new port works, remove the port 22 rule from your security group
Fail2Ban is an intrusion prevention tool that monitors log files and temporarily bans IPs that show malicious signs such as too many failed login attempts. It works by creating firewall rules to block IP addresses that exhibit suspicious behavior.
- Protects against brute force attacks and dictionary attacks
- Reduces server load from sustained attack attempts
- Provides automated response to potential threats
- Customizable to fit specific security needs
sudo apt update
sudo apt install fail2ban -yFail2Ban uses the default configuration in /etc/fail2ban/jail.conf, but we'll create a local configuration file that won't be overwritten during updates:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.d/ssh.localAdd the following configuration:
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 600
findtime = 300
ignoreip = 127.0.0.1/8 ::1
This configuration:
- Enables monitoring for SSH on port 2222
- Sets maximum retry attempts to 3 within 300 seconds (5 minutes)
- Sets ban time to 600 seconds (10 minutes)
- Ignores localhost
sudo systemctl start fail2ban
sudo systemctl enable fail2banCheck Fail2Ban status and configuration:
# Check if Fail2Ban is running
sudo systemctl status fail2ban
# Check the status of the SSH jail
sudo fail2ban-client status sshdTo test Fail2Ban (from a different machine):
- Try to connect with an incorrect key or password multiple times
- After 3 failures, your IP should be banned
- Check the ban status:
sudo fail2ban-client status sshd- Set the
ignoreipparameter to include your fixed IP addresses to prevent locking yourself out - Adjust
bantime,findtime, andmaxretrybased on your security requirements - For production servers, consider increasing the ban time to several hours or days
flowchart TD
A(Client) -->|SSH Login Attempt| B(Server)
B -->|Failed Login| C(/var/log/auth.log)
C -->|Read Log| D(Fail2Ban)
D -->|Check Against Rules| E{Exceed Threshold?}
E -->|Yes| F(Add Firewall Rule)
F -->|Block IP| G(iptables/firewall)
G -->|Connection Blocked| A
E -->|No| H(Continue Monitoring)
I(Timer) -->|After bantime| J(Remove Firewall Rule)
J -->|Unblock IP| G
Two-Factor Authentication (2FA) adds an additional layer of security by requiring something you know (password or key) and something you have (a time-based one-time password generated on your mobile device).
- Adds an extra verification layer beyond SSH keys
- Protects against stolen private keys
- Makes unauthorized access significantly more difficult
- Recommended for production systems with sensitive data
sudo apt update
sudo apt install libpam-google-authenticator -yLog in as the user who will use 2FA, then run:
google-authenticatorAnswer the following prompts:
- Time-based tokens?
y - Update .google_authenticator file?
y - Disallow multiple uses?
y - Increase time window?
n - Rate limiting?
y
After running this command, you'll see:
- A QR code to scan with the Google Authenticator app
- A secret key for manual entry
- Emergency scratch codes (save these securely)
Scan the QR code with the Google Authenticator app on your smartphone.
Edit the SSH PAM configuration:
sudo nano /etc/pam.d/sshdAdd the following line at the end of the file:
auth required pam_google_authenticator.so
Edit the SSH configuration:
sudo nano /etc/ssh/sshd_configFind or add these lines:
# Enable challenge-response authentication
ChallengeResponseAuthentication yes
# Make sure this is set to 'no' if using only key-based auth
PasswordAuthentication no
# Enable AuthenticationMethods
AuthenticationMethods publickey,keyboard-interactive
sudo systemctl restart sshdOpen a new terminal and connect to your server:
ssh -i ~/.ssh/aws-ssh-hardening -p 2222 student@your-instance-public-ipYou should now be prompted for:
- Your SSH key passphrase (if you set one)
- A verification code from your Google Authenticator app
Enter the code shown in your Google Authenticator app to complete the login.
- Keep your backup/scratch codes in a secure location
- If you lose access to your authenticator app and scratch codes, you'll need to use AWS console access to recover
- Ensure your server and phone clocks are synchronized to avoid authentication issues
sequenceDiagram
participant Client
participant Server
participant SSH
participant PAM
participant Google Auth
Client->>Server: Connection request to port 2222
Server->>SSH: Handle connection
SSH->>Client: Request public key
Client->>SSH: Provide public key
SSH->>PAM: Authenticate user
PAM->>Google Auth: Request verification
Google Auth->>Client: Prompt for verification code
Client->>Google Auth: Provide TOTP code
Google Auth->>PAM: Validate code
PAM->>SSH: Authentication result
SSH->>Client: Grant/deny access
Testing your SSH hardening configuration ensures that all security measures are working as expected and helps identify any potential weaknesses or misconfigurations.
- Verifies that security controls are functioning correctly
- Identifies potential vulnerabilities before attackers do
- Ensures legitimate users can still access the system
- Builds confidence in your security implementation
# Connect with the correct key, port, and user
ssh -i ~/.ssh/aws-ssh-hardening -p 2222 student@your-instance-public-ipThis should prompt for your 2FA code and then connect successfully.
Try these tests, which should all fail:
# Attempt to connect to the default port
ssh -i ~/.ssh/aws-ssh-hardening student@your-instance-public-ip
# Attempt to connect as root
ssh -i ~/.ssh/aws-ssh-hardening -p 2222 root@your-instance-public-ip
# Attempt to connect without a key
ssh -p 2222 student@your-instance-public-ip
# Attempt to connect with wrong 2FA code
ssh -i ~/.ssh/aws-ssh-hardening -p 2222 student@your-instance-public-ip
# Enter an incorrect verification codeFrom a different machine or network:
# Attempt multiple failed logins
ssh -p 2222 student@your-instance-public-ip
# Enter incorrect password multiple timesAfter 3 failed attempts, check if your IP is banned:
sudo fail2ban-client status sshdVerify your SSH configuration:
# Check for syntax errors
sudo sshd -t
# View active configuration
sudo sshd -T# View SSH auth logs
sudo grep "sshd" /var/log/auth.logLook for failed login attempts, successful logins, and other SSH-related events.
- Run these tests from different machines if possible
- Testing Fail2Ban might temporarily block your access; have a backup access method
- Use AWS EC2 Instance Connect as a last resort if you get locked out
| Security Measure | Configuration | Implemented | Tested |
|---|---|---|---|
| EC2 Security Group | Custom port 2222 only | β | β |
| Key-based Authentication | RSA/ED25519 key pair | β | β |
| Root Login | PermitRootLogin no |
β | β |
| Password Authentication | PasswordAuthentication no |
β | β |
| Custom SSH Port | Port 2222 |
β | β |
| User Restrictions | AllowUsers student |
β | β |
| Idle Timeout | ClientAliveInterval 300 |
β | β |
| Protocol Version | Protocol 2 |
β | β |
| Verbose Logging | LogLevel VERBOSE |
β | β |
| Fail2Ban | Installed and configured | β | β |
| 2FA Authentication | Google Authenticator | β | β |
| Regular User | student with sudo access |
β | β |
-
Regular Updates:
sudo apt update && sudo apt upgrade -y -
Monitor Failed Login Attempts:
sudo grep "Failed password" /var/log/auth.log -
Configure Automatic Security Updates:
sudo apt install unattended-upgrades sudo dpkg-reconfigure unattended-upgrades
-
Consider Additional Security Tools:
- OSSEC - Host-based intrusion detection
- AWS CloudWatch - Log monitoring and alerting
- AWS GuardDuty - Threat detection service
- AWS Systems Manager - Secure remote management
-
Document Your Configuration:
- Keep records of security settings
- Create a disaster recovery plan
- Document emergency access procedures
Congratulations! You've successfully implemented a comprehensive SSH hardening solution on your AWS EC2 instance. By applying these best practices, you've significantly reduced the attack surface and improved the security posture of your server.
Remember that security is an ongoing process. Regularly update your systems, monitor for suspicious activities, and adjust your security measures as new threats emerge.
This training has covered:
- Setting up AWS EC2 instances with proper security groups
- Implementing key-based authentication
- Hardening SSH configurations
- Installing and configuring Fail2Ban
- Setting up two-factor authentication with Google Authenticator
- Testing and verifying your security measures
These skills are directly applicable to real-world server security and will provide a solid foundation for securing any SSH server you manage in the future.
When you've completed this training, remember to:
-
Terminate your EC2 instance to avoid ongoing charges:
- Go to the EC2 Dashboard
- Select your instance
- Click "Instance State" -> "Terminate Instance"
-
Securely store your documentation for future reference
-
Save your SSH keys if you plan to use them for other servers