Ao fazer a ssh'ing, como posso definir uma variável de ambiente no servidor que muda de sessão para sessão?

92

Quando entro sshem um servidor, como posso passar uma variável de ambiente do cliente para o servidor? Essa variável de ambiente é alterada entre diferentes invocações do ssh, portanto não quero sobrescrever $HOME/.ssh2/environmenttoda vez que faço uma chamada ssh. Como posso fazer isso?

Ross Rogers
fonte
2
Sua pergunta precisa ser um pouco mais específica.
Ignacio Vazquez-Abrams
3
A pergunta estava clara o suficiente para mim. No entanto, na sshpágina de manual, não vejo outra maneira de fazer isso além de definir a variável manualmente após o login no servidor, a menos que você modifique ~ / .ssh2 / environment.
garyjohn
É uma variável diferente a cada vez? Ou um valor diferente?
Dennis Williamson
1
Por outro lado, como isso já é mais popular. Não importa que seja mais velho.
kenorb

Respostas:

110

Obviamente, você pode definir a variável de ambiente dentro do comando, no entanto, terá que ter cuidado ao citar: lembre-se de que seu shell analisará sua linha de comando local e, em seguida, o shell remoto analisará a string recebe.

Se você deseja que uma variável obtenha o mesmo valor no servidor que possui no cliente, tente a SendEnvopção:

ssh -o SendEnv = MYVAR server.example.com mycommand

Isso requer suporte do servidor, no entanto. Com o OpenSSH, o nome da variável precisa ser autorizado /etc/sshd_config.

Se o servidor permitir apenas determinados nomes de variáveis ​​específicos, você poderá contornar isso; por exemplo, uma configuração comum permite LC_*, e você pode fazer o seguinte:

ssh -o SendEnv = LC_MYVAR server.example.com 'MYVAR = $ LC_MYVAR; desmarque LC_MYVAR; exportar MYVAR; mycommand '

Se even LC_*não for uma opção, você pode passar informações na TERMvariável de ambiente, que sempre é copiada (no entanto, pode haver um limite de comprimento). Você ainda precisará garantir que o shell remoto não restrinja a TERMvariável para designar um tipo de terminal conhecido. Passe a -topção para ssh se você não estiver iniciando um shell interativo remoto.

env TERM = "informações adicionais: $ TERM" ssh -t server.example.com 'MYVAR = $ {TERM%: *}; TERM = $ {TERM ## *:}; exportar MYVAR; mycommand '

Outra possibilidade é definir a variável diretamente no comando:

ssh -t server.example.com 'export MYVAR = "informações extras"; mycommand '

Assim, se passar uma variável local:

ssh -t server.example.com 'export MYVAR =' "'$ LOCALVAR'" '; mycommand '

No entanto, cuidado com os problemas de citação: o valor da variável será interpolado diretamente no snippet do shell executado no lado remoto. O último exemplo acima assume que $LOCALVARnão contém aspas simples ( ').

Gilles
fonte
2
Muito obrigado, fiquei furioso porque as variáveis ​​estúpidas LC_ * são exportadas no ssh e sua resposta me direcionou para onde procurar. Eu só tenho que desabilitar isso em ~ / .ssh / config
akostadinov 9/12
1
Estou na situação do pôster original, mas a variável que eu queria encaminhar é TERM, então estou um pouco intrigado com sua resposta. Esse encaminhamento automático de TERM foi desativado pelas versões recentes do OpenSSH?
Doub 20/11/12
1
@Doub O padrão é recusar todas as variáveis ​​de ambiente no lado do servidor, com AcceptEnvdiretivas sshd_configconforme desejado pelo administrador. Mas TERMé tratado especialmente, tanto quanto eu sei que não há como filtrá-lo no lado do servidor (ele é definido no ambiente do shell, independentemente de qualquer configuração). Tem certeza de que não há um script de perfil substituindo-o (como /etc/profileou ~/.profileou ~/.bashrc)?
Gilles
2
@ Gilles: eu testei novamente e, a menos que adicione explicitamente TERM à minha diretiva AcceptEnv, o TERM não será repassado. Não estou abrindo um shell, mas executando um comando diretamente, por exemplo: "ssh -o SendEnv = TERM shell.example.com env". Isso imprime todas as variáveis ​​de ambiente e TERM aparece apenas se estiver em SendEnv no cliente e AcceptEnv no servidor. Se eu executar "ssh -o SendEnv = TERM shell.example.com echo \ $ {TERM}" sem o AcceptEnv ou o SendEnv, ele imprimirá "burro", que não tenho certeza de onde vem (o env nem sequer lista TERM nesse caso).
Doub 27/11/12
7
@ Doub Oh, entendo. TERMsó é transmitido se o cliente solicitar que o servidor aloque um tty. Se não houver terminal no lado remoto, seria inútil transmitir TERM. Ao especificar um comando, se você quiser ter um terminal no lado remoto, precisará da -topção de linha de comando (ou RequestTTYdentro ~/.ssh/config).
Gilles
12

Se você pode administrar o host de destino, pode configurar o sshd para permitir a passagem de suas variáveis ​​de ambiente local para o host de destino.

Na página do manual sshd_config:

 PermitUserEnvironment
     Specifies whether ~/.ssh/environment and environment= options in
     ~/.ssh/authorized_keys are processed by sshd.  The default is
     "no".  Enabling environment processing may enable users to bypass
     access restrictions in some configurations using mechanisms such
     as LD_PRELOAD.

configuração sshd normalmente vive em /etc/ssh/sshd_config

Duncan Beevers
fonte
7
É muito útil saber que isso está definido como "não" por padrão!
precisa saber é o seguinte
6

Então, no seu cliente, você tem alguma variável de ambiente e deseja que ela esteja disponível para o comando remoto? Eu não acho que exista uma maneira de o ssh passar magicamente, mas você provavelmente pode fazer algo assim. Em vez de usar, diga:

ssh remote.host my_command

Você consegue fazer isso:

ssh remote.host env ENV_VAR=$ENV_VAR my_command
pioto
fonte
"provavelmente"? Eu gostaria de ler isso antes de realmente tentar esta resposta. Não funcionou para mim.
Tishma
1
Cuidado para elaborar sobre os erros recebidos, etc?
pioto 30/01
1
@pioto pode estar citando, por exemplo, se ENV_VAR tem espaços nele
Martin C. Martin
No Mac, você deve ter a opção -t para uma versão interativa, caso contrário, ela ficará presa. Portanto, isso pode funcionar: $ ssh -t remote.host env ENV_VAR = $ ENV_VAR my_command
muenalan
3

A resposta do @ emptyset (que não funcionou para mim) me levou a esta resposta:

Você pode adicionar este comando ao seu ~/.ssh/authorized_keysarquivo:

command="/usr/bin/env VARIABLE=<something> $SHELL" ssh-rsa <key>

export VARIABLE=<something>estava saindo imediatamente e a conexão SSH foi fechada (me bloqueando do servidor), enquanto /usr/bin/env ... $SHELLexecutará seu shell padrão com um ambiente modificado.

madprog
fonte
Isso apenas trava ao fazer login para mim. Quando o removo, o SSH volta ao normal e recebo meu shell de login habitual.
Nick Sweeting
@NickSweeting, você tentou substituir talvez $SHELLpor um shell real? Verifique também se / usr / bin / env existe no servidor. No entanto, a solução não é perfeita: notei que ele travou quando eu queria usar scpou um comando embutido.
Madprog 15/0518
Sim, foi a primeira coisa que tentei. Infelizmente nunca funcionou, acabou ativando PermitUserEnvironment yese usando em environment="..."vez de command="...".
Nick Sweeting
Isso está funcionando muito bem para mim.
Sr. Tao
3

No seu cliente local, ~/.ssh/configvocê pode adicionar SetEnv, por exemplo,

Host myhost
  SetEnv FOO=bar

Nota: Verifique man ssh_config.

Em seguida, no servidor, certifique-se de permitir que o cliente passe certas variáveis ​​de ambiente no seu /etc/ssh/sshd_configarquivo de configuração:

AcceptEnv LANG LC_* FOO BAR*

Nota: Verifique man sshd_config.

kenorb
fonte
1

Você pode tentar chamar um comando personalizado, supondo que você tenha uma configuração de login ssh sem senha. No servidor, edite sua entrada ~ / .ssh / allowed_keys que corresponde à chave do seu cliente:

command="export VARIABLE=<something>" ssh-rsa <key>

Veja este link na seção Comando Forçado para um pouco mais de detalhes.

emptyset
fonte
1
Eu tentei isso, mas não funciona. Ele executa o comando e sai, portanto não há sessão interativa. Esse é o comportamento normal? Nesse caso, isso pode ser útil se tudo o que você deseja fazer é permitir que uma chave específica acione um comando específico, mas se você deseja transmitir informações usadas em uma sessão (como a pergunta afirma), é inútil para esse fim. . Não há sessão.
Iconoclast
1

Eu estava criando uma compilação personalizada do OpenSSH para um dispositivo com cramfs no diretório inicial e / etc (o Cram FS é somente leitura) para que o ~ / .ssh / environment não funcionasse sem reconstruir o FS inteiro e estes foram implantados em campo dispositivos (sistemas embarcados, daí o uso de CRAMFS). Você pode especificar no sshd_config a localização do arquivo authroized_keys, mas por alguma razão o environment = funciona apenas para variáveis ​​de ambiente nas ~ / .ssh / authroized_keys. Editar o perfil / etc / não era uma opção e eu tive que carregar o ssh em um diretório não padrão. Em session.c após o child_set_env (... "MAIL" ...), basta adicionar as variáveis ​​de ambiente necessárias (este é um truque, eu sei ...), mas apenas alguém precisará de alguns envs codificados para uma sessão, se você estiver compilando a partir da fonte, você pode fazer isso. TGI-FLOSS

Vai
fonte
0

apenas um comando simples:

ssh -t your_host_or_ip 'export some_var_name=whatever_you_want; bash'
grepit
fonte