This post shows how to use the Python library Paramiko to implement a SSH client, programmatically connect to another computer over SSH and execute a shell command on that computer. Authentication is performed using either username and password or username and a cryptographic key.
Paramiko have many more features than the ones I use in the example in this article, such as being able to function as a SSH server, SFTP client etc. Please refer to the Paramiko documentation for further details!
Preparations
You need a computer that you can connect to using SSH. To determine whether you have SSH access, either use ssh in a terminal window (Linux and OS X users) or use PuTTY (Windows).
If you want to run the example program in an IDE and don’t already have one, I recommend JetBrains PyCharm – there is a free community edition available.
Finally, you need to have Paramiko installed, which I will describe how to in the next section.
Installing Paramiko from a Terminal Window
To install Paramiko from a terminal window, use:
pip install paramiko
If you are on Windows, there may be an error telling you that you need to install a library from Microsoft that is required by Paramiko.
Go to the URL shown in the error message and follow the instructions, the retry the installation using pip.
Installing Paramiko from within PyCharm
If you are developing in JetBrain’s PyCharm and assuming that you already have created a new project (File -> New Project), use the following procedure:
- Open the Preferences.
- In the Preferences, locate the Project node and the Project Interpreter node below the Project node.
In my case it looks like this (yes, I have already installed Paramiko and yes, my project is named “test”):
- Click the + button in the lower left of the packages list to install a new package.
- Type “paramiko” without quotes in the new dialog window that appears.
The result should look like this:
- Click the Install Package button.
If you are on Windows, there may be an error message telling you that you need to install a library from Microsoft required by Paramiko.
Go to the URL shown in the error message and follow the instructions. After having installed the library, repeat the process of installing the Paramiko package in PyCharm.
Private Key File
If you do not have a private keyfile and only use a regular login and password when establishing a SSH connection, just skip this part.
If you do intend to authenticate using a private key, you need to create keyfile named “private_key_file” with the key in it and add it to your Python project.
I had a lot of problems obtaining a file in the proper format. My private key is a DSA private key and the keyfile I successfully used with Paramiko looks like this:
-----BEGIN DSA PRIVATE KEY----- [contents omitted] -----END DSA PRIVATE KEY-----
Show Me the Code!
I have written a function that connects to a SSH host and executes a command. The function returns a tuple consisting of two lists of strings. The first list of strings is the output to standard out as produced when the command executed on the remote computer. The second list of strings is the output to standard err produced at the same occasion.
import time import paramiko def execute_ssh_command(host, port, username, password, keyfilepath, keyfiletype, command): """ execute_ssh_command(host, port, username, password, keyfilepath, keyfiletype, command) -> tuple Executes the supplied command by opening a SSH connection to the supplied host on the supplied port authenticating as the user with supplied username and supplied password or with the private key in a file with the supplied path. If a private key is used for authentication, the type of the keyfile needs to be specified as DSA or RSA. :rtype: tuple consisting of the output to standard out and the output to standard err as produced by the command """ ssh = None key = None try: if keyfilepath is not None: # Get private key used to authenticate user. if keyfiletype == 'DSA': # The private key is a DSA type key. key = paramiko.DSSKey.from_private_key_file(keyfilepath) else: # The private key is a RSA type key. key = paramiko.RSAKey.from_private_key(keyfilepath) # Create the SSH client. ssh = paramiko.SSHClient() # Setting the missing host key policy to AutoAddPolicy will silently add any missing host keys. # Using WarningPolicy, a warning message will be logged if the host key is not previously known # but all host keys will still be accepted. # Finally, RejectPolicy will reject all hosts which key is not previously known. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # Connect to the host. if key is not None: # Authenticate with a username and a private key located in a file. ssh.connect(host, port, username, None, key) else: # Authenticate with a username and a password. ssh.connect(host, port, username, password) # Send the command (non-blocking) stdin, stdout, stderr = ssh.exec_command(command) # Wait for the command to terminate while not stdout.channel.exit_status_ready() and not stdout.channel.recv_ready(): time.sleep(1) stdoutstring = stdout.readlines() stderrstring = stderr.readlines() return stdoutstring, stderrstring finally: if ssh is not None: # Close client connection. ssh.close() host = '192.168.1.2' port = 22 username = 'ivan' password = 'secretpassword' keyfile_path = 'private_key_file' (stdoutstring, stderrstring) = execute_ssh_command(host, port, username, password, None, None, "ls -al") for stdoutrow in stdoutstring: print stdoutrow
The code above connects to a computer at the address 192.168.1.2 on port 22 over SSH using the user-name “ivan” and the password “secretpassword” and then execute the command “ls -al”.
If you want to use a private key, change the invocation of the execute_ssh_command function to:
(stdoutstring, stderrstring) = execute_ssh_command(host, port, username, None, keyfile_path, 'DSA', "ls -al")
Note that the ‘DSA’ value should be replaced with ‘RSA’ if your private key is a RSA key and you should ensure that the path to the keyfile is correct.
If you now run the program, a directory listing of your remote computer should be printed to the console.
Happy coding!
Thank you for your post, it’s useful. I would like to know how it would change the program if I want to send result after ssh to my local, I have added these two lines after finally part:
finally:
with SCPClient(ssh.get_transport()) as scp:
scp.get(remote_file, local_path)
I am not sure if I have to write these two lines in try: part or in finally: part? and second question is about checking channel, I see that you have checked the channel for case of ssh, should I do the same with scp too? if yes, how?
Hello!
It sounds to me as if you want to fetch a file from the remote computer after having executed one or more commands over SSH. Have you seen my article on how to implement a SFTP client using Python and Paramiko here: https://www.ivankrizsan.se/2016/04/28/implementing-a-sftp-client-using-python-and-paramiko/
I hope it will solve your problems.
Happy coding!
Than you for your answer, using SCP is different from SFTP, what will be happened if I want to use SCPClient rather than SFTP., then my description in above, make sense?
Hi!
The SCPClient that I have had a look at works much the same way that SFTP do in that it allows for getting and putting files from/to a remote host. It does not seem to allow for copying directly from one remote host to another remote host. Thus I see little gain in using SCPClient over using SFTP.
Regarding your original questions; the two lines should be placed in the try-block and you do not have to check any channel since there is nothing returned from the SCPClient methods get and put.
Happy coding!
Excellent!
Thanks.
Hi, If i need to execute series of shell commands? how can i do that. i am trying to upload a file from local linux server to AWS transfer sftp . tried using pysftp, but not working. Can i use paramiko /subprocess
hi, i am trying to upload file from local linux server to AWS transfer sftp. what can i use paramiko or subprocess? ALso why didnt you use pysftp in the above code.?