Jak zachować zmienne środowiskowe podczas korzystania z sudo

425

Kiedy używam dowolnego polecenia z sudo, nie ma tam zmiennych środowiskowych. Na przykład po ustawieniu HTTP_PROXY polecenie wgetdziała bez niego sudo. Jednak jeśli piszę sudo wget, mówi, że nie może ominąć ustawienia proxy.

Ahmed Aswani
źródło
2
superuser.com/questions/232231/...
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

475

Najpierw musisz export HTTP_PROXY. Po drugie, musisz man sudouważnie przeczytać i zwrócić uwagę na -Eflagę. To działa:

$ export HTTP_PROXY=foof
$ sudo -E bash -c 'echo $HTTP_PROXY'

Oto cytat ze strony podręcznika:

-E, --preserve-env
             Indicates to the security policy that the user wishes to preserve their
             existing environment variables.  The security policy may return an error
             if the user does not have permission to preserve the environment.
Zatrudniony rosyjski
źródło
1
świetnie, jedynym problemem jest modyfikacja niektórych plików konfiguracyjnych, na przykład pacman dla arch, aby -E został przekazany
Ahmed Aswani
7
Aby zezwolić na -E (zachowanie środowiska) dla wget, musisz określić znacznik SETENV w regule sudo, który pozwala na uruchomienie wget - Przykład: <nazwa użytkownika> ALL = (root) NOPASSWD: SETENV: <ścieżka do wget>
John Bowers
65
To „-E” nie działa, jeśli zmienną jest PATH lub PYTHONPATH.
apporc
Nie działa również z żadną LC_*zmienną. Więc po prostu zrób export LOL_FOO=$LC_FOOi użyj LOL_FOOzamiast tego.
luckydonald
9
To nie działa z prostszym przypadku dodanie jednego elementu do PATHw .bashrcpliku - na przykład export PATH=myPath:$PATH. Jeśli piszę sudo -E bash -c 'echo $PATH', to PATHprawdopodobnie nie zawiera myPath, ponieważ sudojuż wcześniej wyłączył lokalną wartość PATHprzed wywołaniem bash. Zamiast tego znalazłem odpowiedź poniżej stackoverflow.com/a/33183620/5459638 skuteczną, to znaczysudo PATH=$PATH command
XavierStuvw
310

Sztuką jest dodanie zmiennych środowiskowych do sudoerspliku za pomocą sudo visudopolecenia i dodanie następujących wierszy:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

zaczerpnięte z ArchLinux wiki .

W przypadku Ubuntu 14 musisz określić w osobnych wierszach, ponieważ zwraca błędy dla linii o wielu zmiennych:

Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"
Ahmed Aswani
źródło
11
Jest to prawdopodobnie najlepsza opcja, aby uniknąć wycieku informacji i luk bezpieczeństwa. sudo -Eto pewny sposób, aby adhoc uzyskać ten sam efekt jednorazowy
patrz
Napotkałem problem związany z procesem wywoływania sudo (jhbuild) i nie mogę powiedzieć, aby przekazał flagę -E do sudo, więc to jest moje rozwiązanie.
jgomo3
60
Zauważ, że nigdy nie powinieneś edytować etc/sudoersbezpośrednio. Zamiast tego użyj visudopolecenia, które sprawdza składnię twoich zmian przed nadpisaniem sudoerspliku. W ten sposób nie blokujesz się, jeśli popełnisz błąd podczas edycji.
Henning
1
Rozważ użycie zmiennych env wielkich liter. W moim przypadku załatwiło to użycie HTTP_PROXY i HTTPS_PROXY.
pabo
2
wariant małych liter jest lepszy z mojego doświadczenia, ponieważ działa zarówno w wget, jak i curl.
Miroslav Mocek
57

W przypadku poszczególnych zmiennych, które chcesz udostępnić jednorazowo, możesz włączyć je do polecenia.

sudo http_proxy=$http_proxy wget "http://stackoverflow.com"
buckaroo1177125
źródło
Ja testowałem to odpowiedzią na packagepodstawie dodanego do jakiegoś mojasciezka PATHw .bashrcpliku (z exportclausule). Następnie sudo PATH=$PATH which packageznajduje właściwą odpowiedź, w przeciwieństwie do sudo which package. Nie sudo PATH=$PATH packagewykracza jednak poza sudo package(nie znaleziono pliku). Z drugiej strony wystrzeliwanie równiny packagez przywołanej powłoki sudo bashzachowuje przedłużoną ścieżkę i daje packageprawa sudo (dwa gołębie z jednym kamieniem). Odpowiedź naprawdę zależy od tego, które polecenia uruchamiasz
XavierStuvw,
2
Rozdzielczość ŚCIEŻKI dla sudo to inna sprawa - jeśli ktoś znajdzie ten post w poszukiwaniu tej kwestii, sugeruję, aby zobaczyć unix.stackexchange.com/questions/83191/…
buckaroo1177125
24

Możesz także połączyć dwa env_keepstwierdzenia w odpowiedzi Ahmeda Aswani w jedno zdanie takie jak to:

Defaults env_keep += "http_proxy https_proxy"

Należy również rozważyć podanie env_keeptylko jednego polecenia takiego jak to:

Defaults!/bin/[your_command] env_keep += "http_proxy https_proxy"

Stian S.
źródło
1

Prosta funkcja opakowania (lub wbudowana pętla)

Wymyśliłem unikalne rozwiązanie, ponieważ:

  • sudo -E "$@" wyciekły zmienne, które powodowały problemy dla mojej komendy
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" był długi i brzydki w moim przypadku

demo.sh

#!/bin/bash

function sudo_exports(){
    eval sudo $(for x in $_EXPORTS; do printf '%q=%q ' "$x" "${!x}"; done;) "$@"
}

# create a test script to call as sudo
echo 'echo Forty-Two is $VAR42' > sudo_test.sh
chmod +x sudo_test.sh

export VAR42="The Answer to the Ultimate Question of Life, The Universe, and Everything."

export _EXPORTS="_EXPORTS VAR1 VAR2 VAR3 VAR4 VAR5 VAR6 VAR7 VAR8 VAR9 VAR10 VAR11 VAR12 VAR13 VAR14 VAR15 VAR16 VAR17 VAR18 VAR19 VAR20 VAR21 VAR22 VAR23 VAR24 VAR25 VAR26 VAR27 VAR28 VAR29 VAR30 VAR31 VAR32 VAR33 VAR34 VAR35 VAR36 VAR37 VAR38 VAR39 VAR40 VAR41 VAR42"

# clean function style
sudo_exports ./sudo_test.sh

# or just use the content of the function
eval sudo $(for x in $_EXPORTS; do printf '%q=%q ' "$x" "${!x}"; done;) ./sudo_test.sh

Wynik

$ ./demo.sh
Forty-Two is The Answer to the Ultimate Question of Life, The Universe, and Everything.
Forty-Two is The Answer to the Ultimate Question of Life, The Universe, and Everything.

W jaki sposób?

Jest to możliwe dzięki wbudowanej funkcji bash printf. %qTworzy powłoki cytowany łańcuch. W przeciwieństwie do rozszerzenia parametrów w bash 4.4 , działa to w wersjach bash <4.0

Bruno Bronosky
źródło
0

Jeśli potrzebujesz zachować zmienne środowiskowe w skrypcie, możesz umieścić swoje polecenie w dokumencie tutaj takim jak ten. Zwłaszcza jeśli masz wiele zmiennych, dzięki którym rzeczy wyglądają schludnie.

# prepare a script e.g. for running maven
runmaven=/tmp/runmaven$$
# create the script with a here document 
cat << EOF > $runmaven
#!/bin/bash
# run the maven clean with environment variables set
export ANT_HOME=/usr/share/ant
export MAKEFLAGS=-j4
mvn clean install
EOF
# make the script executable
chmod +x $runmaven
# run it
sudo $runmaven
# remove it or comment out to keep
rm $runmaven
Wolfgang Fahl
źródło