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_keys on 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

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.

Resources