22

I've got a server which needs to be set up with the contents of two git repos which I host at github. I now want to add the ssh key of the server as deployment key to both the projects on github.

Unfortunately I'm getting an error saying Key is already in use, which according to this github page is because I can't add a deploy key to more than one repo.

I really wonder though; why is this a problem? Why can't one server have access to several repo's? What's the risk they're trying mitigate here?

kramer65
  • 50,427
  • 120
  • 308
  • 488

2 Answers2

20

That's not quite the right characterization of what it says on the GitHub page you linked. In fact, you can use the same ssh key for many different GitHub repositories. What you can't do is use one ssh key for many repositories and as what they call a "deploy key", nor use the same ssh key as some other user.

What's going on here is that GitHub's ssh server classifies incoming keys into one of two types:

  • An account key, which authenticates an incoming connection as you. You then have permissions on some wide (or narrow) swath of repositories, as controlled by each repository's "accounts that have access" settings. That is, the key itself is how they know you are kramer65 (or whatever your account name actually is there).
  • A deploy key, which authenticates an incoming connection as having access to one particular repository. That is, there's no "account" involved: it's just one key, attached to one specific repository.

There are also "machine users", but those are a form of account; I'm not sure whether GitHub even distinguishes those internally from regular account-keys. Because these are account-like rather than deploy-key-like, you can give them access to many different repositories. (This is probably what you want.)

I really wonder though; why is this a problem? Why can't one server have access to several repo's? What's the risk they're trying mitigate here?

They are not really protecting anything here. They are just letting you save, on GitHub, this one extra key, and for (your) convenience, do it without bothering to create an account. For (their) convenience, they then attach this one extra key to exactly one repository, which lets their ssh server—or really, what's right behind it after the key authenticates, i.e., the "login shell"—look up the one allowed repository without having to indirect through an "account" table first. When the incoming key is an account (or machine user) key, their ssh server, or what's right behind it, must look in this secondary table, to find the set of allowed repositories.

See https://developer.github.com/guides/managing-deploy-keys/#deploy-keys for details.

(There is no theoretical reason they could not allow a deploy key to automatically create an otherwise-anonymous "machine user" that is then automatically added to each repository, or removed from it, as you would like. However, that buys them nothing, since machine users already exist, and perform this same function. They can try to spin it as a security feature because it lets you know "hey, that key already means something to me" ... but if you have that key and aren't supposed to have that key, you can now find out what that one key actually unlocks, which if anything is somewhat anti-security. On the other hand, if you are supposed to have that key, and have simply forgotten which of your repositories it unlocks, that makes the system very difficult for you. This is typical of any security system though: the more secure you make it, the more inconvenient it is to actually use.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • 13
    Let me provide a tl;dr of the answer: It is because of some technical restriction that a regular user should not have to care about. – BillyTom Jan 31 '18 at 09:24
  • Sharing deploy keys (typically used in build/CI systems) between projects is a bad idea from security perspective, as a compromised build job could gain access to all those repos – Yarek T Feb 21 '19 at 10:15
  • @YarekT indeed, something other than a full-access key—such as a single-repository read-only-access deployment authorization string, i.e., a "deploy key"—is a good thing from a security perspective. The single-repository aspect is *probably* less important than the read-only aspect, and I'm not convinced GitHub actually enforces read-only access for deploy keys. – torek Feb 21 '19 at 16:04
  • 5
    This workflow becomes a problem when using automated systems and git submodules. You can't use the same deploy key in more than one repo, so the workaround becomes adding that key to their user account (or a dedicated machine account). Taking the least path of resistance, most users will add it to their own account resulting in a greater security risk. GitHub should rather let the user choose and assume the risk on a per repository basis... – tkeeler Mar 10 '20 at 20:40
  • 1
    @tkeeler: probably true, but I can't control either GitHub or users... :-) – torek Mar 10 '20 at 20:46
  • @YarekT what if you just want it to have access to one other repo? i.e. we have several app repos, and a "deploy assistant" repo that all app repos pull from in order to properly deploy (thereby eliminating duplicated deploy code in each repo) -- simply not having the *option* to add in the key in more than one spot seems stupid. – Jon May 14 '21 at 13:59
  • @Jon Yea I'm still on the fence about this: If you have a Deployer type of app, you should make it support cloning repos with specific deploy keys. It will also give you a chance to implement key rotation as well, all of that can be done via github APIs – Yarek T May 24 '21 at 09:02
  • 1
    @YarekT this situation is actually in reverse (the deployer does not clone other app repos which it then deploys), the app repo pulls the "deploy assistant". That's why it was called "assistant" and not "deployer". We actually do already have the former as well (with it managing deploy keys), but the apps need to rely on a centralized setup different from the deployer itself. I suppose a hack to this would be to have the deployer use one deploy key for the deploy-assistant, pull that in locally, then push the updated code to the target machines, rather than have them pull directly. – Jon May 24 '21 at 15:38
1

A shorter answer: the way GitHub wants you to handle this situation is to create a separate GitHub account to represent the server (GitHub calls this a "machine user", more info here), add the SSH key to that account, and add the account as a collaborator to the repos you want it to access. You'll need to remove the SSH key as a deploy key before GitHub will let you add it to the new machine user.

Nathan Wailes
  • 9,872
  • 7
  • 57
  • 95
  • But, in the case you want to access organization repos and that organization is paying for Team plan or Enterprise plan, it's not so good way of solving this problem, as you have to pay more – Luka Samkharadze Nov 18 '21 at 11:01