Guide · Backend
How SSH Works: Key Exchange, Host Keys, Channels and Agent Forwarding
25 min readUpdated By Saket Bhatnagar
Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.
In short
- How SSH works, in one line: your laptop and a server agree on fresh secret keys, the server proves who it is, then you prove who you are. SSH (Secure Shell) is the encrypted remote login tool developers use daily.
- Key exchange lets both sides build the same secret without ever sending it. OpenSSH, the common free SSH software, has defaulted since 9.0 to a hybrid method. It mixes a classic method with a post-quantum one, meant to resist future quantum computers.
- The host key is the server's long-term identity key. Your laptop stores it in a file called known_hosts on first contact and, by default, refuses to connect if it later changes.
- Public-key login means the server keeps your public key, and you prove you hold the matching private key by signing data tied to this one connection. Shells and tunnels then ride inside channels, numbered streams within one connection.
- Beginners can stop after the channels section. Engineers then get tested OpenSSH 10.5p1 runs on agent forwarding, which lets a middle server use your laptop's keys. In our runs, a forwarded agent let a jump host, the middle server, sign with the laptop's key. ProxyJump, which hops without lending keys, left no agent socket behind.
What goes wrong when you use SSH without knowing what it checks?
You type yes to prompts you cannot read, and you switch on options that let other machines use your keys. Understanding how SSH works tells you which prompts matter and which settings quietly widen your risk.
Picture a common setup. A small team runs its app servers on a private network with no public address. The only way in is a bastion host, one hardened server that faces the internet, also called a jump host. The setup is made up, but every command and output in this guide came from real runs.
Developers in setups like this make three common mistakes. They accept a new fingerprint without checking it. They add -A, the agent forwarding flag, which lets the bastion use the keys on their laptop to hop to an app server. When a warning about a changed host key appears, they delete the old line and carry on.
Each habit skips a check SSH was built to make. This guide walks through those checks in the order a connection makes them, using that same laptop, bastion and app server.
Which words do you need before learning how SSH works?
Eight words carry the whole guide. Each is tied to the laptop, bastion and app server.
- Client and server: the client is the program you run on your laptop, ssh. The server is the program on the remote machine that accepts logins, sshd.
- Key pair: two linked keys. Anyone may see the public key. The private key stays secret and can make signatures that the public key checks.
- Signature: a short value only the private key can produce for a given piece of data. Change one byte of the data and the check fails.
- Host key: the server's own long-term key pair. It answers the question am I talking to the real bastion?
- Fingerprint: a short hash of a public key, such as SHA256 followed by 43 characters. A hash is a fixed-length summary that changes completely if the input changes.
- Channel: one numbered stream inside an SSH connection, such as your shell or one forwarded port.
- Agent: ssh-agent, a background program that holds your unlocked private keys and signs on request.
- Jump host: a machine you pass through to reach another one, here the bastion.
How SSH works: what happens when you type ssh and press Enter?
Your laptop and the server run three protocols, one on top of the other. The SSH architecture standard, RFC 4251, names them: transport, user authentication and connection.
- Transport layer: agrees on encryption, builds fresh session keys and proves the server's identity with its host key.
- User authentication layer: proves who you are, usually with a key pair, over the now-encrypted link.
- Connection layer: splits the single encrypted link into channels for shells, file copies and tunnels.
You can watch every step with ssh -v, where v stands for verbose. Here is a trimmed copy from our run of the OpenSSH 10.5p1 client against a 10.5p1 server on the same machine. The address 127.0.0.1 means this machine, and port 2223 played the app server.
$ ssh -v -p 2223 [email protected] 'echo hello'
debug1: Remote protocol version 2.0, remote software version OpenSSH_10.5
debug1: kex: algorithm: mlkem768x25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: Server host key: ssh-ed25519 SHA256:UmwIWIe63UdOUXs7kn8INFoBZGiGwIwy+u74JtmixTQ
debug1: SSH2_MSG_NEWKEYS received
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/laptop/.ssh/id_ed25519 ED25519 SHA256:jJHi/JngFyrRJjBQrTbOkiqQhnJxaDkTf2mfFE2oU34 explicit
debug1: Server accepts key: /home/laptop/.ssh/id_ed25519 ED25519 SHA256:jJHi/JngFyrRJjBQrTbOkiqQhnJxaDkTf2mfFE2oU34 explicit
Authenticated to 127.0.0.1 ([127.0.0.1]:2223) using "publickey".
debug1: channel 0: new session [client-session] (inactive timeout: 0)
helloWhat just happened? The two sides swapped version banners, then ran a key exchange and switched on encryption at NEWKEYS. Only then did the laptop offer a public key, and the shell command ran inside channel 0.
One SSH login, message by message
Drag to exploreNotice that your identity is only sent after NEWKEYS, so the login itself is already encrypted. The server proves itself before you do.
Diagram connections:
- Version banners to Algorithm lists (pick shared algorithms)
- Algorithm lists to Client key share (agree on mlkem768x25519)
- Client key share to Server reply (server proves identity)
- Server reply to NEWKEYS (client checks known_hosts)
- NEWKEYS to Public-key login (now encrypted)
- Public-key login to Channel open (user accepted)
- Version banners: Laptop → Server and back: SSH-2.0 and software name
- Algorithm lists: Laptop → Server and back: KEXINIT offers
- Client key share: Laptop → Server: the laptop's public share
- Server reply: Server → Laptop: share, host key, signature
- NEWKEYS: Laptop → Server and back: encryption switches on
- Public-key login: Laptop → Server: signature over session ID
- Channel open: Laptop → Server: session channel 0 for the command
| Line in ssh -v | Layer | What it means |
|---|---|---|
| Remote protocol version 2.0 | Transport | Both sides speak SSH version 2, the only version RFC 4253 defines. |
| kex: algorithm: mlkem768x25519-sha256 | Transport | The key exchange method both sides picked from their lists. |
| Server host key: ssh-ed25519 SHA256:... | Transport | The fingerprint your laptop compares with known_hosts. |
| cipher: [email protected] | Transport | The encryption used for the rest of the connection in our run. |
| Authentications that can continue: publickey | User authentication | The login methods this server allows; ours had passwords off. |
| Server accepts key | User authentication | The server found your public key in its allowed list. |
| channel 0: new session | Connection | Your command or shell got its own stream. |
What is key exchange in SSH, and why is the key never sent?
Key exchange is a method where each side sends a public share, and both compute the same secret from the two shares. Someone who records the shares cannot compute the secret with today's computers.
The SSH transport standard, RFC 4253, then hashes the version banners, algorithm lists, host key, both shares and the shared secret into one value called the exchange hash. The first exchange hash becomes the session identifier, a fingerprint of this one connection. The encryption keys come from hashing the shared secret with that exchange hash.
The server then signs the exchange hash with its host key, and your laptop checks that signature. That proves the holder of the host key took part in this exact exchange. A signature from yesterday's connection would not fit, because every exchange hash is different.
Why does OpenSSH use a post-quantum key exchange?
A large future quantum computer could break today's classic key exchange maths. Recorded traffic could then be decrypted years later, an attack OpenSSH calls store now, decrypt later.
OpenSSH's answer is a hybrid method that combines a classic exchange with a post-quantum one. Its post-quantum page says the hybrid is no worse than the classic method, even if the new part were broken. The same page says a hybrid has been the default since 9.0, in April 2022, and mlkem768x25519-sha256 since 10.0, in April 2025.
We checked what older clients get. Ubuntu 24.04's OpenSSH 9.6p1 client, talking to our 10.5p1 server, negotiated [email protected], the earlier hybrid. Its default list has no ML-KEM method at all. ML-KEM is the post-quantum half of mlkem768x25519-sha256.
Since 10.1, the client also warns when the connection falls back to a classic method. We made a 10.5p1 server offer only curve25519-sha256 and got this on screen:
** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.htmlPause and predict: what happens if you set KexAlgorithms yourself to that classic method? In our run, no warning appeared. The 10.5p1 source only warns when you have not chosen key exchange methods explicitly.
In 10.5p1, the WarnWeakCrypto setting in ssh_config, the client config file, can switch the warning off. If you see it on a real server, upgrading that server is the better fix. Since 10.6, which we did not test, sshd has its own WarnWeakCrypto setting and logs such connections by default.
The standard also recommends changing keys after each gigabyte of data or each hour, whichever comes first. This is called rekeying, and it happens inside the same connection.
What is an SSH host key, and what does the fingerprint prompt protect?
The host key is the server's long-term identity, and the fingerprint prompt is your one chance to check it. Without that check, anyone between you and the server could pretend to be it.
RFC 4253 says the client should verify that the host key really belongs to the server. Skipping that check leaves the protocol open to active attacks, where someone in the middle relays and reads everything.
By default, OpenSSH uses the first model RFC 4251 describes: a local list of host names and their keys. OpenSSH also supports host certificates signed by a certificate authority, the second model. On first contact it shows the fingerprint and asks. After you say yes, it saves a line like this in ~/.ssh/known_hosts:
[127.0.0.1]:2223 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIARUCA9...The square brackets and port appear because our server did not use port 22. Upstream OpenSSH stores host names in plain text by default. Ubuntu's own ssh_config switches on HashKnownHosts, so on Ubuntu the line starts with a hashed name.
What happens when the host key changes?
We replaced the app server's host key and connected again. The 10.5p1 client refused and exited with status 255:
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Host key for [127.0.0.1]:2223 has changed and you have requested strict checking.A rebuilt server is the usual cause, but the warning cannot tell the two cases apart. Confirm the new fingerprint through another channel before you remove the old line.
The StrictHostKeyChecking setting controls this behaviour. The default, ask, prompts for new hosts and refuses changed keys. accept-new saves new hosts without asking but still refuses changed keys, which suits automation. Setting it to no weakens both checks.
How do you check a fingerprint the first time?
Get the real fingerprint from the server side
Ask whoever built the bastion, or read it on the server console with ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub. Use a channel an attacker cannot easily fake.
Connect and read the prompt
The prompt shows a line such as ED25519 key fingerprint is SHA256 followed by 43 characters. Compare every character, not just the start.
Answer yes only on a match
OpenSSH then writes the host key to ~/.ssh/known_hosts. Future connections check it silently.
Check your result
Run ssh-keygen -F with the host name to print the saved line. For a non-standard port, quote it as [host]:port. In our run, ssh-keyscan piped into ssh-keygen -lf printed the same SHA256 value as the server's key file.
How does SSH public key authentication work?
The server keeps a copy of your public key, and you prove you hold the private half by signing data tied to this connection. Your private key never leaves your laptop.
Your public keys live in ~/.ssh/authorized_keys on the server, one per line. The user authentication standard, RFC 4252, makes publickey the one method every server must support. Passwords are optional.
Login runs in two moves, and our ssh -v output showed both. First OpenSSH asks whether a key is acceptable, and the server answers yes, which prints Server accepts key. Then the client signs, and the server checks the signature.
The signed data starts with the session identifier from the key exchange. A signature captured from one connection therefore cannot be replayed on another. This detail matters again when we reach agent forwarding.
Which SSH key type should you create in 2026?
Create an Ed25519 key unless a system forces something else. In our 10.5p1 run, ssh-keygen with no -t flag made an Ed25519 key, and the ssh-keygen manual lists ed25519 as the default.
$ ssh-keygen -t ed25519 -C laptop-key
$ ssh-keygen -lf ~/.ssh/id_ed25519.pub
256 SHA256:jJHi/JngFyrRJjBQrTbOkiqQhnJxaDkTf2mfFE2oU34 laptop-key (ED25519)Set a passphrase when asked. It encrypts the private key file on disk, and the manual warns that a lost passphrase cannot be recovered. The private file began with BEGIN OPENSSH PRIVATE KEY and had mode 600, readable only by you.
| Key type | Status in our runs | Use it? |
|---|---|---|
| ed25519 | Default in 10.5p1; standardised for SSH in RFC 8709 | Yes, for almost everyone. |
| ed25519-sk | Key lives on a hardware security key; listed by ssh -Q key | Yes, if you own such a token. |
| rsa | Logins worked with rsa-sha2-512 signatures | Only for old systems that need it. |
| rsa with ssh-rsa signatures | Refused by the 10.5p1 server: Permission denied | No. SHA-1 signatures are off since 8.8. |
| dsa | 10.5p1 said unknown key type dsa; 9.6p1 still made one | No. Removed in 10.0. |
| mldsa44-ed25519 | Listed by 10.5p1 as experimental; 10.6 enabled it under a new name; logins not tested | Not yet for most people. |
An RSA key and an ssh-rsa signature are different things, which confuses many people. RFC 8332 kept the RSA key format and added rsa-sha2-256 and rsa-sha2-512 signatures. Our RSA key logged in fine until we forced the old SHA-1 signature.
What are SSH channels, and how do tunnels share one connection?
A channel is a numbered stream inside one encrypted SSH connection. RFC 4254 says all terminal sessions and forwarded connections are channels, and many can run at once.
Each channel has its own window, a byte allowance the other side may send before it must wait. This is how SSH controls flow for each stream separately.
Port forwarding, also called tunnelling, uses channels to carry ordinary network traffic through SSH. There are three kinds, and we ran each one.
| Flag | Direction | Channel type in our logs | Typical use |
|---|---|---|---|
| -L 9000:127.0.0.1:8000 | Laptop port 9000 reaches server-side port 8000 | direct-tcpip | Open an internal dashboard or database from your laptop. |
| -R 9100:127.0.0.1:7000 | Server port 9100 reaches laptop port 7000 | forwarded-tcpip | Show a local dev server to a remote machine. |
| -D 1080 | Laptop SOCKS proxy; each request names its own destination | not logged at -v in our run | Browse an internal network through the server. |
In the -L run, a web service listened only on the server's loopback address, so nothing outside could reach it. Fetching port 9000 on the laptop returned its page, and the client log said channel 1: new direct-tcpip.
By default, sshd's GatewayPorts setting is no. A remote forward then listens only on the server's loopback address, not on its public interfaces.
How a local port forward rides one SSH connection
Drag to exploreNotice that the internal service only ever sees a connection from the server itself. The laptop-to-server hop is one encrypted connection carrying both channels.
Diagram connections:
- Browser on laptop to ssh -L listener (plain TCP on laptop)
- ssh -L listener to Encrypted SSH connection (data in channel 1)
- Encrypted SSH connection to sshd on app server (decrypted at server)
- sshd on app server to Internal service (plain TCP on server)
- Browser on laptop: Opens 127.0.0.1:9000
- ssh -L listener: Laptop port 9000; one channel per connection
- Encrypted SSH connection: Channel 0 shell, channel 1 direct-tcpip
- sshd on app server: Opens TCP to 127.0.0.1:8000 for you
- Internal service: Listens on server loopback only
Can several sessions share one login?
Yes, with connection multiplexing. ControlMaster in ssh_config keeps one authenticated connection open, and later ssh commands open new channels on it instead of logging in again.
We started a master with ControlMaster=yes and ControlPersist=30, then ran a second command. Its log said mux_client_request_session, and it never offered a key. ssh -O check reported Master running.
Beginners can stop here. The rest covers ssh-agent, agent forwarding and the safer ways to reach a server behind a bastion.
What is ssh-agent, and what does agent forwarding really expose?
ssh-agent holds your unlocked private keys and signs on request, so you type a passphrase once. Agent forwarding lets a remote machine send it signing requests too.
The agent never hands out keys. Its manual says passphrases and private keys never go over the network. Programs talk to it through a socket, a special file whose path sits in the SSH_AUTH_SOCK variable. Since 10.1, that socket lives under ~/.ssh/agent instead of /tmp.
With -A, sshd on the remote machine creates a matching socket there. Anything that can open that socket can ask your laptop's agent to sign, for as long as your connection stays open.
What we saw on the bastion with agent forwarding on
We logged in to our test bastion with -A and looked around. Both test servers ran on one machine, on ports 2222 and 2223. These were the results:
- SSH_AUTH_SOCK on the bastion pointed to a socket inside /home/learner/.ssh/agent, the login user's directory.
- ssh-add -l on the bastion listed the laptop's Ed25519 key, though no private key file existed there.
- From the bastion, ssh to the app server succeeded. The bastion had used the laptop's agent to sign.
The ssh manual states the risk plainly. Users who can bypass file permissions on the remote host can use your agent through the forwarded connection. They cannot copy your keys, but they can use them to log in wherever those keys work.
On a shared bastion, root, the all-powerful admin account, can always bypass file permissions. So can an attacker who has gained root or your account there. The agent protocol standard, RFC 9987, calls this a transitive trust relationship and advises against forwarding to hosts you do not fully trust.
Here is one analogy, used only for this section. The agent is a notary in your pocket who stamps documents but never lends the stamp. Agent forwarding runs a phone line from the bastion to that notary.
Anyone in the bastion's room can phone in stamp requests while the line is open. Where the picture breaks: a real notary might ask why, but a plain agent signs every request unless you set limits.
Recall the session-bound signature from earlier. It stops replay, but it does not stop someone on the bastion from asking your agent for a fresh signature for a new connection they open.
Is ProxyJump safer than agent forwarding?
Yes, for reaching a server through a bastion. ProxyJump makes the bastion relay encrypted bytes, while your laptop logs in to the app server directly with its own keys.
The -J flag, or ProxyJump in ssh_config, opens a connection to the bastion first. It then asks the bastion for a direct-tcpip channel to the app server and runs a second, complete SSH session through it.
Our verbose log showed the mechanism. OpenSSH turned -J into a hidden helper command, ssh -W followed by the target address, which joins its input and output to that channel. The second login printed Authenticated to 127.0.0.1 (via proxy).
On the app server, SSH_AUTH_SOCK was empty. While the session ran, the bastion account had no agent socket directory at all. The bastion carried the inner session's traffic but never held its keys.
Two ways to reach the app server through a bastion
Drag to exploreNotice that only the forwarded agent leaves a signing socket on the bastion. With ProxyJump the bastion moves encrypted bytes it cannot read.
Diagram connections:
- Laptop with ssh-agent to Which flag? (you choose)
- Which flag? to Bastion with -A (ForwardAgent)
- Which flag? to Bastion with -J (ProxyJump)
- Bastion with -A to App server (bastion asks your agent)
- Bastion with -J to App server (laptop logs in end to end)
- Laptop with ssh-agent: Holds the only private key
- Which flag?: -A then ssh again, or -J
- Bastion with -A: Gets an agent socket for your session
- Bastion with -J: Relays one direct-tcpip channel
- App server: Sees a normal public-key login
The manual entry for -A ends with the same advice: a safer alternative may be to use a jump host. This config made the safe path the default for our app server. We checked it with ssh -G, which prints the settings ssh would use:
Host bastion
HostName bastion.example.com
User deploy
ForwardAgent no
Host app1
HostName 192.0.2.15
User deploy
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesWith this file, ssh app1 goes through the bastion with no agent forwarding. ssh -G app1 printed proxyjump bastion and forwardagent no. The same shape, pointed at our two local servers, reached the app server with an empty SSH_AUTH_SOCK.
ProxyJump does not make the bastion harmless. It still sees who connects where and when, and a broken bastion can block access. It just never gets the power to sign as you.
When you must forward an agent, how do you limit the damage?
Restrict which keys go into the agent, where they may be used and for how long. Some jobs, such as pulling from git with your own key on a remote machine, are easiest with a forwarded agent.
Destination-constrained keys
Since OpenSSH 8.9, ssh-add -h ties a key to named hosts. The agent then checks every hop of the path against those rules, using host keys from known_hosts.
We tested four cases with a key restricted to our bastion only:
- Laptop to bastion: allowed, as the rule said.
- Laptop straight to the app server: Permission denied (publickey).
- Forwarded to the bastion, then on to the app server: refused. ssh-add -l on the bastion even said The agent has no identities.
- After adding a second rule allowing the bastion-to-app-server hop: the same hop worked.
The hop rule is written as the first host, a greater-than sign, then the next host. The ssh-add manual shows it with host-b and host-c. Both ends need OpenSSH support for this to work over a forwarded agent.
The design page for this feature names its limits. A hostile hop can still use keys allowed through it, and the rules cover login signatures only, not other signing.
Other limits worth setting
- ssh-add -t sets a lifetime. In our run, a key added with -t 2 was gone three seconds later.
- ssh-add -c asks you to confirm each use through a pop-up program called ssh-askpass. The design page warns such prompts are somewhat easy to phish.
- Forward a smaller agent. ForwardAgent accepts a socket path, so you can forward a second agent holding one low-value key. In our run, ssh-add -l on the bastion then listed only that key.
- Hardware security keys that need a touch per signature add a physical step, though the design page says they are similarly phishable.
On the server side, sshd's AllowAgentForwarding defaults to yes. Its manual notes that turning it off does not improve security unless users are also denied shell access, as they can install their own forwarders.
Which sshd settings matter most on a server you run?
A handful of sshd_config defaults decide most of your exposure. These come from the sshd_config manual as of 29 October 2026, and sshd -T printed the same values on 10.5p1 unless our test file changed them.
| Setting | Default | What to consider |
|---|---|---|
| PasswordAuthentication | yes | Set no once everyone uses keys; it stops password guessing. |
| PermitRootLogin | prohibit-password | Root may log in with keys only. Set no if admins use their own accounts. |
| AllowAgentForwarding | yes | Only meaningful together with blocking shell access. |
| AllowTcpForwarding | yes | Same note; DisableForwarding switches off all forwarding at once. |
| GatewayPorts | no | Keep no so remote forwards stay on loopback. |
If you came here from our guide on the October 2026 OpenSSH compression side channel, this is the protocol underneath it. The 10.6 release notes say it disabled the LZ77 part of SSH compression. Attacker-controlled input could otherwise reveal secrets through the length of encrypted packets.
How do you explain how SSH works in a system design interview?
Walk through the layers in order, then show you know the trade-offs around access to private networks. This frame fits in about two minutes.
Name the three layers
Transport for encryption and server identity, user authentication for the client, and connection for channels. Each layer runs inside the one below.
Explain key exchange
Both sides compute a shared secret from public shares and derive session keys. Mention that OpenSSH has defaulted to a hybrid post-quantum method since 9.0, and to mlkem768x25519-sha256 since 10.0.
Explain host keys
The server signs the exchange hash with its host key. The client checks it against known_hosts, or a certificate authority in larger fleets.
Explain public-key login
The client signs data that includes the session identifier, so signatures cannot be replayed. The server checks authorized_keys.
Describe channels
Shells, file copies and port forwards are channels with their own flow-control windows on one connection.
Design access through a bastion
Recommend ProxyJump over agent forwarding, short-lived or destination-constrained keys, and passwords off. Note the bastion still sees connection metadata.
Questions people ask
- How does SSH work in simple words?
- SSH builds an encrypted connection, checks the server's identity, then checks yours. First both sides run a key exchange to create secret session keys without sending them. The server signs that exchange with its host key, which your laptop compares with known_hosts. Then you sign data tied to this connection with your private key. Shells and tunnels finally run as channels inside the encrypted connection.
- Is it safe to type yes at the SSH fingerprint prompt?
- It is safe only if the fingerprint matches one you got from a trusted place. The prompt appears because your laptop has never seen that server's host key. Compare it with the value from the server console or from your admin. Typing yes blindly means a fake server on the first connection would be trusted from then on.
- What does REMOTE HOST IDENTIFICATION HAS CHANGED mean?
- It means the server sent a different host key from the one saved in your known_hosts file. Usually the server was rebuilt or its keys were regenerated. It can also mean someone is intercepting the connection, and SSH cannot tell which. Confirm the new fingerprint through another channel, then remove the old line with ssh-keygen -R and the host name.
- Is SSH agent forwarding dangerous?
- It can be, on any host you do not fully trust. While you are connected with -A, anyone who can open the forwarded socket on that host, such as root, can ask your agent to sign logins. They cannot copy your private key, but they can use it. Prefer ProxyJump, and if you must forward, restrict keys with ssh-add -h and -t.
- What is the difference between ProxyJump and ForwardAgent?
- ProxyJump relays your connection through a bastion, while ForwardAgent lends the bastion your agent. With ProxyJump, your laptop logs in to the final server itself, and the bastion only moves encrypted bytes. With ForwardAgent, you log in to the bastion and run ssh there, so the bastion signs with your laptop's keys. In our tests, ProxyJump left no agent socket anywhere.
- Which SSH key type should I use in 2026?
- Use Ed25519 for normal work, as of October 2026. It is the default in current OpenSSH, and its public key is only 32 bytes. Use a hardware-backed ed25519-sk key if you have a security key. Keep RSA only for old systems, and drop DSA, which OpenSSH 10.0 removed.
- Does SSH protect against quantum computers?
- Its key exchange is designed to, by default, in current OpenSSH. Since 10.0, OpenSSH defaults to mlkem768x25519-sha256, which mixes a classic and a post-quantum method, aimed at keeping recorded traffic safe if large quantum computers arrive. Older servers may fall back to a classic method, and clients from 10.1 onward warn about that. Post-quantum signatures are newer and still rolling out.
Sources and further reading
- RFC 4251: The SSH Protocol Architecture (three layers, host key trust models)
- RFC 4252: SSH Authentication Protocol (publickey method, signed data, PK_OK)
- RFC 4253: SSH Transport Layer Protocol (exchange hash, session identifier, key derivation, rekeying)
- RFC 4254: SSH Connection Protocol (channels, windows, direct-tcpip, tcpip-forward)
- RFC 8332: Use of RSA Keys with SHA-256 and SHA-512 in SSH
- RFC 8709: Ed25519 and Ed448 Public Key Algorithms for SSH
- RFC 9987: Secure Shell (SSH) Agent Protocol, May 2026 (forwarding and transitive trust)
- OpenSSH release notes (10.0 ML-KEM default and DSA removal, 10.1 warning and agent socket move, 10.6)
- OpenSSH: Post-quantum cryptography page
- OpenSSH 8.8 release notes (ssh-rsa SHA-1 signatures disabled by default)
- OpenSSH 8.9 release notes (ssh-agent restriction system)
- OpenSSH: SSH agent restriction design page (limits of destination constraints)
- OpenSSH manual: ssh(1) (-A warning, -J, -L, -R, -D, verifying host keys)
- OpenSSH manual: ssh_config(5) (ForwardAgent, ProxyJump, StrictHostKeyChecking, WarnWeakCrypto)
- OpenSSH manual: sshd_config(5) (server defaults, forwarding notes)
- OpenSSH manual: ssh-agent(1) (socket location, keys never sent)
- OpenSSH manual: ssh-add(1) (-h destination constraints, -c, -t)
- OpenSSH manual: ssh-keygen(1) (default key type, fingerprints, passphrases)
- OpenSSH portable source at V_10_5_P1: PROTOCOL.agent (session-bind extension)
- OpenSSH portable source at V_10_5_P1: sshconnect.c (when the post-quantum warning prints)