【问题标题】:How to run the bash command as a system user without giving that user the right to run commands as any user如何以系统用户身份运行 bash 命令而不赋予该用户以任何用户身份运行命令的权利
【发布时间】:2017-06-11 18:14:46
【问题描述】:

我编写了一个包含这一行的 python 脚本:

response = subprocess.check_output(['/usr/bin/sudo /bin/su - backup -c "/usr/bin/ssh -q -o StrictHostKeyChecking=no %s bash -s" <<\'EOF\'\nPATH=/usr/local/bin:$PATH\nmvn --version|grep -i Apache|awk \'{print $3}\'|tr -d \'\n\'\nEOF' % i], shell=True)

这是在一个遍历主机名列表的 for 循环中,我想检查每个主机名的命令结果。当我自己运行它时,它工作得很好,但是,这个脚本将由系统用户(shinken - nagios fork)运行,此时我遇到了一个问题。

shinken ALL=(ALL) NOPASSWD: ALL

但是,我想限制用户只允许它作为备份用户运行:

shinken ALL=(backup) NOPASSWD: ALL

但是当我运行脚本时,我得到:

sudo: no tty present and no askpass program specified

我已经阅读并尝试了一些方法来解决它。我尝试将 -t 添加到我的 ssh 命令中,但这没有帮助。我相信我应该能够使用类似于以下内容的命令运行该命令:

response = subprocess.check_output(['/usr/bin/sudo -u backup """ "/usr/bin/ssh -q -o StrictHostKeyChecking=no %s bash -s" <<\'EOF\'\nPATH=/usr/local/bin:$PATH\njava -version|grep -i version|awk \'{print $3}\'|tr -d \'\n\'\nEOF""" ' % i], shell=True)

但后来我得到了这样的回应:

subprocess.CalledProcessError: Command '['/usr/bin/sudo -u backup """ "/usr/bin/ssh -q -o StrictHostKeyChecking=no bamboo-agent-01 bash -s" <<\'EOF\'\nPATH=/usr/local/bin:$PATH\njava -version|grep -i version|awk \'{print $3}\'|tr -d \'\n\'\nEOF""" ']' returned non-zero exit status 1

如果我手动运行命令,我会得到:

sudo:  /usr/bin/ssh: command not found

这很奇怪,因为那是它生活的地方......我不知道我正在尝试的东西是否可能。感谢您的任何建议!

【问题讨论】:

  • 你也许可以使用变量SUDO_ASKPASS
  • 该帐户没有密码,所以我认为这不会有帮助。我还尝试在我的 sudoers 文件中设置“Defaults:shinken !requiretty”,但这也没有帮助....
  • “帐户”? 哪个帐户? sudo 将活动用户更改为root,然后suroot 下降到backupsudo su - backup 不是一个统一的步骤——它运行的是两个完全独立的程序。
  • ...如果您想要只有一步,那么您可以运行sudo -u backup -i
  • 无论如何,当sudo 要求输入密码时,它要求的是您当前的 密码,而不是目标帐户的密码,除非有相反的配置。显然,您希望为这个用例配置NOPASSWD:,但这是需要在/etc/sudoers 中的东西,而不是与脚本相关的细节。

标签: python bash ssh visudo


【解决方案1】:

至于sudo

shinken ALL=(backup) NOPASSWD: ALL

...仅当您将 直接shinken 切换到 backup 时才有效。 您没有在此处这样做sudo su - backup 告诉sudo 切换到root,并运行命令su - backup 作为root。显然,如果你要使用 sudo su(我在其他地方建议不要这样做),你需要你的 /etc/sudoers 配置来支持它。

因为您的/etc/sudoers 不允许直接切换到您请求的root,它正在尝试提示输入密码,这需要 TTY,从而导致失败。

下面,我重写脚本直接从shinken切换到backup没有经过root并运行su


至于脚本:

import subprocess

remote_script='''
PATH=/usr/local/bin:$PATH
mvn --version 2>&1 | awk '/Apache/ { print $3 }' 
'''

def maven_version_for_host(hostname):

    # storing the command lets us pass it when constructing a CalledProcessError later
    # could move it directly into the Popen creation if you don't need that.
    cmd = [
        'sudo', '-u', 'backup', '-i', '--',
        'ssh', '-q', '-o', 'StrictHostKeyChecking=no', str(hostname),
        'bash -s' # arguments in remote-command position to ssh all get concatenated
                  # together, so passing them as one command aids clarity.
    ]
    proc = subprocess.Popen(cmd,
        stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    response, error_string = proc.communicate(remote_script)
    if proc.returncode != 0:
        raise subprocess.CalledProcessError(proc.returncode, cmd, error_string)
    return response.split('\n', 1)[0]

【讨论】:

  • 仅供参考,回复:建议的编辑添加 2&gt;&amp;1,您可以将 'bash -s 2&gt;&amp;1' 全部放入一个字符串中 - 这是因为 ssh 连接其所有尾部位置参数以生成命令。也就是说,如果你想捕获stderr,你也可以通过stderr=subprocess.PIPE,注意communicate()返回的元组的第二块。
  • ...或者您可以通过stderr=subprocess.STDOUT 将它们组合起来,这就是我个人会做的事情(如果您想组合它们而不是将错误分开) - 这样您就可以捕获来自sudossh 的错误,而不是仅捕获发生在远程端的错误。
  • ...不过,我个人认为将错误分开是最佳做法;查看编辑。
  • 添加的原因是当使用java而不是maven运行检查时,java检查的响应出现在终端中,但是响应字段中没有值,所以检查没有不行。当我有 2&>1 时,maven 检查不起作用,所以我显然错了。我已将编辑更改为关注
  • 另外,先生,您是一位绅士,非常感谢您在这里帮助我,其中一些是显而易见的,有些则不那么明显(例如必须有响应和 error_string,感谢您更改标签!)但如果没有你的帮助,我会花更长的时间!
猜你喜欢
  • 1970-01-01
  • 2017-07-12
  • 2019-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-25
相关资源
最近更新 更多