sftp: add --sftp-pin-host-key - Trust On First Use host key pinning

Add two new options, pin_host_key and host_keys, that
together provide a TOFU host-key validation mode for users who don't
maintain a known_hosts file. When --sftp-pin-host-key is used, rclone
records the server's host key into host_keys on the first successful
connection and verifies it on every subsequent connection.

host_keys is always validated when non-empty, so it can also be used
by hand to pin a known fingerprint without enabling TOFU writing.

known_hosts_file takes precedence if both are set. SSH host
certificates are rejected with a clear message pointing at
known_hosts_file. On-the-fly remotes log a warning since the captured
key cannot be persisted.
This commit is contained in:
Nick Craig-Wood
2026-07-27 14:57:21 +01:00
parent 83a366beae
commit b2aa82061f
3 changed files with 1104 additions and 18 deletions
+115 -7
View File
@@ -208,15 +208,25 @@ cat id_rsa-cert.pub id_rsa > merged_key
### Host key validation
By default rclone will not check the server's host key for validation. This
can allow an attacker to replace a server with their own and if you use
password authentication then this can lead to that password being exposed.
By default rclone will not check the server's host key for validation.
This can allow an attacker to replace a server with their own and if
you use password authentication then this can lead to that password
being exposed. Rclone will produce a warning `No host key validation
is being performed` each time the backend is started in this mode.
Host key matching, using standard `known_hosts` files can be turned on by
enabling the `known_hosts_file` option. This can point to the file maintained
by `OpenSSH` or can point to a unique file.
Host key matching, using standard ssh `known_hosts` files can be
turned on by enabling the `known_hosts_file` option. This can point to
the file maintained by `OpenSSH` or can point to a unique file.
e.g. using the OpenSSH `known_hosts` file:
Alternatively rclone can maintain server host keys in a `host_keys`
setting in the config file. This can be updated automatically with
`--sftp-pin-host-key`.
These options are described below
### Using the OpenSSH known_hosts file
Using the OpenSSH `known_hosts` file looks like this:
```ini
[remote]
@@ -266,6 +276,104 @@ and you will need to add the appropriate `@cert-authority` entry.
The `known_hosts_file` setting can be set during `rclone config` as an
advanced option.
### Host key pinning
As an alternative to maintaining a `known_hosts` file, rclone supports
Trust On First Use (TOFU) host key pinning via the `--sftp-pin-host-key`
command-line flag.
The recommended workflow is:
1. For the very first connection to a new remote, run rclone once with
`--sftp-pin-host-key`. Rclone records the server's host key into the
remote's `host_keys` config option and logs the SHA256 fingerprint:
```console
$ rclone --sftp-pin-host-key lsd remote:
2026/01/01 12:00:00 NOTICE: sftp://sftpuser@example.com:22/: Accepted ssh-ed25519 host key SHA256:abc... for example.com:22 on first use
2026/01/01 12:00:00 NOTICE: sftp://sftpuser@example.com:22/: Pinned ssh-ed25519 host key SHA256:abc... for example.com:22 in config
```
2. For every subsequent run, omit the flag. Rclone consults the pinned
`host_keys` and refuses the connection on any mismatch.
This is a strict improvement over the default of no host key validation,
but note that the first connection itself is unauthenticated. Rclone
detects later key changes, not a man-in-the-middle who is already on-path
the first time you connect. Ideally do the first connection over a trusted
network or cross-check the fingerprint rclone logs against one provided out
of band by the server operator.
If `known_hosts_file` is also set it takes precedence and
`--sftp-pin-host-key` is ignored.
After the first successful connection the config will contain a new line:
```ini
[remote]
type = sftp
host = example.com
user = sftpuser
pass =
host_keys = ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...
```
The `host_keys` field is always validated against the offered host key
when non-empty, so you can also pin a known key by hand without ever
running with the flag. Each entry is the complete public key - the
algorithm and base64 fields of a known_hosts line - not its SHA256
fingerprint:
```console
rclone config update remote host_keys "ssh-ed25519 AAAAC3..."
```
Setting `pin_host_key = true` persistently in the config file is not
recommended: while it is set, rclone will accept any new host key algorithm
the server later presents, widening the trust surface beyond the initial
pin. Using `--sftp-pin-host-key` as a one-shot flag keeps each
unauthenticated trust event a deliberate decision.
#### Re-pinning after a legitimate key change
If the server's host key is legitimately rotated, rclone will refuse the
connection with an error containing both the stored and offered SHA256
fingerprints. To accept the new key, clear the stored value and re-run once
with the flag:
```console
rclone config update remote host_keys ""
rclone --sftp-pin-host-key lsd remote:
```
Alternatively edit `host_keys` directly to replace or add the new entry.
Multiple entries (separated by commas) are supported.
#### Limitations
- If the server uses an `@cert-authority`-signed host certificate,
host key pinning cannot validate it (the certificate is re-issued
periodically even though the underlying CA is unchanged). Use
`known_hosts_file` with an `@cert-authority` entry instead.
- On-the-fly remotes (`:sftp,host=...:`) cannot persist the pinned key -
rclone will log a warning and re-accept the server key on every run,
so the flag only provides first-connect fingerprint logging. Named
remotes used with connection string overrides (`remote,port=2022:`)
are fine: the pinned key is saved to the remote's config section.
- If the `ssh` option is set, the configured ssh program makes the
connection and does its own host key validation, so `host_keys` is
not consulted and `--sftp-pin-host-key` pins nothing.
- Load-balanced SFTP endpoints that present a different host key per
backend node will produce a mismatch when a later connection lands on
a different node. Re-run with `--sftp-pin-host-key` after clearing
`host_keys`, or repeat the first-connect step until each node's key
has been observed, appending the additional entries to `host_keys` by
hand (comma-separated).
- rclone does not yet support OpenSSH's `hostkeys@openssh.com` extension,
the non-RFC mechanism that helps clients learn additional host keys
during rotation. This is being tracked upstream at
https://github.com/golang/go/issues/37245
### ssh-agent on macOS
Note that there seem to be various problems with using an ssh-agent on