Author Topic: [Python] Remote execute commands with SSH  (Read 984 times)

0 Members and 2 Guests are viewing this topic.

Offline gray-fox

  • Knight
  • **
  • Posts: 208
  • Cookies: 52
    • View Profile
[Python] Remote execute commands with SSH
« on: September 27, 2015, 11:05:26 pm »
Just thought I'll share small script I made to run same commands on multiple Linux servers quickly. I expanded my original script little bit, so it works also with password authentication and not just with ssh keypair.

To make it work it needs to have hosts.txt file in same folder which has following form per line:
Code: [Select]
[server];[user];[password]
If ssh keys are used to authenticate, then "pk" string is put as [password](without "") and for different port then just using [server:port] works. Not really fond of the idea of storing passwords in file, but with use of gpg or something file can ofc. be encrypted/decrypted when needed. I would have most likely tried to implement encryption/decryption to script if I wouldn't use keypairs. The script uses fabric for handeling ssh connections and it can be installed with pip.

But usage goes like this:
Code: [Select]
$ rexecute.py [command to run]

Here's the code, pretty simple and nothing new, but just my quick implementation of such task.
Code: (python) [Select]
from fabric.api import *
from fabric.tasks import execute
import sys

"""
rexecute.py
author: gray-fox
"""

class remote(object):

    def read_targets(self):
        """
        hosts.txt line pattern.
        One host per line:
        [host];[user];[password]
        Run on specific port:
        [host:<port>]
        If authentication is made with ssh keys use "pk" as
        [password]
        """
        self.hosts = []
        self.users = []
        self.passwords = []

        with open('hosts.txt','r') as h:
            for self.l in h:
                self.params = self.l.split(';', 2)
                self.hosts.append(self.params[0])
                self.users.append(self.params[1])
                self.passwords.append(self.params[2])
       
        return (self.hosts, self.users, self.passwords)
       
           
    def execute(self, cmd_raw):
   
        self.failed = []
        self.cmd = cmd_raw.split()
        self.servers,self.users,self.passwords = self.read_targets()
        for self.s, self.u, self.p in zip(self.servers, self.users, self.passwords):
            if self.p != "pk":
                with settings(host_string=self.s, user=self.u, password=self.p):
                    try:
                        if "sudo" in self.cmd:
                            self.cmd.remove('sudo')
                            sudo(' '.join(self.cmd))
                        else:
                            run(' '.join(self.cmd))
                       
                    except Exception as e:
                        self.failed.append(self.t)
                        print "Execution failed on: "+self.t
                        print "Error:"+str(e)
                       
            else:
                #Change path to match your private key
                with settings(host_string=self.s, user=self.u, key_filename="~/.ssh/id_rsa"):
                    try:
                        if "sudo" in self.cmd:
                            self.cmd.remove('sudo')
                            sudo(' '.join(self.cmd))
                        else:
                            run(' '.join(self.cmd))
                       
                    except Exception as e:
                        self.failed.append(self.t)
                        print "Execution failed on: "+self.t
                        print "Error:"+str(e)

        if len(self.failed) == 0:
            print "Command executed on all servers"
        else:
            print "[!] Execution failed on:"
            for f in self.failed:
                print f

                                     
if __name__=='__main__':
    if len(sys.argv) >= 2:
        remote().execute(' '.join(sys.argv[1:]))
    elif len(sys.argv) < 2:
        sys.exit("[!] No command specified")
« Last Edit: September 29, 2015, 02:56:55 pm by gray-fox »

Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: [PYTHON] Remote execute commands with SSH
« Reply #1 on: September 27, 2015, 11:13:43 pm »
Just thought I'll share small script I made to run same commands on few Linux servers quickly. I expanded my original script little bit, so it works also with password authentication and not just with ssh keypair.

To make it work it needs to have hosts.txt file in same folder which has following form per line:
Code: [Select]
[server];[user];[password]
If ssh keys are used to authenticate, then "pk" string is put as [password](without "") and for different port then just using [server:port] works. Not really fond of the idea of storing passwords in file, but with use of gpg or something file can ofc. be encrypted/decrypted when needed. I would have most likely tried to implement encryption/decryption to script if I wouldn't use keypairs. The script uses fabric for handeling ssh connections and it can be installed with pip.

But usage goes like this:
Code: [Select]
$ rexecute.py [command to run]

Here's the code, pretty simple and nothing new, but just my quick implementation of such task.
Code: (python) [Select]
from fabric.api import *
from fabric.tasks import execute
import sys

"""
rexecute.py
author: gray-fox
"""

class remote(object):

    def read_targets(self):
        """
        hosts.txt line pattern.
        One host per line:
        [host];[user];[password]
        Run on specific port:
        [host:<port>]
        If authentication is made with ssh keys use "pk" as
        [password]
        """
        self.hosts = []
        self.users = []
        self.passwords = []

        with open('hosts.txt','r') as h:
            for self.l in h:
                self.params = self.l.split(';', 2)
                self.hosts.append(self.params[0])
                self.users.append(self.params[1])
                self.passwords.append(self.params[2])
       
        return (self.hosts, self.users, self.passwords)
       
           
    def execute(self, cmd_raw):
   
        self.failed = []
        self.cmd = cmd_raw.split()
        self.servers,self.users,self.passwords = self.read_targets()
        for self.s, self.u, self.p in zip(self.servers, self.users, self.passwords):
            if self.p != "pk":
                with settings(host_string=self.s, user=self.u, password=self.p):
                    try:
                        if "sudo" in self.cmd:
                            self.cmd.remove('sudo')
                            sudo(' '.join(self.cmd))
                        else:
                            run(' '.join(self.cmd))
                       
                    except Exception as e:
                        self.failed.append(self.t)
                        print "Execution failed on: "+self.t
                        print "Error:"+str(e)
                       
            else:
                #Change path to match your private key
                with settings(host_string=self.s, user=self.u, key_filename="~/.ssh/id_rsa"):
                    try:
                        if "sudo" in self.cmd:
                            self.cmd.remove('sudo')
                            sudo(' '.join(self.cmd))
                        else:
                            run(' '.join(self.cmd))
                       
                    except Exception as e:
                        self.failed.append(self.t)
                        print "Execution failed on: "+self.t
                        print "Error:"+str(e)

        if len(self.failed) == 0:
            print "Command executed on all servers"
        else:
            print "[!] Execution failed on:"
            for f in self.failed:
                print f

                                     
if __name__=='__main__':
    if len(sys.argv) >= 2:
        remote().execute(' '.join(sys.argv[1:]))
    elif len(sys.argv) < 2:
        sys.exit("[!] No command specified")

Why don't use just key negotiation ?
This removes the need for pass auth entirely.
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage

Offline gray-fox

  • Knight
  • **
  • Posts: 208
  • Cookies: 52
    • View Profile
Re: [PYTHON] Remote execute commands with SSH
« Reply #2 on: September 27, 2015, 11:39:19 pm »
Not sure if I'm following. Like I though I said, original script only had part where authentication is made with ssh key negoatiation, so no password authentication is needed. Isn't this what you mean?
See this part of code:
Code: [Select]
with settings(host_string=self.s, user=self.u, key_filename="~/.ssh/id_rsa"):
                    try:
                        if "sudo" in self.cmd:
                            self.cmd.remove('sudo')
                            sudo(' '.join(self.cmd))
                        else:
                            run(' '.join(self.cmd))
That was original authentication meganism on my script and hosts.txt was then only: [host];[user].
I just added password part for versatility when I decided to post this here so it is also possible  to use it in servers where key pairs ain't used. Didn't really have anything to do with my usage with it.
If I hypothetically assume that someone else uses this and that someone generally uses user/pass for authentication not ssh keys, then I can't really "remove" need for password auth.

Or did I miss something here? :P
« Last Edit: September 28, 2015, 12:00:41 am by gray-fox »

Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: [PYTHON] Remote execute commands with SSH
« Reply #3 on: September 28, 2015, 05:24:19 am »
Not sure if I'm following. Like I though I said, original script only had part where authentication is made with ssh key negoatiation, so no password authentication is needed. Isn't this what you mean?
See this part of code:
Code: [Select]
with settings(host_string=self.s, user=self.u, key_filename="~/.ssh/id_rsa"):
                    try:
                        if "sudo" in self.cmd:
                            self.cmd.remove('sudo')
                            sudo(' '.join(self.cmd))
                        else:
                            run(' '.join(self.cmd))
That was original authentication meganism on my script and hosts.txt was then only: [host];[user].
I just added password part for versatility when I decided to post this here so it is also possible  to use it in servers where key pairs ain't used. Didn't really have anything to do with my usage with it.
If I hypothetically assume that someone else uses this and that someone generally uses user/pass for authentication not ssh keys, then I can't really "remove" need for password auth.

Or did I miss something here? :P

Lol sorry I misread this , ofc you already thought of that :P
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage