Informing the SSH agent of the target user at server

Hector Martin 'marcan' marcan at marcan.st
Wed Mar 21 21:24:29 AEDT 2018


On 2018-03-21 09:00, Damien Miller wrote:
> you should check out https://github.com/StanfordSNR/guardian-agent

Very nice trick. Requires a modified/bespoke client, of course, but it's
definitely a very powerful approach. I'm going to have customized
clients in some use cases anyway; I'll have to think about whether I can
use this in some cases.

> ATM it's hard because ssh only contacts the agent when it needs it and
> drops the connection immediately when done. To "pin" an agent request
> to a remote identity we'd either need to make the connections persistent
> and add an extension to inform the agent of the remote identity OR
> do this on every request.  The latter is probably easier. 
> 
> I.e. have ssh inject a
> 
> SSH_AGENTC_EXTENSION "remote-id at openssh.com" string("user at host")
> 
> before each agent request (ssh would need to eat the reply too) and the
> agent uses that to filter the keys it is prepared to send. Specifying
> which hosts a given key is allowed for could be done with a key
> constraint.

That sounds reasonable. If the extension and identity list request are
pipelined, it wouldn't introduce a latency penalty.

> It also limits the modifications needed to ssh. At present, ssh doesn't
> have any knowledge of what happens over the agent socket and, critically,
> doesn't inspect or modify messages there. This design would have it do a
> one-shot transaction whenever it opens the socket and then it can go back
> to not caring what happens there afterwards.

There are two independent ideas here: the ultimate ssh client asking the
agent for which specific key it needs, and intermediate (forwarding)
clients tagging the requests with what host they are being made on
behalf of. I was mostly asking about the former; the latter would be
useful too, but they're tangential.

So right now we just have

- SSH_AGENTC_REQUEST_IDENTITIES

But the final ssh could do (1):

- SSH_AGENTC_EXTENSION "remote-id at openssh.com" string("user at host")
- SSH_AGENTC_REQUEST_IDENTITIES

Or an intermediate forwarding ssh could insert a tag (2):

- SSH_AGENTC_EXTENSION "forwarded-for at openssh.com" string("user2 at host2")
- SSH_AGENTC_REQUEST_IDENTITIES

(which would of course nest with multiple chained forwards, similar to
SMTP Received headers)

Or we could have both at once (1+2)

- SSH_AGENTC_EXTENSION "forwarded-for at openssh.com" string("user2 at host2")
- SSH_AGENTC_EXTENSION "remote-id at openssh.com" string("user at host")
- SSH_AGENTC_REQUEST_IDENTITIES

I was asking about case 1 (merely filtering a potentially huge list of
identities to the appropriate one to log in to a given host), which does
not require any changes to the forwarding at all, but case 2 has value too.

Sidenote: I'd want more than a literal user at host string as the
remote-id. Port at least, but also hostkey and an extra freeform
option-specified tag (use case: things like GitHub, where the the key is
all that tells different users apart).

> The downside of this design is that it blurs the trust boundary for
> ssh-agent; no longer would it be making decisions solely on its own - it
> would be trusting ssh not to lie to it about the remote destination.

In my design, the idea is to simply use a separate key for each
user at host. Therefore, if something along the way lies, you just get the
wrong key which won't work on the actual host you're trying to connect
to. The agent would have its own policy and UI to ensure the user is
informed of (and acknowledges) what identity is being used (and
therefore what target is being connected to). This is why I expect to
have potentially hundreds/thousands of keys - one for each user at host.

> I had more grandiose plans to allow each sshd to sign agent requests
> with the hostkey as they passed through, to allow some sort of chain of
> trust. Unfortunately that would require fairly far reaching changes to
> the SSH protocol to enable binding those signatures to the transport
> instance over which they occur.

This sounds interesting. If you bound a *usage* of a key with a given
target user at host/hostkey (case 1 above), say by including constraints in
the to-be-signed message that sshd enforces and the agent can inspect
before signing it, it would allow use cases like having a single
identity that many hosts trust, while the agent can still verify and
apply policy on every individual use. This sounds "relatively" simple to
implement, though it would still require changes to the core protocol to
implement that idea of constraints (e.g. this signature is only valid
for this host key/username combo).

Binding the forwarding path cryptographically (2) sounds a lot more
involved. I guess you can try to enforce that there is a "secure path"
between the end-user/agent and the target host, but the actual transport
isn't end-to-end anyway (in the usual ssh a ssh b scenario). If you're
trying to have end-to-end security I think you'd just ProxyCommand your
way through and then you don't have to care about agent forwarding or
trusting intermediate servers, assuming you have your host key ahead of
time.

-- 
Hector Martin "marcan" (marcan at marcan.st)
Public Key: https://mrcn.st/pub


More information about the openssh-unix-dev mailing list