¿Cuál es la forma más sencilla de SSH usando Python?

82

¿Cómo puedo simplemente SSH a un servidor remoto desde un script de Python (3.0) local, proporcionar un nombre de usuario / contraseña, ejecutar un comando e imprimir la salida en la consola de Python?

Prefiero no usar ninguna biblioteca externa grande ni instalar nada en el servidor remoto.

Christopher Tokar
fuente

Respuestas:

42

No lo he probado, pero este módulo pysftp podría ayudar, que a su vez usa paramiko. Creo que todo está del lado del cliente.

El comando interesante es probablemente el .execute()que ejecuta un comando arbitrario en la máquina remota. (El módulo también presenta .get()y .putmétodos que aluden más a su carácter FTP).

ACTUALIZAR:

Reescribí la respuesta después de que la publicación de blog a la que originalmente vinculé ya no está disponible. Algunos de los comentarios que se refieren a la versión anterior de esta respuesta ahora se verán extraños.

ThomasH
fuente
¡Buen descubrimiento! Siempre que no le importe personalizar las respuestas de error, esta abstracción adicional sería muy útil.
Cascabel
El módulo ssh hizo el truco. Simple y funciona bien. No busque a través de la API de Paramiko.
Christopher Tokar
2
El enlace al archivo ssh.py dentro del enlace que proporcionaste está roto: /
dgorissen
Sí, ¿podemos tener un nuevo enlace por favor? Encontré ssh.py en github, pero no es lo mismo (y no es tan bueno)
joedborg
1
El paquete pysftp solo proporciona SFTP. Lejos de ser un cliente SSH.
bortzmeyer
61

Puede codificarlo usted mismo usando Paramiko, como se sugirió anteriormente. Alternativamente, puede buscar en Fabric, una aplicación de Python para hacer todas las cosas que preguntó:

Fabric es una biblioteca de Python y una herramienta de línea de comandos diseñada para optimizar la implementación de aplicaciones o la realización de tareas de administración del sistema a través del protocolo SSH. Proporciona herramientas para ejecutar comandos de shell arbitrarios (ya sea como un usuario de inicio de sesión normal o mediante sudo), cargar y descargar archivos, etc.

Creo que esto se ajusta a tus necesidades. Tampoco es una biblioteca grande y no requiere instalación de servidor, aunque tiene dependencias en paramiko y pycrypt que requieren instalación en el cliente.

La aplicación solía estar aquí . Ahora se puede encontrar aquí .

* The official, canonical repository is git.fabfile.org
* The official Github mirror is GitHub/bitprophet/fabric

Hay varios artículos buenos al respecto, aunque debe tener cuidado porque ha cambiado en los últimos seis meses:

Implementar Django con Fabric

Herramientas del hacker moderno de Python: Virtualenv, Fabric y Pip

Implementación simple y fácil con Fabric y Virtualenv


Más tarde: Fabric ya no requiere paramiko para instalar:

$ pip install fabric
Downloading/unpacking fabric
  Downloading Fabric-1.4.2.tar.gz (182Kb): 182Kb downloaded
  Running setup.py egg_info for package fabric
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no files found matching 'fabfile.py'
Downloading/unpacking ssh>=1.7.14 (from fabric)
  Downloading ssh-1.7.14.tar.gz (794Kb): 794Kb downloaded
  Running setup.py egg_info for package ssh
Downloading/unpacking pycrypto>=2.1,!=2.4 (from ssh>=1.7.14->fabric)
  Downloading pycrypto-2.6.tar.gz (443Kb): 443Kb downloaded
  Running setup.py egg_info for package pycrypto
Installing collected packages: fabric, ssh, pycrypto
  Running setup.py install for fabric
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no files found matching 'fabfile.py'
    Installing fab script to /home/hbrown/.virtualenvs/fabric-test/bin
  Running setup.py install for ssh
  Running setup.py install for pycrypto
...
Successfully installed fabric ssh pycrypto
Cleaning up...

Sin embargo, esto es principalmente cosmético: ssh es una bifurcación de paramiko, el responsable de ambas bibliotecas es el mismo (Jeff Forcier, también autor de Fabric), y el responsable de mantenimiento tiene planes de reunir paramiko y ssh con el nombre de paramiko . (Esta corrección a través de pbanka ).

hughdbrown
fuente
Como parece un enlace interesante, me gustaría actualizarlo ya que el tuyo ahora está roto. por favor use: clemesha.org/blog/…
dlewin
¿No especificó el autor de la pregunta que no quiere usar una "biblioteca externa grande"? Paramiko y Fabric son exagerados cuando todo lo que el autor realmente pidió es una receta simple y única de ssh.
Zoran Pavlovic
1
@Zoran Pavlovic: todas las respuestas fueron para instalar un paquete local (paramiko, fabric, ssh, libssh2) o usar un subproceso para ejecutar ssh. La última es una solución sin instalación, pero no creo que generar ssh sea una gran idea, y tampoco lo hizo el OP, ya que seleccionó la respuesta para instalar el módulo ssh. Esos documentos dicen: "ssh.py proporciona tres operaciones SSH comunes, obtener, poner y ejecutar. Es una abstracción de alto nivel sobre Paramiko". Entonces, a menos que prefieras libssh2, que es muy codificado, no hay ninguna recomendación conforme. Estoy a favor de dar una buena solución cuando las condiciones del PO no se pueden cumplir razonablemente.
hughdbrown
24

Si desea evitar módulos adicionales, puede utilizar el módulo de subproceso para ejecutar

ssh [host] [command]

y capturar la salida.

Prueba algo como:

process = subprocess.Popen("ssh example.com ls", shell=True,
    stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output,stderr = process.communicate()
status = process.poll()
print output

Para tratar con nombres de usuario y contraseñas, puede usar subprocess para interactuar con el proceso ssh, o puede instalar una clave pública en el servidor para evitar la solicitud de contraseña.

Neil
fuente
7
Pero, ¿y si el cliente está en Windows?
Nathan
Puede ser difícil proporcionar una contraseña para sshsubprocesar a través de una tubería. Consulte ¿Por qué no usar simplemente una tubería (popen ())? . Puede que sea necesario pty, pexpectmódulos para solucionar él.
jfs
no parece funcionar para la cadena 'ssh en alguna computadora; python -c "import numpy; print numpy .__ version__" 'dice que no conoce el comando "importar"
usethedeathstar
1
@usethedeathstar: envuelva todo el comando remoto entre comillas: ssh somecomputer 'python -c "importar esto; imprimir esto"'
Neil
17

He escrito enlaces de Python para libssh2 . Libssh2 es una biblioteca del lado del cliente que implementa el protocolo SSH2.

import socket
import libssh2

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('exmaple.com', 22))

session = libssh2.Session()
session.startup(sock)
session.userauth_password('john', '******')

channel = session.channel()
channel.execute('ls -l')

print channel.read(1024)
Sebastián Noack
fuente
2
Parece de muy bajo nivel. Por ejemplo (su propio ejemplo), debe decir explícitamente que usa IPv4 o IPv6 (algo que no tiene que ver con el cliente de línea de comandos OpenSSH). Además, no encontré cómo hacerlo funcionar con el agente ssh.
bortzmeyer
2
Lo bueno de pylibssh2 es que transfiere archivos MUCHO más rápido que cualquier implementación Python nativa de ssh como paramiko.
Damien
8

Su definición de "más simple" es importante aquí: código simple significa usar un módulo (aunque "biblioteca externa grande" es una exageración).

Creo que el módulo más actualizado (desarrollado activamente) es paramiko . Viene con secuencias de comandos de demostración en la descarga y tiene documentación API en línea detallada. También puede probar PxSSH , que se encuentra en pexpect . Hay una pequeña muestra junto con la documentación en el primer enlace.

De nuevo, con respecto a la simplicidad, tenga en cuenta que una buena detección de errores siempre hará que su código parezca más complejo, pero debería poder reutilizar una gran cantidad de código de los scripts de muestra y luego olvidarse de él.

Cascabel
fuente
6

Como hughdbrown, me gusta Fabric. Tenga en cuenta que si bien implementa su propia secuencia de comandos declarativa (para realizar implementaciones y demás), también se puede importar como un módulo de Python y utilizar en sus programas sin tener que escribir una secuencia de comandos de Fabric.

Fabric tiene un nuevo responsable y está en proceso de reescritura; eso significa que la mayoría de los tutoriales que encontrará (actualmente) en la web no funcionarán con la versión actual. Además, Google todavía muestra la página anterior de Fabric como primer resultado.

Para obtener documentación actualizada, puede consultar: http://docs.fabfile.org

juanjux
fuente
Fabric usa una bifurcación de paramiko pypi.python.org/pypi/ssh para todas las cosas de ssh.
Damien
6

Encontré que paramiko es de un nivel demasiado bajo y que Fabric no es especialmente adecuado para ser utilizado como biblioteca, así que armé mi propia biblioteca llamada spur que usa paramiko para implementar una interfaz un poco más agradable:

import spur

shell = spur.SshShell(hostname="localhost", username="bob", password="password1")
result = shell.run(["echo", "-n", "hello"])
print result.output # prints hello

También puede optar por imprimir la salida del programa mientras se ejecuta, lo cual es útil si desea ver la salida de los comandos de larga ejecución antes de que salga:

result = shell.run(["echo", "-n", "hello"], stdout=sys.stdout)
Michael Williamson
fuente
No admite la ejecución de comandos no estándar, por ejemplo, en algunos enrutadores (MikroTik) los comandos tienen el prefijo '/', esta biblioteca arroja un error. Sin embargo, para los hosts estándar de Linux, parece bastante bueno.
Babken Vardanyan
Cuando paso una dirección IP al nombre de host, arroja un error que dice que la IP no se encontró en known_hosts ...
rexbelia
@rexbelia Este es el comportamiento normal de SSH: para asegurarse de que está hablando con el servidor correcto, SSH solo aceptará la clave de un host si ya la conoce. La solución es agregar la clave relevante a known_hosts, o establecer el argumento missing_host_key en un valor apropiado, como se describe en la documentación.
Michael Williamson
4

Para beneficio de aquellos que llegan aquí buscando en Google una muestra de python ssh. La pregunta y la respuesta originales son casi una descodificación antiguas ahora. Parece que paramiko ha ganado un poco de funcionalidades (Ok. Lo admitiré, adivinando aquí, soy nuevo en Python) y puedes crear un cliente ssh directamente con paramiko.

import base64
import paramiko

client = paramiko.SSHClient()

client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('192.168.1.1', username='user', password='password')
stdin, stdout, stderr = client.exec_command('cat /proc/meminfo')
for line in stdout:
    print('... ' + line.strip('\n'))
client.close()

Este código fue adaptado de la demostración de https://github.com/paramiko/paramiko Funciona para mí.

Oceanuz
fuente
1

Esto funcionó para mi

import subprocess
import sys
HOST="IP"
COMMAND="ifconfig"

def passwordless_ssh(HOST):
        ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
                       shell=False,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE)
        result = ssh.stdout.readlines()
        if result == []:
                error = ssh.stderr.readlines()
                print >>sys.stderr, "ERROR: %s" % error
                return "error"
        else:
                return result
Naveen
fuente
1

please refer to paramiko.org, its very useful while doing ssh using python.

import paramiko

import time

ssh = paramiko.SSHClient() #SSHClient() is the paramiko object</n>

#Below lines adds the server key automatically to know_hosts file.use anyone one of the below

ssh.load_system_host_keys() 

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

try:

#Here we are actually connecting to the server.

ssh.connect('10.106.104.24', port=22, username='admin', password='')

time.sleep(5)

#I have mentioned time because some servers or endpoint prints there own information after 
#loggin in e.g. the version, model and uptime information, so its better to give some time 
#before executing the command.

#Here we execute the command, stdin for input, stdout for output, stderr for error

stdin, stdout, stderr = ssh.exec_command('xstatus Time')

#Here we are reading the lines from output.

output = stdout.readlines() 

print(output)


#Below all are the Exception handled by paramiko while ssh. Refer to paramiko.org for more information about exception.


except (BadHostKeyException, AuthenticationException,  
    SSHException, socket.error) as e:           

print(e)
Harshan Gowda
fuente
0

Eche un vistazo a spurplus , un envoltorio sobre spur y paramiko que desarrollamos para administrar máquinas remotas y realizar operaciones de archivos.

Spurplus proporciona una check_output()función lista para usar :

import spurplus
with spurplus.connect_with_retries(
        hostname='some-machine.example.com', username='devop') as shell:
     out = shell.check_output(['/path/to/the/command', '--some_argument']) 
     print(out)
marko.ristin
fuente