2011-06-07 67 views
12

Lo que he intentado:¿Cómo ejecutar sudo con paramiko? (Python)

  1. invoke_shell() entonces channel.send Do luego enviar la contraseña dio lugar a no ser la raíz
  2. invoke_shell() entonces channel.exec_command dio lugar a errores de canal cerrado
  3. _transport.open_session() entonces channel.exec_command dado lugar a no estar en la raíz
  4. invoke_shell() a continuación, escribir a la entrada estándar y al ras que dio lugar a no estar en la raíz
+0

¿Por qué no utilizar setuid http://en.wikipedia.org/wiki/Setuid? –

Respuesta

17

cheque a cabo este ejemplo:

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 

Ejemplo encontrar aquí con más explicaciones: http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/

espero que ayude!

+2

esto no funcionará si su sudoer requiere una contraseña, sin embargo: "sudo: sin TTY presente y hay un programa askpass especificado" –

+1

bien, el comentario de riskable en el enlace que ya ha proporcionado resuelve el problema anterior: stdin, stdout, stderr = ssh.exec_command ("sudo -S% s"% command) # Si stdout aún está abierto, sudo nos pide una contraseña si stdout.channel.closed es False: stdin.write ('% s \ n '% password) stdin.flush() –

+0

¿Esto todavía funciona?no hace nada por mí –

0

En mi opinión, sería mucho más fácil y seguro crear un script que tenga derechos sudoer.

Por ejemplo, añadir esto a sudoers:

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

Ahora usted puede simplemente invocar el script a través de paramiko en el ordenador central y hacerse con él.

+0

Para editar sudoers, tenemos que iniciar sesión como root (o usar 'su' |' sudo') y editar sudoers o ejecutar script para hacer eso. Puede ser difícil o imposible si tienes acceso al sistema remoto solo a través de 'paramiko'. Por ejemplo, está automatizando algo, no desea preparar manualmente cada host para sus scripts. – Jury

+0

Esto no es una opción en la mayoría de los casos ya que esto es un alto riesgo de seguridad. –

4

invoke_shell trabajó para mí de esta manera:

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) 
+0

Eso '' 'while not loop''' hizo el truco! ¡Gracias por compartir! :) –

+0

Esto no funciona, getpass tampoco es seguro porque muestra la contraseña en la historia – TechJS

2

Lo siento no tengo tiempo para más detalles respuesta, pero fue capaz de poner en práctica los comandos sudo en paramiko usando this consejo

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) 
2
You Can use channel to send sudo password: 

    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()de here 
0

AlexS La respuesta ajustada (que ahora la estoy usando en producción) sería:

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

Elimine la parte key_filename del método connect si no utiliza un archivo de clave y, por el contrario, si solo utiliza una clave sin contraseña, elimine la parte password.

Algunas notas sobre esto es que, es multi comando. Lo que significa que se está ejecutando un bash como root por lo que puede hacer tantos comandos como pueda en una sola ejecución con solo separarlos con ;.