[running on
OpenSSH_9.0, LibreSSL 3.6.0
OpenBSD 7.1-current (GENERIC.MP) #630: Mon Jul 18 09:28:20 MDT 2022
deraadt at amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP]
Hi,
I usually use distinct IdentityFile values for distinct sites without
IdentityAgent set or ssh-agent(1) running, so site A never sees login
attempts with !A keys.
Now I want to forward an agent containing keys for site B onto site A.
Logging into A shall only use its respective key and from A I want to
to be able to connect to B using the forwarded agent.
Having read ssh_config(5)'s ForwardAgent description, my impression was
that setting this option to a socket path should be enough, i.e.
$ ssh -oForwardAgent=/path/to/B.sock A
Testing however shows that ForwardAgent has no effect unless
IdentityAgent is set whatever yields the same socket.
This in turn causes SSH to use the identity agent for authentication
against A (explicitly undesired) and adding both A and B keys to the
agent forwarded would result in using both keys A and B for
authentication against B (explicitly undesired).
It is not obvious to me from the manual that ForwardAgent requires
IdentityAgent, neither does it make sense to me.
What is the benefit of overwriting IdentityAgent's socket path with
ForwardAgent=/path/to/sock?
Using IdentityAgent=yes|SSH_AUTH_SOCK|/path/to/sock together with
ForwardAgent=yes is clear, as that's simply how to use a single agent
for site A and whatever follows on site A.
Is this behaviour intended and thus possibly underdocumented?
Should the relatively new SSH agent restriction functionality be used
for usecases like mine?
Or can/should ForwardAgent work without IdentityAgent, i.e. can I simply
forward an agent without using it for the initial connection?
FWIW, here is how I tested against a default /etc/ssh/sshd_config config
on my local OpenBSD system:
1. create dummy site A (aka. localhost):
$ doas rcctl -f start sshd
$ cd `mktemp -d`
$ ssh-keygen -q -N '' -f ./A.key
$ cat ./A.key.pub >> ~/.ssh/authorized_keys
$ ssh -F none -i ./A.key localhost -- 'env | grep ^SSH'
SSH_CLIENT=127.0.0.1 41399 22
SSH_CONNECTION=127.0.0.1 41399 127.0.0.1 22
3. create dummy key and agent for site B:
$ ssh-keygen -q -N '' -f ./B.key
$ SSH_AUTH_SOCK=./B.sock ssh-add ./B.key
Identity added: ./B.key (./B.key)
4. login to A with key alone and forward agent B:
$ ssh -F none -i ./A.key -o IdentityAgent=none \
-o ForwardAgent=./B.sock localhost -- \
'env | grep ^SSH ; ssh-add -l'
SSH_CLIENT=127.0.0.1 19770 22
SSH_CONNECTION=127.0.0.1 19770 127.0.0.1 22
Could not open a connection to your authentication agent.
Adding `-vvv' here shows no debug log about IdentityAgent or
ForwardAgent whatsoever.
Neither does "enabling" IdentityAgent, i.e. using "yes" or
"/dev/null"
(whilst having SSH_AUTH_SOCK unset in, of course) work.
5. login to A with key and wrong agent B and forward agent B:
$ ssh -F none -i ./A.key -o IdentityAgent=./B.sock \
-o ForwardAgent=./B.sock localhost -- \
'env | grep ^SSH ; ssh-add -l'
SSH_AUTH_SOCK=/tmp/ssh-vaPtauEZPt/agent.80209
SSH_CLIENT=127.0.0.1 5081 22
SSH_CONNECTION=127.0.0.1 5081 127.0.0.1 22
3072 SHA256:mgkO5o+UnLNER2rh3uNkAJr0Zbbz0YKNBpBzawfuVBQ ./B.key (RSA)
Adding `-vvv' here shows how B.key is tried against A (undesired) and
A.key is used to login to A (as intended):
debug1: Will attempt key: ./B.key RSA
SHA256:mgkO5o+UnLNER2rh3uNkAJr0Zbbz0YKNBpBzawfuVBQ agent
debug1: Offering public key: ./B.key RSA
SHA256:mgkO5o+UnLNER2rh3uNkAJr0Zbbz0YKNBpBzawfuVBQ agent
...
debug1: Offering public key: ./A.key RSA
SHA256:dH9k2cvncTBOFjv+KWOqThAbZ6troMdfZuiW/Qp1aDs explicit
debug1: Server accepts key: ./A.key RSA
SHA256:dH9k2cvncTBOFjv+KWOqThAbZ6troMdfZuiW/Qp1aDs explicit
So this logging into B from A would now be possible, but not without
disclosing B.key to A.
I see https://www.openssh.com/agent-restrict.html describes host rules
to limit keys in a single agent.
In theory, I could probably use a single agent and implement my
desired separation between distinct sites with such rules, but that
seems a) more error prone to me and b) requires more duplication, e.g.
hostnames and their relation now have to be manually entered into
ssh-agent(1) with ssh-add(1)'s `-h'.
With ForwardAgent working independently of IdentityAgent, I can leave
all that to existing Host/Match blocks which would conditionally set
ForwardAgent.