简体   繁体   English

如何使用 Paramiko 运行 sudo? (Python)

[英]How to run sudo with Paramiko? (Python)

What I've tried:我试过的:

  1. invoke_shell() then channel.send su and then sending the password resulted in not being root invoke_shell()然后channel.send su然后发送密码导致不是root
  2. invoke_shell() and then channel.exec_command resulted in a "Channel Closed" error invoke_shell()然后channel.exec_command导致“通道关闭”错误
  3. _transport.open_session() then channel.exec_command resulted in not being root _transport.open_session()然后channel.exec_command导致不是 root
  4. invoke_shell() then writing to stdin and flushing it resulted in not being root invoke_shell()然后写入标准输入并刷新它导致不是root

check this example out:看看这个例子:

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

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

Hope it helps!希望能帮助到你!

invoke_shell worked for me like this: 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 )

AlexS Fine tuned answer (which I am now using it in production) would be: 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"))

Remove the key_filename part of connect method if you dont use a key file and in contrast if you only use a key without password, remove the password part.如果您不使用密钥文件,请删除connect方法的key_filename部分,相反,如果您只使用没有密码的密钥,请删除password部分。

Some notes about this is that, it is multi command capable.关于这一点的一些注意事项是,它具有多命令能力。 Meaning that is is running a bash as root so you can as much commands as you can in a single run with just separating them with ;这意味着正在以root身份运行bash ,因此您可以在一次运行中尽可能多地执行命令,只需用;分隔它们即可。 . .

You Can use channel to send sudo password:您可以使用通道发送 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()

Im sorry i dont have time for details answer but i was able to implement sudo commands on paramiko using this advise对不起,我没有时间详细回答,但我能够使用这个建议在 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)

To my mind it would be much easier and secure to create a script which has sudoer rights.在我看来,创建一个具有 sudoer 权限的脚本会更加容易和安全。

For example, add this to sudoers:例如,将其添加到 sudoers:

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

Now you can just invoke the script via paramiko on the host machine and be done with it.现在您可以通过主机上的 paramiko 调用脚本并完成它。

I came up with this:我想出了这个:

def ssh_command(ssh_client, command, sudo=False):
    """Like SSHClient.exec_command, but raises if the command fails.

    Otherwise, the stdout result is returned as a string.
    """
    nbytes = 4 * 2e20           # 4 MiB
    with ssh_client.get_transport().open_session() as channel:
        command = 'sudo ' + command if sudo else command

        if sudo:
            channel.set_combine_stderr(True)
            channel.get_pty()

        channel.exec_command(command)

        if sudo:
            while not channel.recv_ready():
                stdout = channel.recv(nbytes).decode('UTF-8')
                if re.search('[Pp]assword', stdout):
                    channel.send(ROBOT_PASSWORD + '\n')
                    time.sleep(1)

        status = channel.recv_exit_status()  # blocking call
        if status != 0:
            if sudo:
                output = channel.recv(nbytes).decode('UTF-8')
            else:
                output = channel.recv_stderr(nbytes).decode('UTF-8')
            raise RuntimeError(f'command {command} exited with {status}, '
                               f'output: {output}')
        return channel.recv(nbytes).decode('UTF-8')

I'm surprised this basic functionality is left for Paramiko users to reinvent themselves.我很惊讶这个基本功能留给 Paramiko 用户来重塑自己。

I was able to run sudo cupsdisable command on the remote server manually without having to enter the password when I login to that server as one of the admin user(not root) but when I execute the same using stdin, stdout, stderr = client.exec_command("sudo cupsdisable <Printqueuename>") it does nothing.我能够在远程服务器上手动运行sudo cupsdisable命令,而无需输入密码,当我以管理员用户(不是 root)身份登录到该服务器时,但是当我使用 stdin、stdout、 stderr = client.exec_command("sudo cupsdisable <Printqueuename>")它什么也不做。

The command that worked for me was:对我有用的命令是:

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

This is specific to the above mentioned scenario only.这仅适用于上述场景。 Hope this helps someone希望这可以帮助某人

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM