hselbie
hselbie

Reputation: 1879

Setting up multiple SSH key access to Github

I'm trying to configure a remote linux machine to access two distinct git accounts which I own. I keep getting authentication access manifesting in.

> git push
ERROR: Repository not found.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Steps i've taken,

  1. Generated a two sets of ssh keys (call them key1 and key2)
  2. Generated a config file at ~/.ssh/config
  3. Edited that file
    1 # Default github account: key1
      2 Host github.com
      3    HostName github.com
      4    IdentityFile ~/.ssh/key1
      5    IdentitiesOnly yes
      6
      7 # Other github account: key2
      8 Host github-key2
      9    HostName github.com
     10    IdentityFile ~/.ssh/key2
     11    IdentitiesOnly yes
  1. Added the .pub version to my two git accounts under the user account settings/ssh keys.
  2. Added them on my VM with ssh-add ~/.ssh/key1

I'm unsure really where to go from here and what the next steps are for why this isn't working. I feel like there might be a step i'm missing.

Upvotes: 4

Views: 5757

Answers (2)

DanielT
DanielT

Reputation: 61

I have created a .zsh script that will prompt the user a ssh key just for GitHub when running git clone or git push. All the other git commands remain the same. You can even pass the standard flags with no issue and select the key with the keyboard arrows.

git_sshprompt.zsh

#!/bin/zsh

# Colors for the terminal output
COLOR_RESET="\033[0m"
COLOR_GREEN="\033[32m"
COLOR_YELLOW="\033[33m"
COLOR_CYAN="\033[36m"
COLOR_BLUE="\033[34m"
COLOR_RED="\033[31m"
COLOR_BOLD="\033[1m"

# Emojis for enhanced user experience
EMOJI_GITHUB="🍏"
EMOJI_SELECT="🔑"
EMOJI_ERROR="❌"
EMOJI_SUCCESS="✅"
EMOJI_ARROW="➡️"  # Right arrow emoji

# Path to the SSH config file
SSH_CONFIG="$HOME/.ssh/config"
declare -A SSH_KEYS
index=1

if [[ ! -f $SSH_CONFIG ]]; then
    echo -e "${EMOJI_ERROR} ${COLOR_RED}${COLOR_BOLD}SSH config file not found at $SSH_CONFIG.${COLOR_RESET}"
    exit 1
fi

# Initialize variables
is_github=false

# List all available IdentityFile keys for HostName github.com
echo -e "${EMOJI_GITHUB} ${COLOR_CYAN}${COLOR_BOLD}Available SSH identities for github.com:${COLOR_RESET}"
while read -r line; do
    # Check for Host github.com
    if [[ $line =~ ^Host\ github\.com ]]; then
        is_github=true
    elif [[ $is_github == true && $line =~ ^IdentityFile ]]; then
        key_path=${line#IdentityFile }
        SSH_KEYS[$index]=$key_path
        echo -e "  ${COLOR_YELLOW}${COLOR_BOLD}[$index]${COLOR_RESET} $key_path"
        ((index++))
    elif [[ $is_github == true && -z $line ]]; then
        # Stop collecting when we reach an empty line or another Host block
        is_github=false
    fi
done < $SSH_CONFIG

if [[ ${#SSH_KEYS[@]} -eq 0 ]]; then
    echo -e "${EMOJI_ERROR} ${COLOR_RED}${COLOR_BOLD}No IdentityFile entries found for github.com in $SSH_CONFIG.${COLOR_RESET}"
    exit 1
fi

# Check if the Git command is 'git push' or 'git clone'
if [[ "$1" == "push" ]]; then
    # For git push, no repository URL is needed
    echo -e "${EMOJI_ARROW} ${COLOR_BOLD}Select an SSH identity for git push:"
elif [[ "$1" == "clone" && -z "$2" ]]; then
    # If git clone is called but no URL is provided
    echo -e "${EMOJI_ERROR} ${COLOR_RED}${COLOR_BOLD}No repository URL provided for git clone. Exiting.${COLOR_RESET}"
    exit 1
elif [[ "$1" == "clone" && -n "$2" ]]; then
    # If git clone is called and a URL is provided
    echo -e "${EMOJI_ARROW} ${COLOR_BOLD}Select an SSH identity for git clone:"
else
    # For other commands (git pull, git fetch, etc.), skip the prompt
    command git "$@"
    exit 0
fi

# Use fzf for selecting the SSH key, but stay in the same window
selected_key=$(printf "%s\n" "${(@)SSH_KEYS[@]}" | fzf --height 20 --border --ansi \
    --prompt="${EMOJI_ARROW} Select an SSH identity: " --preview "echo {}")

if [[ -z $selected_key ]]; then
    echo -e "${EMOJI_ERROR} ${COLOR_RED}${COLOR_BOLD}No SSH key selected. Exiting.${COLOR_RESET}"
    exit 1
fi

# Display the selected SSH key
echo -e "${EMOJI_SUCCESS} ${COLOR_GREEN}${COLOR_BOLD}You selected SSH key:${COLOR_RESET} $selected_key"

# Check if repository URL is provided (only for git clone)
if [[ "$1" == "clone" && -n "$2" ]]; then
    repo_url=$2
    # Check for additional flags or arguments and pass them along with the git command
    shift 2  # Remove 'clone' and the URL from the arguments
    echo -e "${EMOJI_ARROW} ${COLOR_BOLD}Cloning repository: $repo_url${COLOR_RESET}"
    GIT_SSH_COMMAND="ssh -i $selected_key" git clone "$repo_url" "$@"
elif [[ "$1" == "push" ]]; then
    # For git push, no URL is required, so just set the SSH key and push with any flags
    shift 1  # Remove 'push' from the arguments
    echo -e "${EMOJI_ARROW} ${COLOR_BOLD}Pushing changes to the remote repository${COLOR_RESET}"
    GIT_SSH_COMMAND="ssh -i $selected_key" git push "$@"
fi

.zshrc

git_with_key() {
    # Check if the command is 'git clone' or 'git push'
    if [[ "$1" == "clone" || "$1" == "push" ]]; then
        # Call the script to prompt for SSH key selection, passing all arguments
        $ZSH_CUSTOM/plugins/gitssh/git_sshprompt.zsh "${(@)argv}"
    else
        # Otherwise, run the regular git command
        command git "$@"
    fi
}

# Make sure to replace the regular git command with the git_with_key function
alias git="git_with_key"

git clone example git clone example

git push example git push example

Upvotes: 0

user15965983
user15965983

Reputation: 126

tl;dr: Add the following entry to your ~/.ssh/config where $user is the GitHub username and $key is the private key specified for that user and defined in the setting for that GitHub user:

Host github.com-$user
    Hostname github.com
    User git
    IdentityFile ~/.ssh/$key
    IdentitiesOnly yes

Then, configure your git remote URL:

git remote add origin [email protected]$user:$user/$repo

Basically, I had a long-running SSH key for work/personal projects, then wanted to add a new key for unrelated side projects. I did all of the steps you outlined in your question, and still got the same error. Doing $ GIT_SSH_COMMAND='ssh -v' git fetch showed that git was passing my main user's private key first, and even though it was authenticating correctly as a valid key, that user of course had no permissions on the new user's private repositories.

Relevant post: https://medium.com/@ordinary.yobi/multiple-ssh-keys-on-github-f75a372d5374

Upvotes: 11

Related Questions