Kiedy ssh'ing, jak mogę ustawić zmienną środowiskową na serwerze, która zmienia się między sesjami?

92

Kiedy sshprzechodzę na serwer, jak mogę przekazać zmienną środowiskową z klienta na serwer? Ta zmienna środowiskowa zmienia się między różnymi wywołaniami ssh, więc nie chcę nadpisywać za $HOME/.ssh2/environmentkażdym razem, gdy wykonuję wywołanie ssh. Jak mogę to zrobić?

Ross Rogers
źródło
2
Twoje pytanie musi być bardziej szczegółowe.
Ignacio Vazquez-Abrams
3
Pytanie było dla mnie wystarczająco jasne. Jednak na sshstronie podręcznika nie widzę innego sposobu, niż ręczne ustawienie zmiennej po zalogowaniu się na serwerze, chyba że zmodyfikujesz środowisko ~ / .ssh2 /.
garyjohn
Czy za każdym razem jest to inna zmienna? Lub inna wartość?
Dennis Williamson,
1
Odwrotnie, ponieważ jest to już bardziej popularne. Nie ma znaczenia, że ​​jest starszy.
kenorb

Odpowiedzi:

110

Oczywiście możesz ustawić zmienną środowiskową wewnątrz polecenia, jednak musisz uważać na cytowanie: pamiętaj, że twoja powłoka przeanalizuje lokalny wiersz poleceń, a wtedy zdalna powłoka będzie miała ciąg otrzymuje.

Jeśli chcesz, aby zmienna otrzymywała tę samą wartość na serwerze, co na kliencie, wypróbuj SendEnvopcję:

ssh -o SendEnv = MYVAR server.example.com moja komenda

Wymaga to jednak wsparcia ze strony serwera. W OpenSSH nazwa zmiennej musi być autoryzowana w /etc/sshd_config.

Jeśli serwer zezwala tylko na określone nazwy zmiennych, możesz obejść to; na przykład pozwala na to wspólna konfiguracja LC_*i można wykonać następujące czynności:

ssh -o SendEnv = LC_MYVAR server.example.com 'MYVAR = $ LC_MYVAR; rozbrojony LC_MYVAR; eksport MYVAR; moja komenda ”

Jeśli nawet LC_*nie jest opcją, możesz przekazać informacje do TERMzmiennej środowiskowej, która jest zawsze kopiowana (może istnieć jednak limit długości). Nadal będziesz musiał upewnić się, że zdalna powłoka nie ogranicza TERMzmiennej do wyznaczania znanego typu terminala. Przekaż -topcję ssh, jeśli nie uruchamiasz zdalnej interaktywnej powłoki.

env TERM = „dodatkowe informacje: $ TERM” ssh -t server.example.com 'MYVAR = $ {TERM%: *}; TERM = $ {TERM ## *:}; eksport MYVAR; moja komenda ”

Inną możliwością jest zdefiniowanie zmiennej bezpośrednio w poleceniu:

ssh -t server.example.com 'export MYVAR = "dodatkowe informacje"; moja komenda ”

Zatem jeśli przekazujesz zmienną lokalną:

ssh -t server.example.com 'export MYVAR =' "'$ LOCALVAR'” '; moja komenda ”

Uważaj jednak na kwestie cytowania: wartość zmiennej zostanie interpolowana bezpośrednio do fragmentu powłoki wykonanego po stronie zdalnej. Ostatni przykład powyżej zakłada, że $LOCALVARnie zawiera żadnych pojedynczych cudzysłowów ( ').

Gilles
źródło
2
Dzięki wielkie, byłem wściekły, że głupie zmienne LC_ * są eksportowane do ssh, a twoja odpowiedź wskazała mi, gdzie szukać. Po prostu muszę to wyłączyć w ~ / .ssh / config
akostadinov
1
Jestem w sytuacji z oryginalnego plakatu, ale zmienną, którą chciałem przekazać, jest TERM, więc twoja odpowiedź nieco mnie dziwi. Czy to automatyczne przekazywanie TERM zostało wyłączone przez ostatnie wersje OpenSSH?
Doub
1
@Doub Domyślnie odrzucane są wszystkie zmienne środowiskowe po stronie serwera, z AcceptEnvdyrektywami sshd_configzgodnie z życzeniem administratora. Ale TERMjest traktowany specjalnie, o ile wiem, nie ma możliwości filtrowania go po stronie serwera (jest ustawiony w środowisku powłoki niezależnie od jakichkolwiek ustawień konfiguracyjnych). Czy na pewno nie ma skryptu profilu zastępującego go (jak /etc/profilelub ~/.profilelub ~/.bashrc)?
Gilles,
2
@Gilles: Przetestowałem to ponownie i chyba że wyraźnie dodam TERM do mojej dyrektywy AcceptEnv, TERM nie jest przekazywany. Nie otwieram powłoki, ale uruchamiam polecenie bezpośrednio, na przykład: „ssh -o SendEnv = TERM shell.example.com env”. Spowoduje to wydrukowanie wszystkich zmiennych środowiskowych, a TERM pojawia się tylko wtedy, gdy znajduje się w SendEnv na kliencie i AcceptEnv na serwerze. Jeśli uruchomię „ssh -o SendEnv = TERM shell.example.com echo \ $ {TERM}” bez AcceptEnv lub SendEnv, wypisze „głupi”, z którego nie jestem pewien, skąd pochodzi (env nawet nie w takim przypadku należy podać TERM).
Doub
7
@Doub Oh, rozumiem. TERMjest przesyłany tylko wtedy, gdy klient poprosi serwer o przydzielenie tty. Jeśli po drugiej stronie nie ma terminala, nadawanie byłoby bezużyteczne TERM. Jeśli określisz polecenie, jeśli chcesz mieć terminal po stronie zdalnej, potrzebujesz -topcji wiersza polecenia (lub RequestTTYin ~/.ssh/config).
Gilles
12

Jeśli możesz administrować hostem docelowym, możesz skonfigurować sshd, aby zezwalał na przekazywanie lokalnych zmiennych środowiskowych do hosta docelowego.

Ze strony podręcznika 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.

Konfiguracja sshd zwykle mieszka w /etc/ssh/sshd_config

Duncan Beevers
źródło
7
Warto wiedzieć, że domyślnie jest to ustawione na „nie”!
jathanism
6

Na kliencie masz więc zmienną środowiskową i chcesz, aby była dostępna dla polecenia zdalnego? Nie sądzę, że istnieje sposób, aby ssh magicznie to przekazał, ale prawdopodobnie możesz zrobić coś takiego. Zamiast używać powiedz:

ssh remote.host my_command

Możesz to zrobić:

ssh remote.host env ENV_VAR=$ENV_VAR my_command
pioto
źródło
"prawdopodobnie"? Chciałbym to przeczytać przed wypróbowaniem tej odpowiedzi. Nie działało dla mnie.
tishma
1
Czy chcesz opracować wszelkie otrzymane błędy itp.?
pioto
1
@pioto Może być cytowany, np. jeśli ENV_VAR ma spacje
Martin C. Martin
Na Macu musisz mieć opcję -t dla wersji interaktywnej, w przeciwnym razie wygląda to na zablokowanie. Więc to może działać: $ ssh -t remote.host env ENV_VAR = $ ENV_VAR moja_komenda
muenalan
3

Odpowiedź @ emptyset (która nie działała dla mnie) doprowadziła mnie do tej odpowiedzi:

Możesz dodać to polecenie do swojego ~/.ssh/authorized_keyspliku:

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

export VARIABLE=<something>natychmiast wychodził, a połączenie SSH zostało zamknięte (blokując mnie z serwera), natomiast /usr/bin/env ... $SHELLuruchomi domyślną powłokę w zmodyfikowanym środowisku.

madprog
źródło
To zawiesza się podczas logowania dla mnie. Po usunięciu SSH wraca do normy i otrzymuję zwykłą powłokę logowania.
Nick Sweeting
@NickSweeting próbowałeś może zastąpić $SHELLrzeczywistą powłoką? Sprawdź także, czy / usr / bin / env istnieje na serwerze. Jednak rozwiązanie nie jest idealne: zauważyłem, że zawiesił się, gdy chciałem użyć scppolecenia lub polecenia wbudowanego.
madprog
Tak, to była pierwsza rzecz, której spróbowałem. Niestety nigdy nie działało, w końcu włączono PermitUserEnvironment yesi uruchomiono environment="..."zamiast command="...".
Nick Sweeting
To mi ładnie działa.
Pan Tao
2

Na swoim lokalnym kliencie ~/.ssh/configmożesz dodać SetEnvnp

Host myhost
  SetEnv FOO=bar

Uwaga: Sprawdź man ssh_config.

Następnie na serwerze upewnij się, że klient może przekazać określone zmienne środowiskowe w /etc/ssh/sshd_configpliku konfiguracyjnym:

AcceptEnv LANG LC_* FOO BAR*

Uwaga: Sprawdź man sshd_config.

kenorb
źródło
1

Możesz spróbować wywołać niestandardowe polecenie, zakładając, że masz konfigurację logowania ssh bez hasła. Na serwerze edytuj wpis ~ / .ssh / Author_keys, który odpowiada kluczowi od twojego klienta:

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

Spójrz na ten link w sekcji Wymuszone polecenie, aby uzyskać trochę więcej szczegółów.

emptyset
źródło
1
Próbowałem tego, ale to nie działa. Uruchamia polecenie i kończy pracę, więc nie ma interaktywnej sesji. Czy to jest normalne zachowanie? Jeśli tak, może to być przydatne, jeśli wszystko, co chcesz zrobić, to pozwolić, aby określony klawisz uruchomił określone polecenie, ale jeśli chcesz przekazać informacje, które są używane w sesji (jak mówi pytanie), to jest to bezużyteczne w tym celu . Nie ma sesji.
iconoclast
1

Tworzyłem niestandardową kompilację OpenSSH dla urządzenia z cramfs w katalogu domowym i / etc (Cram FS jest tylko do odczytu), więc ~ / .ssh / environment nie działałoby bez przebudowy całego FS i zostały one wdrożone w terenie urządzenia (systemy osadzone Stąd użycie CRAMFS). Możesz określić w pliku sshd_config lokalizację pliku authroized_keys, ale z jakiegoś powodu środowisko = działa tylko dla zmiennych środowiskowych w ~ / .ssh / authroized_keys. Edycja profilu / etc / nie była opcją i musiałem załadować ssh do niestandardowego katalogu. W session.c po child_set_env (... „MAIL” ...) po prostu dodaj potrzebne zmienne środowiskowe (wiem, że to hack ...), ale jeśli tylko potrzebujesz kogoś, kto potrzebuje trochę zakodowanych envów na sesję, jeśli jesteś kompilując ze źródła możesz to zrobić. TGI-FLOSS

Będzie
źródło
0

tylko jedno proste polecenie:

ssh -t your_host_or_ip 'export some_var_name=whatever_you_want; bash'
grepit
źródło