Como dizer ao git qual chave privada usar?


646

sshtem a -iopção de informar qual arquivo de chave privada usar ao autenticar:

-i identity_file

    Seleciona um arquivo a partir do qual a identidade (chave privada) para autenticação RSA ou DSA é lida. O padrão é ~/.ssh/identitypara a versão 1 do protocolo ~/.ssh/id_rsae ~/.ssh/id_dsapara a versão 2. do protocolo. Os arquivos de identidade também podem ser especificados por host no arquivo de configuração. É possível ter várias -iopções (e várias identidades especificadas nos arquivos de configuração).

Existe uma maneira semelhante de saber gitqual arquivo de chave privada usar em um sistema com várias chaves privadas no ~/.sshdiretório?



Respostas:


671

Em ~/.ssh/config, adicione:

host github.com
 HostName github.com
 IdentityFile ~/.ssh/id_rsa_github
 User git

Agora você pode fazer git clone [email protected]:username/repo.git.

NOTA: Verifique se as permissões no IdentityFile são 400. O SSH rejeitará, de maneira não claramente explícita, as chaves SSH que são legíveis demais. Será apenas uma rejeição de credencial. A solução, neste caso, é:

chmod 400 ~/.ssh/id_rsa_github

117
E se você precisar se conectar ao mesmo host com chaves diferentes?
Valentin Klinghammer 30/11/2012

6
@Quelltextfabrik - você pode adicionar outra seção com um anfitrião diferente: nerderati.com/2011/03/…
Ben Challenor

1
@Cliff Nop, na minha página de manual: " HostName: Especifica o nome real do host no qual efetuar login. Isso pode ser usado para especificar apelidos ou abreviações para hosts." Minha versão do ssh é openssh-6.7p1.
Grissiom

11
Se o arquivo de configuração for novo, não esqueça de fazer #chmod 600 ~/.ssh/config
elysch 15/03

2
@ValentinKlinghammer a resposta da @Flimm tem a solução para esta pergunta. É para usar a core.sshCommandconfiguração do git. superuser.com/a/912281/162466
VasyaNovikov

345

Variável de ambiente GIT_SSH_COMMAND:

No Git versão 2.3.0, você pode usar a variável de ambiente GIT_SSH_COMMANDassim:

GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example" git clone example

Observe que -iàs vezes pode ser substituído pelo seu arquivo de configuração; nesse caso, você deve fornecer ao SSH um arquivo de configuração vazio, como este:

GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example -F /dev/null" git clone example

Configuração core.sshCommand:

Na versão 2.10.0 do Git, você pode configurar isso por repo ou globalmente, para não precisar mais definir a variável de ambiente!

git config core.sshCommand "ssh -i ~/.ssh/id_rsa_example -F /dev/null"
git pull
git push

1
Eu tinha que exportar o shell variável para uma variável de ambiente para fazer este trabalho, isto é export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example", em seguida,git clone example
Abdull

7
@ Abdull No Bash, fazer a atribuição na mesma linha que o comando exporta a variável de ambiente apenas para esse comando. Experimente: example=hello /usr/bin/env | grep example.
Flimm

3
as coisas tornaram-se ainda melhor: a partir Git 2.10, você pode armazenar o comando na sua configuração de Git: stackoverflow.com/a/38474220/520162
Eckes

2
@Noitidart /dev/nullé apenas um nome de arquivo válido em sistemas operacionais semelhantes ao UNIX, não funciona no Windows.
Flimm

2
Para mim GIT_SSH_COMMANDnão funcionou até que eu usei IdentitiesOnly, como este comando: GIT_SSH_COMMAND="ssh -i ~/.ssh/mysubdir/id_rsa -o 'IdentitiesOnly yes'" git push.
Tyler Collier

111

Não uma maneira direta de saber gitqual chave privada usar, porque ela depende sshda autenticação do repositório. No entanto, ainda existem algumas maneiras de atingir seu objetivo:

Opção 1: ssh-agent

Você pode usar ssh-agentpara autorizar temporariamente sua chave privada.

Por exemplo:

$ ssh-agent sh -c 'ssh-add ~/.ssh/id_rsa; git fetch [email protected]'

Opção 2: GIT_SSH_COMMAND

Passe os argumentos ssh usando a GIT_SSH_COMMANDvariável de ambiente (Git 2.3.0+).

Por exemplo:

$ GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \
  git clone [email protected]

Você pode digitar tudo isso em uma linha - ignore $e deixe de fora o \.

Opção 3: GIT_SSH

Passe os argumentos ssh usando a GIT_SSHvariável de ambiente para especificar o sshbinário alternativo .

Por exemplo:

$ echo 'ssh -i ~/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $*' > ssh
$ chmod +x ssh
$ GIT_TRACE=1 GIT_SSH='./ssh' git clone [email protected]

Nota: As linhas acima são linhas de comando shell (terminal) que você deve colar no seu terminal. Eles criarão um arquivo chamado ssh, o tornarão executável e (indiretamente) o executarão.

Nota: GIT_SSHestá disponível desde a v0.99.4 (2005).

Opção 4: ~/.ssh/config

Use o ~/.ssh/configarquivo conforme sugerido em outras respostas para especificar o local da sua chave privada, por exemplo

Host github.com
  User git
  Hostname github.com
  IdentityFile ~/.ssh/id_rsa

1
//, mas se a sua identidade no ssh-agent for encaminhada, como nesta pergunta? superuser.com/questions/971732/…
Nathan Basanese 11/11/15

1
Permiti-me reformatar este post: na IMO, essa é de longe a resposta mais abrangente. Em seu design original, uma varredura rápida sugeria que o post descrevesse uma única solução complicada para o problema, então eu a perdi.
Alberto

3
$ ssh-agent sh -c 'ssh-add ~/.ssh/id_rsa; git fetch [email protected]'trabalhou para mim quando nada mais faria. Parabéns.
22417 Daniel Dewhurst

1
Eu tive que usar ~/.ssh/configmétodo, env vars não funcionou para mim ...
Greg Dubicki

1
GIT_SSHestá disponível desde a v0.99.4 (agosto de 2005) , então basicamente desde que o Git existe (abril de 2005).
Dominik

32

Escreva um script que chame sshcom os argumentos desejados e insira o nome do arquivo do script $GIT_SSH. Ou apenas coloque sua configuração ~/.ssh/config.


2
Outra explicação de como fazer isso.
Sithsu

1
~/.ssh/configÉ o caminho a percorrer.
Hek2mgl # 8/15

Trabalho em uma máquina (A) da qual git push para um servidor (B) que aceita apenas autenticação de chave ssh. Enquanto meu ~ / .ssh / setup de configuração em (A) funciona perfeitamente bem quando eu trabalhar diretamente sobre essa máquina, isso não acontece quando eu entrar de algum outro local (C). Usando $GIT_SSHe um script resolveu esse problema. Obrigado!
precisa saber é

18

Se você não deseja especificar variáveis ​​de ambiente sempre que executar o git, não deseja outro script de wrapper, não pode / não pode executar o ssh-agent (1) nem deseja fazer o download de outro pacote apenas para isso, use o git -remote-ext (1) transporte externo:

$ git clone 'ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git'
Cloning into 'repository'
(...)
$ cd repository
$ git remote -v
origin  ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git (fetch)
origin  ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git (push)

Considero esta solução superior porque:

  • É específico do repositório / remoto
  • Evite o inchaço do script do wrapper
  • Não precisa do agente SSH - útil se você quiser clones / push / pull autônomos (por exemplo, no cron)
  • Definitivamente, nenhuma ferramenta externa é necessária

2
Esta resposta foi exatamente o que eu precisava para forçar o gitrecurso do Chef a usar chaves de implantação específicas do repositório para clonar / buscar em repositórios particulares do Github. A vantagem adicional desse método sobre o ambiente / script é que, como o caminho da chave é codificado na configuração do repositório de trabalho, ele usará a mesma chave no clone inicial e nas buscas / empurrões subsequentes.
Adam Franco

2
UAU! Isso é ótimo, não sabia disso. Obrigado pela resposta, bastante útil também em ambientes fantoches, para evitar o incômodo extra de gerenciar .ssh/configetc. +1!
gf_

1
Esta solução não funciona junto com o sinalizador --recursive. Os submódulos não são buscados usando a chave especificada e, portanto, falham se exigirem autenticação.
Daniele Testa

1
Cada submódulo é um repositório totalmente diferente, com seu próprio conjunto de controles remotos. Eles são colados pelo Git para sua conveniência, mas os controles remotos de um submódulo não estão vinculados aos do repositório pai. Receio que você deve configurar o controle remoto usando o exttransporte em cada submódulo para que a recursão no pai funcione.
flaviovs

2
Se você encontrar o seguinte erro fatal: transport 'ext' not allowed, precisará colocar o protocolo ext na lista de permissões via export GIT_ALLOW_PROTOCOL=ext. Basicamente, o auxiliar remoto do git-remote-ext (que suporta URLs "ext :: ssh example.com% S foo / repo") permite a execução arbitrária de comandos. Isso normalmente nem sempre é uma preocupação, porque o usuário sempre vê e confia no URL que passa para o git. No entanto, os submodules git, por meio do arquivo .gitmodules, permitem que um invasor solicite ao cliente que busque URLs git arbitrários. hackerone.com/reports/104465
Gomino

18

Use a configuração personalizada do host ~/.ssh/config, desta forma:

Host gitlab-as-thuc  
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa.thuc
    IdentitiesOnly yes

use seu nome de host personalizado assim:

git remote add thuc [email protected]:your-repo.git  

2
Esta é a resposta que eu estava procurando, pois tenho contas GitHub separadas para casa e trabalho. Eu só precisava definir Host work.github.com HostName github.com IdentityFile ~/.ssh/worke substituir "github.com" por "work.github.com" sempre que clonar um repositório de trabalho. Ele ainda se conecta ao "github.com", mas usando um par de chaves não padrão.
Mikkel

1
O URL para detalhes (" itblog.study.land / ..." ) não funciona mais :(
Carl Smotricz

@CarlSmotricz o original foi movido para cá: medium.com/@thucnc/…
thucnguyen

4
FINALMENTE!!! Esta resposta realmente mostra como você pode utilizar o que coloca no ~/.ssh/configarquivo. Todas as outras respostas perdem como você pode definir o host ao adicionar a origem, o que automaticamente permite que o git use o arquivo de chave correto. OBRIGADO!!
precisa saber é o seguinte

1
Bom, era isso que eu estava procurando :)
Lucas D'Avila

15

Depois da minha luta, $GIT_SSHeu gostaria de compartilhar o que funcionou para mim.

Pelos meus exemplos, assumirei que você tem sua chave privada localizada em/home/user/.ssh/jenkins

Erro a evitar: o valor GIT_SSH inclui opções

$ export GIT_SSH="ssh -i /home/user/.ssh/jenkins"

ou qualquer falha semelhante, pois o git tentará executar o valor como um arquivo . Por esse motivo, você deve criar um script.

Exemplo de trabalho do script $ GIT_SSH /home/user/gssh.sh

O script será chamado da seguinte maneira:

$ $GIT_SSH [[email protected]]host [-p <port>] <command>

Um exemplo de trabalho de script pode ter a seguinte aparência:

#!/bin/sh
ssh -i /home/user/.ssh/jenkins $*

Observe o $*no final, é parte importante disso.

Uma alternativa ainda mais segura, que impediria qualquer possível conflito com qualquer coisa no seu arquivo de configuração padrão (além de mencionar explicitamente a porta a ser usada) seria:

#!/bin/sh
ssh -i /home/user/.ssh/jenkins -F /dev/null -p 22 $*

Assumindo que o script esteja /home/user/gssh.sh, você deve:

$ export GIT_SSH=/home/user/gssh.sh

e tudo deve funcionar.


Obrigado. Apenas observe: use "$ @" em vez de $ * para argumentos de passagem, pois o primeiro se comporta corretamente quando os argumentos contêm espaços em branco.
Piotr Findeisen 31/03

@PiotrFindeisen Obrigado pela sua observação. No entanto, eu não entendo completamente - no zsh, isso me ajuda a manter as cordas com espaço em uma peça, mas no bash não. Você pode me dizer mais ou apontar para alguma explicação? Não quero adicionar algumas modificações às cegas.
Jan Vlcinsky

Você deve remover a primeira metade da sua resposta. Ninguém está interessado em uma solução que não funcione, e é uma leitura perdida que ofusca a resposta correta na parte inferior, que funciona maravilhosamente.
Cerin

@ Cerin Se você quer dizer remover o "Erro a evitar", vou mantê-lo lá. Ele compartilha armadilhas comuns a serem evitadas e é muito curto. Tenho certeza de que alguém tentaria otimizar a solução, fornecendo todas as coisas em variáveis ​​(isso aconteceu comigo), então tentei encurtar o caminho para o sucesso.
Jan Vlcinsky

5

Você pode apenas usar ssh-ident em vez de criar seu próprio wrapper.

Você pode ler mais em: https://github.com/ccontavalli/ssh-ident

Carrega chaves ssh sob demanda quando necessário, uma vez, mesmo com várias sessões de login, xterms ou casas compartilhadas NFS.

Com um pequeno arquivo de configuração, ele pode carregar automaticamente chaves diferentes e mantê-las separadas em agentes diferentes (para encaminhamento de agente), dependendo do que você precisa fazer.


5

Eu tinha um cliente que precisava de uma conta separada no github. Então, eu precisava usar uma chave separada apenas para este projeto.

Minha solução foi adicionar isso ao meu .zshrc / .bashrc:

alias infogit="GIT_SSH_COMMAND=\"ssh -i ~/.ssh/id_specialkey\" git [email protected]"

Sempre que eu quero usar o git para esse projeto, substituo "infogit" por git:

infogit commit -am "Some message" && infogit push

Para mim, é mais fácil lembrar.


4

Então, defino a variável env GIT_SSH como $HOME/bin/git-ssh.

Para que a minha configuração de repositório determine que identidade ssh usar, meu ~/bin/git-ssharquivo é o seguinte:

#!/bin/sh
ssh -i $(git config --get ssh.identity) -F /dev/null -p 22 $*

Então eu tenho uma configuração global de configuração do git:

$ git config --global ssh.identity ~/.ssh/default_id_rsa

E dentro de qualquer repositório git, posso apenas definir um ssh.identityvalor de configuração local do git:

$ git config --local ssh.identity ~/.ssh/any_other_id_rsa

Voila!

Se você pode ter um endereço de email diferente para cada identidade, fica ainda mais simples, porque você pode apenas nomear suas chaves após seus endereços de email e solicitar ao user.e do git config. Email conduz a seleção de chaves da ~/bin/git-sshseguinte maneira:

#!/bin/sh
ssh -i $HOME/.ssh/$(git config --get user.email) -F /dev/null -p 22 $*

2

Minha solução foi esta:

crie um script:

#!/bin/bash
KEY=dafault_key_to_be_used
PORT=10022 #default port...
for i in [email protected];do
   case $i in
    --port=*)
        PORT="${i:7}";;
    --key=*)KEY="${i:6}";;
   esac
done
export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/${KEY} -p ${PORT}"
echo Command: $GIT_SSH_COMMAND

quando você precisar alterar a execução var:

. ./thescript.sh [--port=] [--key=]

Não esqueça o ponto extra !! isso faz o script definir os ambientes variados !! --key e --port são opcionais.


2

Geralmente, você deseja usar ~/.ssh/configpara isso. Simplesmente emparelhe os endereços do servidor com as chaves que você deseja usar para eles da seguinte maneira:

Host github.com
  IdentityFile ~/.ssh/id_rsa.github
Host heroku.com
  IdentityFile ~/.ssh/id_rsa.heroku
Host *
  IdentityFile ~/.ssh/id_rsa

Host *denota qualquer servidor, então eu o uso para definir ~/.ssh/id_rsacomo a chave padrão a ser usada.


2

Eu desenvolvo o @shellholic e esse tópico SO com algumas dicas. Eu uso o GitHub como exemplo e suponho que você tenha uma chave privada ~/.ssh/github(caso contrário, consulte este tópico do SO ) e que você adicionou a chave pública ao seu perfil do GitHub (caso contrário, consulte a ajuda do GitHub ).

Se necessário, crie um novo arquivo de configuração SSH em ~/.ssh/confige altere as permissões para 400

touch ~/.ssh/config
chmod 600 ~/.ssh/config

Adicione isso ao ~/.ssh/configarquivo:

Host github.com
    IdentityFile ~/.ssh/github
    IdentitiesOnly yes

Se você já possui uma configuração remota, convém excluí-la, caso contrário, você ainda poderá solicitar o nome de usuário e a senha:

git remote rm origin

Em seguida, adicione um controle remoto ao repositório git e observe os dois pontos antes do nome do usuário:

git remote add origin [email protected]:user_name/repo_name.git

E então os comandos git funcionam normalmente, por exemplo:

git push origin master
git pull origin 

@HeyWatchThis neste encadeamento SO sugeriu a adição IdentitiesOnly yespara impedir o comportamento padrão do SSH de enviar o arquivo de identidade correspondente ao nome do arquivo padrão para cada protocolo. Veja esse tópico para mais informações e referências.


Este foi o meu erro: "Se você já tem um controle remoto configurado ...". Muito obrigado!!!
Allan Andrade

erro comum --- esta é a resposta
Goddard

1

Basta usar ssh-agente ssh-addcomandos.

# create an agent
ssh-agent

# add your default key
ssh-add ~/.ssh/id_rsa

# add your second key
ssh-add ~/.ssh/<your key name>

Depois de executar os comandos acima, você pode usar as duas teclas ao mesmo tempo. Apenas digite

git clone [email protected]:<yourname>/<your-repo>.git

clonar seu repositório.

Você precisa executar o comando acima depois de reiniciar sua máquina.


Explique o processo, incluindo Como posso criar um agente
Srikrushna 06/04

0

Estou usando o git versão 2.16 e não preciso de um único pedaço de script, nem mesmo de um comando config ou modificado.

  • Apenas copiei minha chave privada para .ssh / id_rsa
  • definir permissões para 600

E o git lê a chave automaticamente. Eu não pergunto nada e não gera um erro. Apenas funciona bem.


Você notou que a pergunta é sobre "um sistema com várias chaves privadas no ~/.sshdiretório"?
Scott

0

Embora a pergunta não solicite, estou incluindo esta resposta para qualquer pessoa que esteja procurando resolver o mesmo problema especificamente para o .

A solução gitlab

Tentei usar a abordagem de , mas mesmo a documentação do git recomenda usar ~/.ssh/configalgo além do simples caso. No meu caso, estou para um servidor - e queria fazê-lo como um usuário específico - que é definido pela durante a e não pelo nome de usuário git. Uma vez implementado, basta executar o seguinte:

~/myrepo> git mycommit -m "Important Stuff"
~/myrepo> git mypush
[proceed to enter passphrase for private key...]

Configuração

Lembre-se da localização da sua /myfolder/.ssh/my_gitlab_id_rsa no meu caso.

Adicione uma entrada em ~/.ssh/config:

Host gitlab-delegate
    HostName gitlab.mydomain.com
    User git
    IdentityFile /myfolder/.ssh/my_gitlab_id_rsa
    IdentitiesOnly yes

Adicione o em ~/.gitconfig:

mypush = "!f() { \
           path=$(git config --get remote.origin.url | cut -d':' -f2); \
           branch=$(git rev-parse --abbrev-ref HEAD); \
           git remote add gitlab_as_me [email protected]:$path && \
           git push gitlab_as_me $branch && \
           git pull origin $branch; \
           git remote remove gitlab_as_me; \
         }; f"

Como bônus, eu realizo meus commits neste mesmo host que um usuário específico com este :

mycommit = "!f() { \
             git -c "user.name=myname" -c "[email protected]" commit \"[email protected]\"; \
           }; f"

Explicação

Todas as opções acima assumem que o controle remoto é originrelevante e que o ramo relevante está atualmente com check-out. Para referência, encontrei vários itens que precisavam ser abordados:

  • A solução requer a criação de um novo controle remoto gitlab_as_me, e eu não gostei de ver o controle remoto extra pendurado na minha árvore de logs, então removo-o quando terminar
  • Para criar o controle remoto, é necessário gerar a URL do controle em tempo real - no caso do gitlab, isso foi alcançado com um simples do bash
  • Ao executar um push, gitlab_as_mevocê precisa ser específico sobre qual ramo você está empurrando
  • Depois de executar o push, seu originponteiro local precisa ser "atualizado" para corresponder gitlab_as_me(o que git pull origin $branchfaz isso)

0

Quando você tem várias contas git e deseja uma chave ssh diferente

Você deve seguir o mesmo passo para gerar a chave ssh, mas não se esqueça de

ssh-keygen -t ed25519 -C "[email protected]" 

Digite o caminho que você deseja salvar (por exemplo: my-pc / Desktop / .ssh / ed25519)

Adicione a chave pública ao seu gitlab ( Como adicionar a chave ssh ao gitlab )

Você precisa da nova identidade ssh usando o comando abaixo

ssh-add ~/my-pc/Desktop/.ssh/ed25519

(1) Você está citando alguém ou algo? Nesse caso, identifique a fonte. Caso contrário, não use formatação de cotação. (2) O que é "ed25519"? ……………………………… Por favor, não responda nos comentários; edite  sua resposta para torná-la mais clara e completa.
Scott

0
    # start :: how-to use different ssh identity files

    # create the company identity file
    ssh-keygen -t rsa -b 4096 -C "[email protected]"
    # save private key to ~/.ssh/id_rsa.corp, 
    cat ~/.ssh/id_rsa.corp.pub # copy paste this string into your corp web ui security ssh keys

    # create your private identify file
    ssh-keygen -t rsa -b 4096 -C "[email protected]"
    # save private key to ~/.ssh/id_rsa.me, note the public key ~/.ssh/id_rsa.me.pub
    cat ~/.ssh/id_rsa.me.pub # copy paste this one into your githubs, private keys

    # clone company internal repo as follows
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.corp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git clone [email protected]:corp/project.git

    export git_msg="my commit msg with my corporate identity, explicitly provide author"
    git add --all ; git commit -m "$git_msg" --author "MeFirst MeLast <[email protected]>"
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.corp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git push 
    # and verify 
    clear ; git log --pretty --format='%h %ae %<(15)%an ::: %s

    # clone public repo as follows
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.corp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git clone [email protected]:acoolprojectowner/coolproject.git

    export git_msg="my commit msg with my personal identity, again author "
    git add --all ; git commit -m "$git_msg" --author "MeFirst MeLast <[email protected]>"
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.me -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git push ; 
    # and verify 
    clear ; git log --pretty --format='%h %ae %<(15)%an ::: %s

    # stop :: how-to use different ssh identity files
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.