How does ssh server know which public key to match the ssh private key?

Viewed 819

The server's authorized_keys contains tens of thousands keys, how does the server know which public key to match the current user's private key?

For example, normally the username is always git, how does the server know current user's identity?

enter image description here

Detail questions:

  • When I use ssh to pull the code by git pull, how does the server know that git pull is from which user?

  • And then how does the server get the public key associated with the user?

3 Answers

Because the public key is registered to the GitHub user account settings

https://github-images.s3.amazonaws.com/github-ae/assets/images/help/settings/ssh-key-paste.png

Usually, this kind of repository hosting service will populate its ~git/.ssh/authorized_keys with a SSH forced command:

command="/path/to/script userID",\
 no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty \
 ssh-rsa <yourPublicKey>

instead of:

 ssh-rsa <yourPublicKey>

It calls a script with your userId, associated to your public key.

That is how GitHub will associate git@github.com with your account.
Registering a public key in your account modifies the ~git/.ssh/authorized_keys with a command and the userID, not just the public key.

  • When I use ssh to pull the code by git pull, how does the server know that git pull is from which user?
  • And then how does the server get the public key associated with the user?

Actually GitHub gets your public key as part of the SSH transaction between you and GitHub: it then fetches your userID from its ~git/.ssh/authorized_keys

Finally, it checks if that user is authorized to clone/fetch/pull from the remote repository (which could be private, for instance, in which case the user better be the owner or a declared collaborator on that repository).

The short answer is that it doesn't. That answer is not very helpful, though.

Imagine you're an ssh server and you have just been handed a user name—which is always git at this point—and a public key.

You now look at ~git/.ssh/authorized_keys, which is a big file full of lines consisting of four space-sparated fields:

  • options
  • keytype
  • base64-encoded-key
  • comment

(though the options part can be omitted). The first important part here is the base64-encoded-key: this consists of the public key, plus some other stuff.

Now let's look at your question again:

The server's authorized_keys contains tens of thousands keys, how does the server know which public key to match the current user's private key?

It doesn't. It doesn't need to. It has two public keys in hand right now; it only needs to match the two public keys, which is easy, because they either match bit for bit, or don't. So all it has to do at this point is scan the entire authorized_keys file, line by line, checking: does this line have the same public key?

It will, of course, have to authenticate further: just having the public key doesn't mean that you are who you claim to be, yet. But this suffices for the first pass. Having found the (or "a") right line in the authorized_keys file, sshd can now use the options to decide who you are, if you pass the rest of the authentication process.

Logically:

  1. When you register your public key with GitHub, GitHub will associate the public key with your account.

  2. When you try to login to GitHub , you tell GitHub which public key to use in some way.

  3. GitHub then use the public key to authenticate you and you need to use the private key to complete the authentication process.

  4. If you pass the authentication, GitHub knows your account based on step 1.

SSH key authentication just makes the whole process implicit with only the first time setting up the keys explicitly.

Username/Password authentication is explicit for just every time.

Related: How does SSH public key authentication work (picking up right keys)

Related