SSH Key Authentication
I pulled passwords out of my cloud infrastructure and put SSH keys in their place. Below: generating the keys, hardening sshd_config, turning off password login, and closing the other password paths on the box.
What you get:
- Nothing to crack. An Ed25519 key carries 256 bits of security. A password you can remember carries about 40.
- Nothing to spray. Brute-force and credential-stuffing bots hit a closed door.
- An audit trail. Each key ties to one person or one job, and the auth log says which key connected.
- Working automation. CI and deploy scripts authenticate without a human at a prompt.
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: elliptic curve, shorter and faster than RSA at the same strength-C "your-email@example.com": a label so you can tell keys apart later-f ~/.ssh/id_rsa: where to write the pair
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 ssh my-server is the whole command.
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 you test. If the new config locks you out, the session you already have is how you undo it.
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 every year or two:
# 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
What this buys you
- Ed25519 keys, which nobody brute-forces
- Password authentication off in SSH and in PAM
- One key per identity, so the auth log names who connected
- A passphrase on the key when you want a second factor
Where this fits
Cloud servers you reach over the internet, deployments spanning several machines, CI pipelines that need unattended access, and team servers with shared logins.
Where it does not
A single laptop with no remote access gains little over the OS keychain. A system with nowhere safe to store the private key moves the problem rather than solving it. If users churn every week, hand-copied authorized_keys files fall behind, and you want the SSH certificate setup below instead.