Как запустить sudo с Paramiko? (Питон)

Что я пробовал:

  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

person Takkun    schedule 07.06.2011    source источник
comment
Почему бы не использовать setuid en.wikipedia.org/wiki/Setuid?   -  person Nick ODell    schedule 07.06.2011
comment


Ответы (7)


проверьте этот пример:

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/

Надеюсь, поможет!

person W0bble    schedule 07.06.2011
comment
Это не будет работать, если ваш sudoer требует пароль: sudo: нет tty и не указана программа askpass - person Haroldo_OK; 28.05.2014
comment
Хорошо, комментарий Riskable по предоставленной вами ссылке решает проблему выше: stdin, stdout, stderr = ssh.exec_command(sudo -S %s % command) # Если stdout все еще открыт, sudo запрашивает у нас пароль, если stdout.channel .closed равно False: stdin.write('%s\n' % password) stdin.flush() - person Haroldo_OK; 28.05.2014
comment
мой плохой, я не проверял stderr, следует сказать, что нужно использовать get_pty=True, поэтому вам нужно использовать: ssh.exec_command('your command', get_pty=True) - person sliders_alpha; 08.07.2016
comment
get_pty=True полезно. без этого запроса пароля не приходит. - person VISHAL VIRADIA; 23.09.2016
comment
Данная ссылка удалена автором. - person Adrian W; 16.08.2019
comment
@NomNomNom Я собирался опубликовать то же самое! Отлично сделано! - person David Golembiowski; 05.06.2021

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 )
person seelaman    schedule 03.10.2014
comment
Этот while not loop сделал свое дело! Спасибо, что поделился! :) - person Paul Calabro; 04.02.2015
comment
Это не работает, getpass также небезопасен, потому что показывает пароль в истории - person AmirHossein; 16.02.2018
comment
Это единственное решение, которое сработало для меня. Однако мне пришлось добавить \r ко всем отправляемым данным (команда и пароль). В противном случае ничего не происходит. - person Adrian W; 16.08.2019
comment
Используйте этот классный фрагмент класса stackoverflow.com/a/36948840/5167801вместо этого - person Anum Sheraz; 06.12.2019

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"))

Удалите часть key_filename метода connect, если вы не используете файл ключа, и, напротив, если вы используете только ключ без пароля, удалите часть password.

Некоторые примечания по этому поводу заключаются в том, что он поддерживает несколько команд. Это означает, что выполняется bash как root, поэтому вы можете выполнять столько команд, сколько можете, за один запуск, просто разделяя их с помощью ;.

person AmirHossein    schedule 16.02.2018

Извините, у меня нет времени на подробный ответ, но я смог реализовать команды sudo на paramiko, используя это советовать

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)
person AlexS    schedule 18.01.2015

Вы можете использовать канал для отправки пароля 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()
person Aashutosh jha    schedule 24.11.2016

На мой взгляд, было бы намного проще и безопаснее создать скрипт с правами sudoer.

Например, добавьте это в sudoers:

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

Теперь вы можете просто вызвать скрипт через paramiko на хост-компьютере и покончить с этим.

person Uku Loskit    schedule 07.06.2011
comment
Чтобы редактировать sudoers, мы должны войти в систему как root (или использовать su|sudo) и отредактировать sudoers или запустить для этого скрипт. Мне может быть сложно или невозможно, если у вас есть доступ к удаленной системе только через paramiko. Например, вы что-то автоматизируете, не хотите вручную каждый хост подготавливать под свои скрипты. - person Jury; 24.12.2015
comment
В большинстве случаев это не вариант, так как это высокий риск для безопасности. - person Appu Sidhardh; 12.05.2016

Мне удалось запустить команду sudo cupsdisable на удаленном сервере вручную без необходимости вводить пароль, когда я вхожу на этот сервер как один из администраторов (не root), но когда я выполняю то же самое с помощью stdin, stdout, stderr = client.exec_command("sudo cupsdisable <Printqueuename>") это ничего не делает.

Команда, которая сработала для меня, была:

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

Это характерно только для вышеупомянутого сценария. Надеюсь, это поможет кому-то

person user9603539    schedule 05.04.2018
comment
Этот ответ относится к вашему случаю, а не к общему ответу. Это не ответ на вопрос. - person Azsgy; 05.04.2018