Software and Versions Used
This explanation applies to:
- SSH protocol: OpenSSH 9.0+ (standard on modern systems)
- Cryptography: RSA-4096, Ed25519, ECDSA-256
- SSH client: ssh, ssh-keygen, ssh-add, ssh-agent
- Context: Distribution-independent SSH fundamentals
SSH Keys Replace Passwords with Mathematical Proof
SSH connections without passwords use asymmetric cryptography with key pairs. The private key (id_rsa) signs authentication messages, while the corresponding public key (id_rsa.pub) verifies those signatures. The server stores public keys in ~/.ssh/authorized_keys—clients prove their identity by generating a signature with the private key without transmitting a password.
Article 1 explains port-based network communication. SSH extends these fundamentals with encrypted connections on port 22 using cryptographic authentication. An SSH client connects to 192.168.1.100:22 and performs a key exchange protocol—the mathematical proof of key ownership completely replaces password entry.
RSA-4096 keys provide 152-bit security against current attack methods. Ed25519 keys use elliptic curve cryptography with better performance while providing equivalent security. Running ssh-keygen -t ed25519 creates a 256-bit Ed25519 key in less than one second—RSA-4096 keys require several seconds to generate.
The SSH Agent Stores Decrypted Keys in Memory
Private SSH keys are typically stored encrypted with a passphrase. After you enter the passphrase once, the SSH agent loads these keys into memory and automatically signs SSH authentication requests. Running ssh-add ~/.ssh/id_ed25519 adds the key to the agent—subsequent SSH connections work without additional authentication.
SSH agent forwarding forwards local SSH keys across SSH connections. Running ssh -A user@server1 allows you to establish additional SSH connections from server1 using your local keys. The agent runs only on the local client—remote servers never receive private keys and can only submit signing requests.
Keychain and ssh-ident automate SSH agent management across shell sessions. These tools automatically start the SSH agent at login and load configured keys without additional user interaction. Desktop environments such as GNOME and KDE integrate the SSH agent into their keyring systems so that the passphrase only needs to be entered once through the graphical interface.
Key Generation Follows Cryptographic Standards
Ed25519 keys provide modern cryptography with an optimal security-to-performance balance:
ssh-keygen -t ed25519 -C "user@hostname-description"
This command creates ~/.ssh/id_ed25519 (private key) and ~/.ssh/id_ed25519.pub (public key). The comment parameter (-C) helps identify keys in authorized_keys files that contain multiple entries.
RSA keys require a minimum length of 4096 bits to provide adequate security:
ssh-keygen -t rsa -b 4096 -C "user@hostname-rsa"
ECDSA keys use elliptic curves with different curve sizes:
ssh-keygen -t ecdsa -b 256 -C "user@hostname-ecdsa"
The passphrase encrypts the private key using AES-128-CBC. Strong passphrases combine randomness and length—the Diceware method generates secure, memorable passphrases from word lists. An empty passphrase creates unencrypted private keys for automated systems.
Secure automation uses encrypted keys: SSH Agent with keychain loads keys once at login after the passphrase is entered. Desktop keyring systems (GNOME Keyring, KDE KWallet) store passphrases in encrypted form and automatically unlock SSH keys. systemd user services start ssh-agent with preloaded keys without requiring the passphrase to be entered repeatedly. Command-restricted keys execute only predefined commands instead of providing full shell access.
The Public Key Enables Server Access
The public key is stored in ~/.ssh/authorized_keys on the target server:
# Local public key
cat ~/.ssh/id_ed25519.pub
# Add it on the server
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG... user@hostname" >> ~/.ssh/authorized_keys
Each line in authorized_keys represents one authorized public key. The format is: key-type public-key comment. Multiple keys allow access from different clients or provide backup keys for emergencies.
ssh-copy-id automates key installation on remote servers:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@192.168.1.100
This command copies the specified public key to ~/.ssh/authorized_keys and sets the correct file permissions (600 for authorized_keys, 700 for the .ssh directory). The initial connection still requires password authentication.
Advanced Key Security and Restrictions
SSH keys support access restrictions directly within authorized_keys:
command="/usr/local/bin/backup-script",no-port-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... backup@client
from="192.168.1.0/24",no-agent-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... admin@workstation
Command restrictions execute only specific commands—the key can only run the defined backup script. The from restriction limits access to specific IP address ranges but also supports hostnames (from="workstation.example.com") and wildcards (from="*.company.com"). Dynamic IP addresses can introduce DNS caching issues—broader network ranges or VPN-based solutions are generally more reliable. These restrictions work independently of the SSH client configuration.
Certificate-based SSH authentication scales more effectively for large infrastructures. A certificate authority (CA) signs user keys with validity periods and access scopes. Servers trust the CA instead of individual public keys, so adding new users requires no server-side configuration.
FIDO2/WebAuthn hardware tokens provide physical two-factor authentication for SSH:
ssh-keygen -t ed25519-sk -C "user@hostname-yubikey"
These keys require a physical touch of the hardware token for every authentication. The private key never leaves the hardware token. Stolen “key files” contain only token references, which are useless without the physical token.
Monitoring and Auditing SSH Connections
SSH server logs in /var/log/auth.log (Debian/Arch) or /var/log/authlog (OpenBSD) show connection attempts and authentication events:
Feb 15 10:30:15 server sshd[1234]: Accepted publickey for admin from 192.168.1.50 port 54321 ssh2: ED25519 SHA256:abc123...
Feb 15 10:35:22 server sshd[5678]: Failed password for root from 203.0.113.10 port 12345 ssh2
These log entries identify successful key-based authentications and failed password attempts. SSH key fingerprints in the logs allow specific keys to be identified. Fail2ban automatically blocks IP addresses after repeated failed login attempts.
SSH session recording with the standard Unix script utility documents administrative activities:
script -t 2>timing.log -a session.log
# Administrative work
exit
These recordings make it possible to replay SSH sessions for auditing purposes. Centralized logging with rsyslog or journald collects SSH session records from multiple servers in one location.
LastLog and wtmp display different types of logins:
# All login sessions (including the local console)
last -i root
root tty1 0.0.0.0 Mon Sep 18 16:41 - 16:42 (00:01)
# Only direct root logins, not sudo privilege escalation
lastlog -u root
Username Port Latest
root **Never logged in**
lastlog records only direct logins (ssh root@server), not privilege escalation (sudo su -). This distinction is security-relevant: frequent root entries in lastlog may indicate direct SSH attacks against the root account, while sudo usage appears in separate logs.
Troubleshooting Common SSH Key Problems
The error Permission denied (publickey) is usually caused by incorrect file permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
SSH servers reject connections when security-related files have overly permissive permissions. World-readable private keys (644) or writable authorized_keys files (666) are ignored. These strict permissions prevent key compromise by other users.
SSH agent problems appear as connection errors:
ssh-add -l
Could not open a connection to your authentication agent.
# SSH still works with unencrypted keys
ssh server.example.com
Last login: Sun Sep 14 19:24:37 2025 from 192.168.1.50
OpenBSD 7.7 (GENERIC.MP) #2: Sun Jun 29 09:07:00 MDT 2025
The SSH agent is required only for encrypted keys protected by passphrases. Unencrypted keys work directly without an agent. For encrypted keys:
# Start the SSH agent
eval $(ssh-agent)
# Check SSH agent status
ssh-add -l
# Remove all keys
ssh-add -D
# Add the key again
ssh-add ~/.ssh/id_ed25519
The SSH_AUTH_SOCK environment variable contains the path to the SSH agent socket. Missing or incorrect values prevent communication with the SSH agent. New terminal sessions do not automatically inherit the SSH agent environment—keychain or ssh-ident solve this problem.
Host key verification failures occur when server keys change:
ssh-keygen -R hostname.example.com
ssh-keygen -R 192.168.1.100
These commands remove known host keys from ~/.ssh/known_hosts. Reinstalling a server or changing its IP address requires updating the host key. StrictHostKeyChecking=no disables verification but reduces protection against man-in-the-middle attacks.
Verbose SSH debugging output helps identify authentication problems:
ssh -vvv user@hostname
Triple-verbose mode displays detailed protocol negotiation, key attempts, and server responses. This output helps locate configuration errors, network problems, or server-side restrictions. Key exchange algorithms, cipher suites, and authentication methods are logged in full.
Next steps: