使用sudo时如何保存环境变量

当我用sudo使用任何命令时,环境变量都不存在。例如,在设置HTTP_PROXY之后,命令wget没有sudo也可以正常工作。然而,如果我输入sudo wget,它说它不能绕过代理设置。

406594 次浏览

首先你需要export HTTP_PROXY。其次,您需要阅读man sudo,并查看-E标志。如此:

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

下面是手册页中的引文:

-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.

诀窍是通过sudo visudo命令将环境变量添加到sudoers文件中,并添加这些行:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

取自ArchLinux维基

对于Ubuntu 14,你需要在单独的行中指定,因为它会返回多变量行的错误:

Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"

你也可以把Ahmed Aswani回答中的两个env_keep语句合并成一个语句,就像这样:

# EYZ0

您还应该考虑仅为单个命令指定env_keep,如下所示:

# EYZ0

对于您希望一次性可用的单个变量,您可以将其作为命令的一部分。

sudo http_proxy=$http_proxy wget "http://stackoverflow.com"

如果您需要将环境变量保存在脚本中,您可以将您的命令放在如下的here文档中。特别是当你有很多变量让事情看起来很整洁的时候。

# 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

一个简单的包装器函数(或内联for循环)

我想出了一个独特的解决方案,因为:

  • sudo -E "$@"泄漏变量,导致我的命令出现问题
  • 对我来说,sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@"又长又丑

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

结果

$ ./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.

如何?

这是bash内置在printf中的一个特性实现的。%q生成一个shell引号字符串。与bash 4.4中的参数展开不同,这适用于bash版本<4.0

添加代码片段到/etc/sudoers.d

不知道这是否在所有发行版中都可用,但在基于debian的发行版中,在/etc/sudoers文件的尾部或附近有一行,其中包括文件夹/etc/sudoers.d。在这里,可以添加代码"snippets"修改sudo的配置。具体来说,它们允许控制sudo中使用的所有环境变量。

/etc/sudoers一样,这些“代码snippets"应该使用visudo进行编辑。你可以从阅读README文件开始,这也是一个方便的地方,可以保存任何你想做的笔记:

$ sudo visudo -f /etc/sudoers.d/README


# files for your snippets may be created/edited like so:


$ sudo visudo -f /etc/sudoers.d/20_mysnippets

阅读“命令环境”;“man 5 sudoers”部分

sudo中关于环境配置的最有信息的文档可能在man 5 sudoersCommand environment部分中找到。在这里,我们了解到默认情况下阻塞的sudoers环境变量可能是“whitelisted",使用env_checkenv_keep选项;如。

Defaults env_keep += "http_proxy HTTP_PROXY"
Defaults env_keep += "https_proxy HTTPS_PROXY"
Defaults env_keep += "ftp_proxy FTP_PROXY"

因此,在OP的情况下,我们可以“通过”;sudo的环境变量如下:

$ sudo visudo -f /etc/sudoers.d/10_myenvwlist


# opens the default editor for entry of the following lines:
Defaults env_keep += "http_proxy HTTP_PROXY"
Defaults env_keep += "https_proxy HTTPS_PROXY"
# and any others deemed useful/necessary
# Save the file, close the editor, and you are done!

从“# sudo -V”中找到你的方位

OP可能在sudo试错法中发现了缺失的环境变量。但是,可以采取主动:从root提示符中可以获得所有环境变量的列表,以及它们的允许或拒绝状态(对于每个主机都是唯一的),如下所示:

# sudo -V
...
Environment variables to check for safety:
...
Environment variables to remove:
...
Environment variables to preserve:
...

注意,一旦一个环境变量被“白名单”;如上所述,它将出现在sudo -V的后续列表中。清单。