SSH Key Authentication and Hardening
I’m documenting my approach to eliminating passwords across my cloud infrastructure. This guide covers SSH key-based authentication, hardening SSH configuration, disabling password-based login, and locking down authentication across the system. Password-less authentication is more secure than password-based login when done properly, and reduces dependency on password strength and complexity.
Why eliminate passwords?
- Stronger security — SSH keys are cryptographically harder to crack than passwords
- Reduced attack surface — No password spray or brute-force attacks
- Better auditability — SSH keys can be tied to specific identities and purposes
- Automation-friendly — CI/CD and automated deployments work better with key-based auth
- Less friction — No need to manage or rotate passwords regularly
Prerequisites
On your Mac:
- SSH installed (default on macOS)
- Access to SSH directory (
~/.ssh/)
On your Linux server:
- SSH server (openssh-server) installed and running
- Root or sudo access
- Firewall allowing SSH port (22 or custom)
Step 1: Generate SSH Key Pair on macOS
On your local Mac, generate a new SSH key pair:
ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/id_rsa
Explanation:
-t ed25519— Modern elliptic curve algorithm (better than RSA)-C "your-email@example.com"— Comment/label for the key-f ~/.ssh/id_rsa— Save to default location with default name
When prompted for passphrase, you can leave it empty for password-less login, or add one for extra security (you’ll need to use SSH agent).
Verify the key was created:
ls -la ~/.ssh/
# Should show: id_rsa (private key) and id_rsa.pub (public key)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
Step 2: Copy Public Key to Remote Server
Copy your public key to the server (this happens over SSH with a password, last time):
ssh-copy-id -i ~/.ssh/id_rsa.pub <REMOTE_USER_NAME>@<REMOTE_IP>
# Or if using a custom SSH port:
ssh-copy-id -i ~/.ssh/id_rsa.pub -p 5022 <REMOTE_USER_NAME>@<REMOTE_IP>
What this does:
- Adds your public key to
~/.ssh/authorized_keyson the remote server - Sets proper permissions (
~/.ssh/→ 700,authorized_keys→ 600)
Manual alternative (if ssh-copy-id doesn’t work):
# On your Mac:
cat ~/.ssh/id_rsa.pub
# Copy the output, then on the remote server:
mkdir -p ~/.ssh
echo "paste-your-public-key-here" >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Step 3: Test Key-Based Login
Test that key-based authentication works:
ssh -i ~/.ssh/id_rsa <REMOTE_USER_NAME>@<REMOTE_IP>
# Should connect without asking for password
If this works, you’re ready to disable password authentication.
Step 4: Configure SSH on macOS
Update your local SSH config to use the key automatically:
cat >> ~/.ssh/config << 'EOF'
Host my-server
HostName <REMOTE_IP>
User <REMOTE_USER_NAME>
Port 22
IdentityFile ~/.ssh/id_rsa
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
EOF
Now you can simply: ssh my-server
Step 5: Harden SSH on Linux Server
Edit SSH configuration:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sudo vim /etc/ssh/sshd_config
Make these changes:
# Disable root login (if you have other sudo users)
PermitRootLogin no
# Disable password authentication
PasswordAuthentication no
PubkeyAuthentication yes
# Disable empty passwords
PermitEmptyPasswords no
# Disable challenge-response (keyboard-interactive)
ChallengeResponseAuthentication no
# Disable X11 forwarding (if not needed)
X11Forwarding no
# Reduce login grace time
LoginGraceTime 30
# Limit concurrent sessions
MaxAuthTries 3
MaxSessions 10
# Use only strong key exchange algorithms
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
# Use only strong ciphers
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
# Use only strong MACs
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
Verify the configuration is valid:
sudo sshd -t
# Should return no errors
Restart SSH:
sudo systemctl restart ssh
# Or: sudo systemctl restart sshd
Test the connection from your Mac:
ssh my-server
# Should connect without password
⚠️ Keep this terminal open while testing, in case you need to revert changes.
Step 6: Disable Password-Based Authentication in Other Services
PAM (Pluggable Authentication Modules)
Disable password authentication system-wide:
sudo vim /etc/pam.d/common-password
Look for lines with pam_unix.so and ensure they have nullok removed (disallows empty passwords):
password [success=1 default=ignore] pam_unix.so obscured use_authtok try_first_pass yescrypt shadow
Sudo (if using non-root users)
Prevent password-based sudo:
sudo vim /etc/sudoers.d/99-passwordless
Add this line (allows specific users to sudo without password):
jayaprakash ALL=(ALL) NOPASSWD:ALL
Or if you want sudo to require SSH key (already covered by SSH hardening):
sudoedit /etc/sudoers
# Add: %sudo ALL=(ALL) NOPASSWD: ALL
Lock System User Accounts
Lock accounts that should never login:
# Lock the root account password (if using non-root sudo user)
sudo passwd -l root
# Lock other system accounts
sudo passwd -l www-data
sudo passwd -l mail
sudo passwd -l news
Verify locked accounts:
sudo cat /etc/shadow | grep '!' | head -5
# Lines starting with ! indicate locked accounts
Step 7: Add SSH Key to macOS Keychain (Optional)
If you set a passphrase on your SSH key, add it to SSH agent for convenience:
# Add key to agent
ssh-add -K ~/.ssh/id_rsa
# List loaded keys
ssh-add -l
# Add to ~/.ssh/config to auto-load on login:
# Host *
# UseKeychain yes
# AddKeysToAgent yes
Step 8: Generate Additional Keys (Recommended)
For different purposes (work, personal, CI/CD), generate separate keys:
# Work key
ssh-keygen -t ed25519 -C "work-deploy" -f ~/.ssh/id_work
# Personal key
ssh-keygen -t ed25519 -C "personal-server" -f ~/.ssh/id_personal
# CI/CD key
ssh-keygen -t ed25519 -C "ci-deploy" -f ~/.ssh/id_ci
Add to your SSH config:
Host work-server
HostName work.example.com
User deploy
IdentityFile ~/.ssh/id_work
Host personal-server
HostName personal.example.com
User root
IdentityFile ~/.ssh/id_personal
Best Practices
1. Key Rotation
Rotate SSH keys periodically (every 1-2 years):
# Generate new key
ssh-keygen -t ed25519 -C "new-key-$(date +%Y)" -f ~/.ssh/id_rsa_new
# Copy to server
ssh-copy-id -i ~/.ssh/id_rsa_new.pub <REMOTE_USER_NAME>@<REMOTE_IP>
# Remove old key from authorized_keys after verifying new one works
2. Monitoring Failed Login Attempts
Even with password auth disabled, monitor for attacks:
# Check failed SSH attempts
sudo tail -f /var/log/auth.log | grep "Failed password"
# Count attempts by IP
sudo grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn
3. Use SSH Config Aliases
Make connection management easier:
# ~/.ssh/config
Host home
HostName 192.168.1.100
User <LOCAL_USER_NAME>
IdentityFile ~/.ssh/id_rsa
Host cloud
HostName <REMOTE_IP>
User <REMOTE_USER_NAME>
Port 22
IdentityFile ~/.ssh/id_rsa
ServerAliveInterval 60
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
4. Disable Root Account Login
If you have a non-root sudo user, lock the root account:
sudo passwd -l root
sudo vim /etc/ssh/sshd_config
# Set: PermitRootLogin no
sudo systemctl restart ssh
5. IP Whitelisting (Optional)
Restrict SSH to specific IPs:
sudo vim /etc/ssh/sshd_config
Add at the end:
# Allow only specific IPs
ListenAddress 0.0.0.0
AllowUsers root@192.168.1.* root@5.78.110.*
6. Use SSH Certificates (Advanced)
For managing many keys across many servers, consider SSH certificates instead of individual authorized_keys:
# Generate a CA key (keep private)
ssh-keygen -t ed25519 -C "ssh-ca" -f ~/.ssh/ca_key
# Sign user key
ssh-keygen -s ~/.ssh/ca_key -I "user-cert-2026" -n root -V +52w ~/.ssh/id_rsa.pub
# Creates id_rsa-cert.pub valid for 52 weeks
Troubleshooting
“Permission denied (publickey)”
# Verify key is on server
ssh my-server "cat ~/.ssh/authorized_keys"
# Check permissions
ssh my-server "ls -la ~/.ssh/"
# Should be: drwx------ (700) for .ssh, -rw------- (600) for authorized_keys
# Debug SSH connection
ssh -vvv my-server
# Shows detailed handshake information
“Too many authentication failures”
# SSH tried too many keys; specify which one to use
ssh -i ~/.ssh/id_rsa trade
# Or add to SSH config:
# IdentitiesOnly yes
# IdentityFile ~/.ssh/id_rsa
Lost SSH Access to Server
If you locked yourself out, you need console/VNC access to recover:
# Via VNC or console:
sudo vim /etc/ssh/sshd_config
# Change PasswordAuthentication back to yes
sudo systemctl restart ssh
# Now login with password and fix the issue
Security Summary
This setup is secure because:
- SSH keys are cryptographically strong (Ed25519 algorithm)
- Passwords are disabled across SSH and system authentication
- Brute-force attacks are ineffective (keys cannot be guessed)
- Audit trail is clear (which key authenticated)
- Multi-factor auth is possible (SSH key + passphrase)
When to Use This Approach
- ✅ Cloud servers requiring remote access
- ✅ Multi-server deployments
- ✅ CI/CD pipelines needing automated access
- ✅ Teams sharing server access
- ✅ Long-term credential management
When to Consider Alternatives
- ❌ Single-machine personal use (OS keychain might be sufficient)
- ❌ Systems without secure key storage
- ❌ Environments requiring frequent user changes