Skip to main content

SSH host-key pinning

Qorionix records each machine's SSH host key the first time it reaches it, then refuses to connect if that machine ever presents a different one. How to confirm, and what a mismatch means.

Written for whoever runs IT9 min readUpdated

Every time Qorionix connects to one of your machines over SSH — to broker a session, to rotate a credential, or just to run the Test connection action on a target — the machine proves who it is with a host key. A host key is a cryptographic identity belonging to the machine itself rather than to any account on it: the server holds the private half and shows the public half to anybody who connects.

The problem is the very first connection. The first time we ever reach a given host and port we have nothing to compare against, so we have no way to tell the machine's own key from an impostor's. The answer Qorionix uses is the same one every SSH client uses, and it has a name: trust on first use. We record the key we are shown the first time, and from then on we check that every connection presents that same key. If a machine ever presents a different key, something has changed that we cannot verify — most innocently the machine was rebuilt, at worst something has placed itself between us and the server — and we refuse to connect rather than carry on and hand over a vaulted password.

This article is the whole feature: what happens on a first connection, how to confirm a fingerprint properly, what a mismatch looks like and what to do about it, how to resolve a genuine rebuild, and who is allowed to do any of it.

The first connection: trust on first use

There is nothing for you to do to start this. The first time any Qorionix SSH connection reaches a host and port, the key that host presents is recorded automatically, and the connection proceeds. No configuration, no import step, and no way to load a key ahead of time.

The new record appears in the SSH host keys table with a state of Unconfirmed, which means exactly what it says: we have written the key down and are now enforcing it, but nobody has yet checked that it is the right one. A Needs attention item is raised at the same time, asking you to confirm the fingerprint against the real machine. If your vault screen shows the Needs attention panel described in The credential vault, unconfirmed host keys appear there too, named individually rather than as a count.

Confirming a fingerprint

The table shows one row per host, with:

  • The host and port the key was recorded against.
  • The key type — the algorithm the key uses, such as ssh-ed25519, ssh-rsa or ecdsa-sha2-nistp256.
  • The fingerprint — a short cryptographic hash of the key. It is not secret: it is safe to read out over the phone, paste into a ticket or compare against a screen, and it is the thing you actually compare.
  • When it was first seen.
  • Its state — unconfirmed, confirmed, or a mismatch.

Confirming means comparing the fingerprint in the table against the fingerprint the machine itself reports, obtained by some route other than the connection you are trying to verify — which is the entire point. On a Linux server the usual method is to read it from the host's own public key file at the console or over a channel you already trust:

Reading a host's own fingerprint on the machine itself
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

# 256 SHA256:kQ7xR2mB9tYfL4nVdW8cJp1sHg3eZ0aUoI6bN5rTqXk root@app-01 (ED25519)

Whatever your usual out-of-band check is — a build record, a cloud provider's console output, a colleague at the rack — is equally fine. What matters is that it does not come down the same connection you are checking. When the two agree, use the Confirm fingerprint action on the row to mark the key trusted. Confirming also clears any past mismatch recorded against that host.

An unconfirmed key is still enforced. Confirming is not what switches the checking on — it is how you record that a human verified the key, so that the difference between we trusted whatever answered and somebody checked is visible on the screen and in the audit trail rather than being a matter of memory.

What a mismatch means, and what it looks like

If a host presents a fingerprint or a key type that differs from what is on file, the connection is refused outright — before any credential is sent. Nothing from the vault is decrypted, nothing is put on the wire, and no session is brokered. The refusal happens at the point the host's identity fails to match, which is the only point at which refusing still protects the secret.

In the table the host's state becomes a hard-refused mismatch, and the row shows both fingerprints: the one on record, and the newly presented one that was rejected. Seeing them side by side is usually how you work out what happened, because a rebuilt machine's new key is a perfectly ordinary key that simply is not the one we had.

A Needs attention item is raised as well, at a higher severity than an unconfirmed key — an unconfirmed key is an unfinished task, whereas a mismatch is an event. The wording is along these lines:

A machine presented a different SSH host key than the one recorded and was refused. If you rebuilt this server, this is expected. If you did not, treat it as a possible interception of privileged traffic and investigate before reconnecting.

Both readings are common and only you can tell them apart, so the honest guidance is a question rather than a procedure: did somebody rebuild, reimage, restore or replace that machine, or regenerate its host keys? If yes, this is expected and the next section is how you clear it. If nobody can account for the change, do not clear it. A refused connection costs you a rotation run or a session; carrying on regardless is how a vaulted administrator password reaches whoever is standing in the middle.

Forgetting a key: how you resolve a genuine rebuild

When a server really was rebuilt, the recorded key is simply out of date and the fix is to discard it. The Forget key action on the row removes the recorded key for that host entirely, after a confirmation that warns you to do this only for a server you rebuilt yourself.

Once forgotten, there is no record for that host, so the very next connection is a first connection again: whatever key the host presents is recorded and trusted, the state returns to unconfirmed, and a Needs attention item asks you to confirm it. The whole trust-on-first-use process starts over, including the part where you check the new fingerprint against the machine.

  1. Establish that the change is accounted for

    Find the person or the change record that explains why this machine's identity changed. If nobody can, stop here and investigate — the platform is currently protecting you and forgetting the key removes that protection.

  2. Forget the key

    Forget key on the host's row, and read the confirmation rather than clicking through it. This is the point of no return: the old fingerprint is gone and cannot be compared against afterwards.

  3. Reconnect once

    Run Test connection on the target, or let the next session or rotation run. That connection records the machine's new key.

  4. Confirm the new fingerprint

    Compare it against the rebuilt machine the same way you would a new host, and use Confirm fingerprint. Skipping this leaves the host permanently in the unconfirmed state, which works but records that nobody checked.

What the check covers

Every SSH connection Qorionix makes to a target, not just interactive ones:

  • Proxied sessions — see Proxied SSH sessions.
  • Credential rotation, including scheduled runs that nobody is watching. This is arguably where it matters most: rotation authenticates with the current password before setting a new one, so an unverified host is an unverified host being given a working administrator credential at three in the morning.
  • The Test connection action on a target, which is also the easiest way to record or re-record a key deliberately.

If this is not configured on a deployment

Host-key pinning either works fully or is switched off, and there is no state in between. On a deployment where it is not configured, every action in this article — listing keys, confirming a fingerprint, forgetting a key — is refused with a plain message saying the feature is not configured, rather than appearing to succeed.

That is worth knowing because the alternative is worse than an error. An action that quietly did nothing would leave you looking at a screen that says a key is confirmed when nothing was recorded, which is the kind of false assurance this whole feature exists to prevent. If you see that refusal on a deployment you run yourself, the checking is not happening either — treat it as a configuration gap to close, not as a screen to ignore.

Who can do this

The SSH host keys section requires the same access as managing privileged-access targets generally: pam:targets.read to see the table and the fingerprints, and pam:targets.write to confirm a fingerprint or forget a key. Both are administrator-only, and neither the member nor the viewer role holds the write half. See Who can see and do what.

The read side being administrator-only is the deliberate part. Fingerprints are not secret, but the table is a complete inventory of every machine Qorionix has ever reached over SSH, which is a map of your privileged estate whether or not any individual value in it is sensitive.

What to do next

  1. Open Privileged access → Targets and scroll to SSH host keys. Confirm every unconfirmed fingerprint against the machine while you still remember which servers are which.
  2. Read what a proxied SSH session does — this check is what stands between the vaulted password and whatever answers on the target's address.
  3. Read how a privileged session is started, including what a refused connection looks like from the requester's side.
  4. Read where the secrets themselves live, and check its Needs attention panel at the same time as this one.

Was this article wrong?

If a procedure here does not match what you see, or a limit we described has changed, tell us and we will fix the page. Email us about this article, or see how to get help if you need an answer rather than a correction.

Everything in privileged access