【问题标题】:How to run sudo with Paramiko? (Python)如何使用 Paramiko 运行 sudo? (Python)
【发布时间】:2011-09-10 08:54:21
【问题描述】:

我尝试过的:

  1. invoke_shell() 然后channel.send su 然后发送密码导致不是root
  2. invoke_shell() 然后channel.exec_command 导致“频道已关闭”错误
  3. _transport.open_session() 然后channel.exec_command 导致不是root
  4. invoke_shell() 然后写入标准输入并刷新它导致不是 root

【问题讨论】:

标签: python ssh sudo paramiko


【解决方案1】:

看看这个例子:

ssh.connect('127.0.0.1', username='jesse', 
    password='lol')
stdin, stdout, stderr = ssh.exec_command(
    "sudo dmesg")
stdin.write('lol\n')
stdin.flush()
data = stdout.read.splitlines()
for line in data:
    if line.split(':')[0] == 'AirPort':
        print line

在此处找到的示例有更多解释: http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/

希望对你有帮助!

【讨论】:

  • 如果您的 sudoer 需要密码,这将不起作用,但是:“sudo: no tty present and no askpass program specified”
  • 好的,riskable 在您提供的链接上的评论解决了上述问题:stdin, stdout, stderr = ssh.exec_command("sudo -S %s" % command) # 如果 stdout 仍然打开,则 sudo如果 stdout.channel.closed 为 False,则要求我们输入密码: stdin.write('%s\n' % password) stdin.flush()
  • 我的不好,我没有检查stderr,应该说必须使用get_pty=True,所以你需要使用:ssh.exec_command('your command', get_pty=True)
  • get_pty=True 很有帮助。没有这个密码提示就不会出现。
【解决方案2】:

invoke_shell 像这样为我工作:

import paramiko, getpass, re, time

ssh_client = paramiko.SSHClient()   
ssh_client.connect( host )
sudo_pw = getpass.getpass("sudo pw for %s: " % host)
command = "sudo magicwand"

channel = ssh_client.invoke_shell() 
channel.send( command )       
# wait for prompt             
while not re.search(".*\[sudo\].*",channel.recv(1024)): time.sleep(1)
channel.send( "%s\n" % sudo_pw )

【讨论】:

  • while not loop 成功了!感谢分享! :)
  • 这不起作用,getpass 也不安全,因为它会在历史记录中显示密码
  • 这是唯一对我有用的解决方案。但是,我必须将\r 添加到所有发送的数据(命令和密码)中。否则什么都不会发生。
  • 使用这个经典的课程*.com/a/36948840/5167801instead
【解决方案3】:

AlexS 微调的答案(我现在在生产中使用它)将是:

def sudo_run_commands_remote(command, server_address, server_username, server_pass, server_key_file):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname=server_address,
                username=server_username,
                password=server_pass,
                key_filename=server_key_file)
    session = ssh.get_transport().open_session()
    session.set_combine_stderr(True)
    session.get_pty()
    session.exec_command("sudo bash -c \"" + command + "\"")
    stdin = session.makefile('wb', -1)
    stdout = session.makefile('rb', -1)
    stdin.write(server_pass + '\n')
    stdin.flush()
    print(stdout.read().decode("utf-8"))

如果您不使用密钥文件,请删除connect 方法的key_filename 部分,相反,如果您只使用没有密码的密钥,请删除password 部分。

关于此的一些注意事项是,它具有多命令能力。这意味着将bash 作为root 运行,因此您可以在一次运行中尽可能多地执行命令,只需将它们与; 分开即可。

【讨论】:

  • 我将您的方法与盐和 SSH 隧道一起使用,并且在返回的值中找到了密码。你能仔细检查一下并分享你的经验吗?谢谢
【解决方案4】:

对不起,我没有时间详细回答,但我能够使用 thisadvise 在 paramiko 上实现 sudo 命令

import paramiko
l_password = "yourpassword"
l_host = "yourhost"
l_user = "yourusername"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(l_host, username=l_user, password=l_password)    
transport = ssh.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
#for testing purposes we want to force sudo to always to ask for password. because of that we use "-k" key
session.exec_command("sudo -k dmesg")
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
#you have to check if you really need to send password here 
stdin.write(l_password +'\n')
stdin.flush()
for line in stdout.read().splitlines():        
    print 'host: %s: %s' % (l_host, line)

【讨论】:

    【解决方案5】:

    您可以使用频道发送sudo密码:

      passwd = getpass.getpass()
      ssh = paramiko.client.SSHClient()
      ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
      ssh.load_system_host_keys()
      ssh.connect(host, allow_agent=True)
      chan = ssh.get_transport().open_session()
      chan.get_pty()
      chan.setblocking(1)
    
      chan.exec_command("sudo -k dmesg")
    
      while chan.recv_ready()==False:
          stdout=chan.recv(4096)
          if re.search('[Pp]assword', stdout):
              chan.send(passwd+'\n')
          time.sleep(1)
          
      while chan.recv_ready():
          stdout += chan.recv(20000)
      chan.close()
      ssh.close()
    

    【讨论】:

      【解决方案6】:

      在我看来,创建一个具有 sudoer 权限的脚本会更容易和安全。

      例如,将这个添加到 sudoers:

      myuser  ALL=NOPASSWD:/home/myuser/somescript.sh
      

      现在您可以通过主机上的 paramiko 调用脚本并完成它。

      【讨论】:

      • 要编辑 sudoers,我们必须以 root 身份登录(或使用 su|sudo)并编辑 sudoers 或运行脚本来执行此操作。如果您只能通过paramiko 访问远程系统,我可能很难或不可能。例如,您正在自动化某些事情,您不想为您的脚本手动准备每个主机。
      • 在大多数情况下这不是一个选项,因为这是高安全风险。
      【解决方案7】:

      我能够在远程服务器上手动运行sudo cupsdisable 命令,而无需输入密码,当我以管理员用户(不是root)之一登录到该服务器时,但当我使用标准输入、标准输出执行相同操作时, stderr = client.exec_command("sudo cupsdisable <Printqueuename>") 它什么也不做。

      对我有用的命令是:

      stdin, stdout, stderr = client.exec_command("sudo -u root /usr/sbin/cupsdisable <printQueuename>")
      

      这仅适用于上述场景。希望这可以帮助某人

      【讨论】:

      • 这个答案是针对你的情况的,而不是一般的答案。它没有回答问题。
      最近更新 更多