Search code examples
gitgithubssh-keysssh-agent

Cloning (updating) git submodule fails when two ssh-keys are loaded at the same time in ssh-agent


I am working on a couple of maven-projects where common java-classes is placed in a submodule. The submodule is then added to each maven-project and the project is cloned from a private github-repo to a docker container.

I have created a ssh-key for each project and the submodule, added the public key to 'Deploy keys' in 'Settings' in the github-repo. All keys are created without a password.

Downloading the main-repo went fine but adding the submodule failed with [email protected]: Permission denied (publickey).. And hence the compile failed. Both keys were loaded before cloning the repo and updating the submodule.

It turns out I can have only one key loaded at a time. So I modified the script that clone so it unload all keys before loading the key for the submodule.

eval $(ssh-agent -s)
ssh-add /home/docker/.ssh/id_ed25519_maven_repo
ssh-keyscan -H github.com >> /home/docker/.ssh/known_hosts

cd /home/docker/code
git clone [email protected]:foo/main.git
cd main

ssh-add -D   <--- Unload all keys ---
ssh-add /home/docker/.ssh/id_ed25519_submodule
git submodule init
git submodule update

mvn compile

Why must I unload and load before updating the submodule instead of having both keys loaded at the same time?

(spent hours troubleshooting)


Solution

  • It sounds like you have two SSH keys that are either associated with different GitHub accounts or that are deploy keys with different repositories. If so, the reason this happens is due to the SSH protocol.

    When any user wants to connect to a remote machine via SSH using an SSH key, the authentication happens before any command is sent or anything is known about the desired behavior. In this case, all users connect to the git user on github.com, so the only way to distinguish users and the access which they have is by the SSH key. If you authenticate with a particular key and that key is valid for some access, GitHub will accept it, and then if it is not valid for what you want to access, then it will reject your request.

    Since the SSH protocol does not allow specifying the resource to access until authentication has completed, GitHub has no way to know that you really wanted to use a different key to access that resource, one which does indeed have the ability to access it.

    If you need to use multiple SSH keys for different resources, that case is covered in the Git FAQ:

    For example, you could write something like the following in ~/.ssh/config, substituting the proper private key file:

    # This is the account for author on git.example.org.
    Host example_author
        HostName git.example.org
        User git
        # This is the key pair registered for author with git.example.org.
        IdentityFile ~/.ssh/id_author
        IdentitiesOnly yes
    # This is the account for committer on git.example.org.
    Host example_committer
        HostName git.example.org
        User git
        # This is the key pair registered for committer with git.example.org.
        IdentityFile ~/.ssh/id_committer
        IdentitiesOnly yes
    

    Then, you can adjust your push URL to use git@example_author or git@example_committer instead of [email protected] (e.g., git remote set-url git@example_author:org1/project1.git).