I've already written an entry on what SSH keys in your .ssh/config will be offered to servers , but it wasn't quite complete and I still managed to confuse myself about this recently. So today I'm going to try to write down in one place more or less everything I know about this.
Assuming that you're using
ssh-agent
and you don't have
IdentitiesOnly
set anywhere, the following is what keys will be offered to the remote server:
- All keys from
ssh-agent, in the order they were loaded intossh-agent. - The key from a
-iargument, if any. - Any key(s) from matching
HostorMatchstanzas in.ssh/config, in the order they are listed (and matched) in the file. Yes, all keys from all matching stanzas;IdentityFiledirectives are cumulative , which can be a bit surprising.(If there are no
IdentityFilematches in.ssh/config, OpenSSH will fall back to the default.ssh/id_*keys if they exist.)
(If you aren't using
ssh-agent
, only #2 and #3 are applicable and you can pretty much ignore the rest of this entry.)
If there is a '
IdentitiesOnly yes
' directive in any matching
.ssh/config
stanza (whether it is in a '
Host *
' or a specific '
Host <whatever>
'), the only keys from
ssh-agent
that will be offered in #1 are the keys that would otherwise be offered in both #2 and #3. Unfortunately
IdentitiesOnly
doesn't change the order that keys are offered in; keys in
ssh-agent
are still offered first (in #1) and in the order they were loaded into
ssh-agent
, not the order that they would be offered in if
ssh-agent
wasn't running.
Where the '
IdentitiesOnly yes
' directive comes from makes no difference, as you'd pretty much expect. The only difference between having it in eg '
Hosts *
' versus only (some) specific '
Host
<whatever>
' entries is how many connections it applies to. This leads to an important observation:
The main effect of a universal
IdentitiesOnlydirective is to make it harmless to load a ton of keys into yourssh-agent.
OpenSSH servers have a relatively low limit on how many public keys they will let you offer to them; usually it's six or less (technically it's a limit on total authentication 'attempts', which can wind up including eg a regular password). Since OpenSSH normally offers all keys from your
ssh-agent
, loading too many keys into it can cause authentication problems (how many problems you have depends on how many places you can authenticate to with the first five or six keys loaded). Setting a universal '
IdentitiesOnly yes
' means that you can safely load even host-specific keys into
ssh-agent
and still have everything usable.
(This is the
sshd
configuration directive
MaxAuthTries
.)
Note that specifying
-i
does not help if you're offering too many keys through
ssh-agent
, because the
ssh-agent
keys are offered first. You must enable
IdentitiesOnly
as well, either in
.ssh/config
or as a command line option. Even this may not be a complete cure if your
.ssh/config
enables too many
IdentityFile
directives and those keys are loaded into
ssh-agent
so that they get offered first.
If the key for
-i
is loaded into your
ssh-agent
, OpenSSH will use the
ssh-agent
version for authentication. This will cause a confirmation check if the key was loaded with '
ssh-add -c
' (and yes, this still happens even if the
-i
key is unencrypted).
(
ssh-agent
confirmation checks only happen when the key is about to be used to authenticate you, not when it is initially offered to the server.)
PS: you can see what keys you're going to be offering in what order with '
ssh -v -v ...
'. Look for the 'debug2: key: ...' lines, and also 'debug1: Offering ...' lines. Note that keys with paths and marked '
explicit
' may still come from
ssh-agent
; that explicit path just means that they're known through an
IdentityFile
directive.
Sidebar: the drawback of a universal
IdentitiesOnly
The short version is 'agent forwarding from elsewhere'. Suppose that you are on machine A, with a
ssh-agent
collection of keys, and you log into machine B with agent forwarding ( for whatever reason ). If machine B is set up with up with universal
IdentitiesOnly
, you will be totally unable to use any
ssh-agent
keys that machine B doesn't know about. This can sort of defeat the purpose of agent forwarding.
There is a potential half way around this, which is that
IdentityFile
can be used without the private key file. Given a stanza:
Host * IdentitiesOnly yes IdentityFile /u/cks/.ssh/ids/key-ed2
If you have a
key-ed2.pub
file but no
key-ed2
private key file, this key will still be offered to servers. If you have
key-ed2
loaded into your
ssh-agent
through some alternate path, SSH can authenticate you to the remote server; otherwise
ssh
will offer the key, have it accepted by the server, and then discover that it can't authenticate with it because there is no private key. SSH will continue to try any remaining authentication methods, including more identities.
(This is the inverse of how SSH only needs you to decrypt private keys when it's about to use them .)
However, this causes SSH to offer the key all the time, using up some of your
MaxAuthTries
even in situations where the key is not usable. Unfortunately, as far as I can tell there is no way to tell SSH 'offer this key only if
ssh-agent
supports it', which is what we really want here.