SSH & Key-Based Authentication

TL;DR

SSH key-based auth uses a public/private key pair — your private key stays on your machine, the public key goes on the server. No passwords cross the network. Use ssh-keygen to create keys, ssh-copy-id to deploy them, and ssh-agent to avoid retyping passphrases.

Explain Like I'm 12

Imagine you have a special padlock (public key) and the only key that opens it (private key). You send copies of the padlock to everyone — your school, your friend, your locker. When they want to make sure it's really you, they lock a secret message with your padlock. Only YOU can open it because only you have the key. That's SSH keys — your private key never leaves your pocket.

How SSH Key Authentication Works

When you connect to a server via SSH, a cryptographic handshake happens behind the scenes:

SSH key-based authentication flow showing client generating challenge, server verifying with public key
  1. Client connects to the SSH server and presents its public key
  2. Server checks if that public key is in ~/.ssh/authorized_keys
  3. Server sends a challenge — random data encrypted with the client's public key
  4. Client decrypts the challenge with its private key and sends back a hash
  5. Server verifies the hash — if it matches, authentication succeeds
Info: The private key never leaves your machine and is never sent over the network. The server only needs your public key to verify your identity.

Generating SSH Keys

# Generate an Ed25519 key (recommended — fast, secure, short)
ssh-keygen -t ed25519 -C "[email protected]"
# Output: ~/.ssh/id_ed25519 (private) + ~/.ssh/id_ed25519.pub (public)

# Generate an RSA key (wider compatibility, use 4096 bits)
ssh-keygen -t rsa -b 4096 -C "[email protected]"
# Output: ~/.ssh/id_rsa (private) + ~/.ssh/id_rsa.pub (public)

# ALWAYS set a passphrase when prompted!
# It encrypts your private key at rest.
AlgorithmKey SizeSecurityRecommendation
Ed25519256-bitExcellentUse this (modern, fast, short keys)
RSA4096-bitGoodFallback when Ed25519 isn't supported
ECDSA256/384/521-bitGoodAvoid (potential implementation issues)
DSA1024-bitWeakDeprecated — never use
Warning: Always protect your private key with a passphrase. Without one, anyone who gets your private key file has instant access to all servers that trust it.

Deploying Your Public Key

# Method 1: ssh-copy-id (easiest)
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

# Method 2: Manual copy
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

# Method 3: For GitHub/GitLab — paste the public key in Settings > SSH Keys
cat ~/.ssh/id_ed25519.pub
# Copy the output and paste it into GitHub SSH settings
Tip: The authorized_keys file lives at ~/.ssh/authorized_keys on the server. Each line is one public key. You can add multiple keys for different machines.

SSH Agent: Don't Retype Your Passphrase

The ssh-agent holds your decrypted private keys in memory so you only enter your passphrase once per session.

# Start the agent (usually auto-started on modern systems)
eval "$(ssh-agent -s)"

# Add your key (prompts for passphrase once)
ssh-add ~/.ssh/id_ed25519

# List loaded keys
ssh-add -l

# On macOS, add to Keychain so it persists across reboots
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Info: Agent forwarding (ssh -A) lets you use your local keys on a remote server to hop to another server. But use it carefully — a compromised remote server could use your forwarded agent.

SSH Config File

The ~/.ssh/config file lets you create shortcuts and set per-host options:

# ~/.ssh/config

# Short alias for a production server
Host prod
    HostName 203.0.113.50
    User deploy
    IdentityFile ~/.ssh/id_ed25519_work
    Port 2222

# GitHub with specific key
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github

# Jump through a bastion host
Host internal-db
    HostName 10.0.1.50
    User admin
    ProxyJump bastion.example.com

# Now just type: ssh prod  (instead of ssh -i ~/.ssh/id_ed25519_work -p 2222 [email protected])

Security Best Practices

PracticeWhyHow
Use Ed25519Modern, fast, short keys, high securityssh-keygen -t ed25519
Always set a passphraseEncrypts private key at restEnter passphrase when prompted by ssh-keygen
Disable password auth on serverPrevents brute-force attacksPasswordAuthentication no in sshd_config
Disable root loginForces use of named accounts + sudoPermitRootLogin no in sshd_config
Use ssh-agent, not passphrase-less keysConvenience without sacrificing securityssh-add ~/.ssh/id_ed25519
Rotate keys periodicallyLimits exposure window if compromisedGenerate new key, deploy, remove old
Set correct file permissionsSSH refuses keys with loose permissionschmod 700 ~/.ssh; chmod 600 ~/.ssh/*
# Harden sshd_config on your server
# /etc/ssh/sshd_config

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
MaxAuthTries 3
X11Forwarding no

# Restart SSH after changes
sudo systemctl restart sshd
Warning: Before disabling password auth, make sure your SSH key works! Otherwise you'll lock yourself out. Always test key-based login in a second terminal before changing sshd_config.

SSH for Git (GitHub, GitLab, Bitbucket)

# Test your SSH connection to GitHub
ssh -T [email protected]
# Hi username! You've authenticated, but GitHub does not provide shell access.

# Clone with SSH (no password prompts ever)
git clone [email protected]:username/repo.git

# Switch existing repo from HTTPS to SSH
git remote set-url origin [email protected]:username/repo.git
Tip: If you have multiple GitHub accounts (work + personal), use the SSH config file to map different keys to different Host aliases.

Test Yourself

In SSH key authentication, what is sent over the network — the public key or the private key?

Neither is "sent" during authentication in the traditional sense. The public key is pre-deployed to the server's authorized_keys. During the handshake, the server uses it to create a challenge. The private key never leaves your machine — it's used locally to decrypt the challenge and prove you own it.

Why should you use Ed25519 over RSA for new SSH keys?

Ed25519 provides equivalent or better security with much shorter keys (256 vs 4096 bits), faster key generation and authentication, and is resistant to certain side-channel attacks. The only reason to use RSA is compatibility with very old systems.

What happens if your ~/.ssh directory has 777 permissions?

SSH will refuse to use your keys and fall back to password auth (or fail entirely). SSH requires strict permissions: ~/.ssh must be 700, private keys must be 600. This prevents other users on the system from reading your keys.

What is agent forwarding and what's the risk?

Agent forwarding (ssh -A) lets a remote server use your local ssh-agent to authenticate to other servers. The risk: if the remote server is compromised, an attacker can use your forwarded agent to access any server your key is authorized on. Use ProxyJump instead when possible.

You've set up key-based auth and want to disable passwords. What should you verify first?

Test your key-based login in a separate terminal session first. If you disable PasswordAuthentication and your key doesn't work (wrong permissions, wrong key deployed), you'll be locked out permanently. Always keep an active session open while testing.

Interview Questions

Explain the SSH key-based authentication handshake in detail. What happens at each step?

1) Client connects and offers its public key fingerprint. 2) Server checks authorized_keys for a match. 3) Server generates a random number, encrypts it with the client's public key, and sends it. 4) Client decrypts with its private key, combines with the session ID, and sends back an HMAC hash. 5) Server verifies the hash. If it matches, the client proved it holds the private key without ever transmitting it.

How would you set up SSH access through a bastion host (jump server) securely?

Use ProxyJump in SSH config: Host internal\n ProxyJump bastion. This creates a direct tunnel — your SSH client connects through the bastion to the internal host. The bastion never sees your private key (unlike agent forwarding). Add strict bastion rules: key-only auth, limited users, audit logging, session recording.

A developer commits their SSH private key to a public GitHub repo. What's the remediation plan?

1) Assume the key is compromised — immediately remove the public key from all authorized_keys files on every server. 2) Generate a new key pair and deploy the new public key. 3) Audit access logs on all servers for unauthorized access. 4) Remove the key from git history (git filter-branch or BFG Repo-Cleaner). 5) Add id_* patterns to .gitignore and consider pre-commit hooks to prevent future leaks.

What's the difference between SSH key-based auth and certificate-based SSH auth?

Key-based: each public key is individually added to each server's authorized_keys — doesn't scale well. Certificate-based: a CA signs short-lived SSH certificates. Servers trust the CA, not individual keys. Benefits: automatic expiry, no authorized_keys management, centralized revocation. Tools like HashiCorp Vault can issue SSH certificates on demand.