pexpect實現linux免密鑰登陸

免密鑰登錄

  1. 配置主機的hostname 使用hostnamectl命令:python

    • 查看主機的hostname信息:hostnamectl status
    • 修改主機的hostname信息:hostnamectl set-hostname "hgfx5"
  2. 配置ssh 在/etc/ssh/sshd_config中,添加如向兩行:bash

RSAAuthentication yes
PubkeyAuthentication yes

使得主機ssh接受RSA認證。服務器

sshd_configssh_config的區別:app

  1. sshd_config:配置服務器提供ssh服務的配置文件。
  2. ssh_config:配置客戶端經過ssh鏈接到本機的配置文件。
  1. 修改相關目錄權限並重起ssh服務 .ssh700 authorized_keys 600 service sshd restartssh

  2. 仍是須要登陸密碼的問題: 出現問題後,查看/var/log/securethis

  3. 從A ssh鏈接到B,發現錯誤:Address 192.168.1.106 maps to localhost, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!。 解決辦法:在A的ssh客戶端的配置文件中,修改/etc/ssh/ssh_config文件中的GSSAPIAuthentication yesGSSAPIAuthentication no 2. 登陸時顯示No route to host:兩主機再也不一個局域網下面,試試互相ping的通?spa

  4. pexpect實現自動免密鑰登陸rest

#! /usr/bin/python
# coding:utf-8

import pexpect
import sys
import copy

__author__ = 'hgf'

class Host:
    def __init__(self,ip,user,password):
        self.ip=ip
        self.user=user
        self.userpass=password

class AutoPassword:
    '''
     一個一個輸入,實現初始化,server 爲Host的一個對象,slaves時Host對象列表,all表示是否只能服務器免密鑰訪問slaves
    '''
    def __init__(self, server, slaves, all):
        self.sever=server
        self.slaves=slaves
        self.all = all
        self.fout = file('log.txt','w')
        fout = file('log.txt','w')

    def readhostsfromfile(self, filenamepath, all):
        '''
        文件初始化server和slave,文件的格式IP:username:password。其中username和password中不能出現:號,默認第一行是server,其他爲slaves;all同上
        :param filenamepath:從文件讀取服務器信息
        :param all:
        :return:
        '''
        self.all = all
        self.slaves=[]
        self.fout = file('log.txt','w')
        fhandle = open(filenamepath,'r')
        first = True
        for line in fhandle.readlines():
            info = line.split(":")
            host = Host(info[0], info[1], info[2])
            if(first == True):
                self.server = host
                first=False
            else:
                self.slaves.append(host)

    def check_hosts_files(self):
        '''
        將全部的主機所有檢查一遍,若all=True,則將全部其餘主機生成的密鑰scp到server;若all=False,則server把密鑰發到其餘主機,而且設置免密鑰登陸
        1.  對每個slaves主機:
        3.  將攝製好的sshd——config傳到slave主機:1》傳到某個目錄;2》sudo mv到系統目錄
        4.  將slave的公鑰傳到server
        5.  將全部的slave主機的公鑰》authorised_keys
        6.  all=True
        7.  將server的密鑰也放入authorised_keys文件
        8. 將authorised_keys文將複製到每一個slave文件
        9.  ssh到slave主機
            》修改.ssh目錄的權限,authorized_keys的權限
        10.  重起slave的ssh服務
        11.
        :return:
        '''
        # 建立authorized_keys文件,並間server的公鑰複製進去
        server_home = self.generatepath(server)+'/'
        self.child = pexpect.spawn('touch '+ server_home+'authorized_keys')
        self.child.logfile = self.fout
        index = self.child.expect(['#', pexpect.EOF])
        if index == 0:
            print index,':OK'
        else:
            print 'OK'

        self.cat2file(server_home+'.ssh/id_rsa.pub', server_home+'authorized_keys', True, True)#server的公鑰拷貝到authorized_keys文件,直接覆蓋,以避免裏面有以前的數據
        for slave in self.slaves:
            home = self.generatepath(slave)+'/'
            sshd_conf_file = 'sshd_config'
            self.scp_local_file(sshd_conf_file, home, slave)# 將本地的sshd配置文件傳到slave主機
            self.scp2local_file(home+'.ssh/id_rsa.pub', server_home+'id_rsa.pub.'+slave.ip, slave)# 將slave的公鑰複製到server
            self.cat2file(server_home+'id_rsa.pub.'+slave.ip, server_home+'authorized_keys', False, True)# 將slaves的公鑰拷貝進authorized_keys文件

        for slave in self.slaves:# 將authorized_keys複製到每一個slave主機
            home = self.generatepath(slave)+'/'
            self.scp_local_file(server_home+'authorized_keys', home+'.ssh/',slave)

        for slave in self.slaves:
            home = self.generatepath(slave)+'/'
            sshd_conf_file = 'sshd_config'
            sshd_conf_dir = '/etc/ssh/'
            self.ssh_remote(slave)
            self.mv_file(home+sshd_conf_file, sshd_conf_dir+ sshd_conf_file, slave, True)
            self.chmod(home+'.ssh', '700')
            self.chmod(home+'.ssh/authorized_keys', '600')
            self.child.close()
        if all:# 若是所有互相免密鑰鏈接
            self.child = pexpect.spawn('ls')# 將authorized_keys複製到server的.ssh目錄下
            self.child.logfile = self.fout
            index = self.child.expect(['autho',pexpect.EOF])
            print index
            self.mv_file(server_home+'authorized_keys', server_home+'.ssh/authorized_keys', server)
            self.chmod(server_home+'.ssh/authorized_keys', '600')
            self.chmod(server_home+'.ssh', '700')

    def mv_file(self, frompath, topath, host, needroot=False):
        '''
        移動一個文件
        :param frompath: 移動的文件原來的路徑
        :param topath: 文件移動後的路徑
        :param host:移動文件的主機
        :param needroot:是否須要root權限,True須要,默認爲False
        :return:
        '''
        str = 'mv '+ frompath+' '+ topath
        if needroot:
            str = 'sudo '+ str
        self.child.sendline(str)
        index = self.child.expect(['(?i)password', '#', pexpect.EOF])
        if index == 0:
            self.child.sendline(host.userpass)
            self.child.expect('#')
        elif index == 1:
            pass
        elif index==2:
            print '緩衝區沒有數據,host ip:'+host.ip

    def cat2file(self, srcpath, destpath, overriwter=True, isserver=False):
        '''
        將文件重定向到文件
        :param srcpath:源文件路徑
        :param destpath:目標文件路徑
        :param overriwter 是否覆蓋,True,直接覆蓋
        :param isserver 是不是時主控端
        :return:
        '''
        if overriwter:
            self.childcat = pexpect.spawn('/bin/bash -c "cat '+ srcpath+' > '+ destpath+'"')
        else:
            self.childcat = pexpect.spawn('/bin/bash -c "cat '+ srcpath+' >> '+ destpath+'"')

        self.childcat.logfile=self.fout
        if isserver:
            self.child.expect(pexpect.EOF)
        else:
            self.child.expect('#')
        self.childcat.close()
        self.child.logfile = self.fout

    def chmod(self, filepath, mod):
        '''
        修改文件權限
        :param filepath:文件路徑
        :param mod:賦予的權限
        :return:
        '''
        self.child.sendline('chmod '+ mod +' '+ filepath)
        index = self.child.expect(['#',pexpect.EOF])
        if index ==1:
            print '緩衝區無數據'


    def scp2local_file(self, filefrompath, filetopath, hostfrom):
        '''
        將遠程文件傳送到本地
        :param filefrompath:遠程主機上的路徑
        :param filetopath:本地主機上的路徑
        :param hostfrom:文件來源主機
        :return:
        '''
        self.childscp = pexpect.spawn('scp '+hostfrom.user +'@' + hostfrom.ip + ':' + filefrompath +' '+filetopath)
        self.childscp.logfile = self.fout
        index = self.childscp.expect(['(?i)are you', '(?i)password', pexpect.EOF, pexpect.TIMEOUT])
        print index
        if index==0:# 之前從未登陸過這個IP
            self.childscp.sendline('yes')
            self.childscp.expect('(?i)password')
            self.childscp.sendline(hostfrom.userpass)
            self.childscp.expect('%')
        elif index==1:
            self.childscp.sendline(hostfrom.userpass)
            self.childscp.expect('%')
        elif index==2:# 緩衝區沒有數據了
            print 'EOF, check log file please.'
        elif index==3:# 鏈接超時
            print 'connection timeout, check log file please.'
        self.childscp.close()
        self.child.logfile = self.fout

    def scp_local_file(self, filefrompath, filetopath, hostto):
        '''
        使用scp傳輸本地文件文件
        :param filefrompath: 文件源路徑
        :param filetopath: 文件移動到目的主機上的路徑
        :param hostto: 想要移動到的主機的名字
        :return:
        '''
        self.childscp = pexpect.spawn('scp '+ filefrompath +' '+hostto.user +'@' + hostto.ip+':'+filetopath)
        self.childscp.logfile = self.fout
        index = self.childscp.expect(['(?i)are you', '(?i)password', pexpect.EOF, pexpect.TIMEOUT])
        print index
        if index==0:# 之前從未登陸過這個IP
            self.childscp.sendline('yes')
            self.childscp.expect('(?i)password')
            self.childscp.sendline(hostto.userpass)
            self.childscp.expect('%')
        elif index==1:
            self.childscp.sendline(hostto.userpass)
            self.childscp.expect('%')
        elif index==2:# 緩衝區沒有數據了
            print 'EOF, check log file please.'
        elif index==3:# 鏈接超時
            print 'connection timeout, check log file please.'
        self.childscp.close()
        self.child.logfile=self.fout

    def generate_rsa(self, hostfrom, hostto):
        '''
        產生密鑰文件
        :param hostfrom: 生成rsa密鑰的主機
        :param hostto: rsa公鑰的傳送目的地
        :return:
        '''
        self.child.sendline('rm -rf '+ self.generatepath(hostfrom)+'/.ssh')
        self.child.expect('#')
        self.child.sendline('ssh-keygen -t rsa')
        self.child.expect('(?i)enter')
        self.child.sendline('\r\n')
        index = self.child.expect('(?i)enter')
        self.child.sendline('\r\n')
        self.child.expect('(?i)enter')
        self.child.sendline('\r\n')
        self.scp_local_file(self.generatepath(hostfrom)+'/.ssh/id_rsa.pub', self.generatepath(hostto)+'id_rsa.pub'+hostfrom.ip, hostto )

    def generatepath(self, host):
        '''
        根據用戶名得到用戶目錄
        :param host: 當前操做的主機
        :return:
        '''
        if host.user=='root':
            return '/root'
        else:
            return '/home/'+host.user

    def ssh_remote(self, hostto):
        '''
        使用ssh鏈接到遠程主機
        :param hostto: 想要鏈接的主機
        :return:
        '''
        self.child = pexpect.spawn( str( 'ssh %s@%s' % (hostto.user, hostto.ip) ) )
        self.child.logfile = self.fout
        index = self.child.expect(['(?i)are you', '(?i)password', '(?i)continue connecting (yes/no)?','(?i)Last login', pexpect.EOF, pexpect.TIMEOUT])
        print index
        if index==0:# 之前從未登陸過這個IP
            self.child.sendline('yes')
            self.child.expect('(?i)password')
            self.child.sendline(hostto.userpass)
            self.child.expect('#')
        elif index==1:
            self.child.sendline(hostto.userpass)
            self.child.expect('#')
        elif index==2 or index==3:# 已經能夠免密碼登陸,
            print "already ssh without password, remove from unchcecked list"
            self.child.expect('#')
        elif index==4:# 緩衝區沒有數據了
            print 'EOF, check log file please.'
        elif index==5:# 鏈接超時
            self.child.read()
            self.child.close()
            print 'connection timeout, check log file please.'
            sys.exit(-1)

if __name__=='__main__':
    # test ssh_remote
    server=Host('192.168.122.1','hgf','hgfgood')
    slave=Host('192.168.122.190','root','hgfgood')
    slaves=[]
    slaves.append(slave)
    inst = AutoPassword(server,slaves, False)
    inst.check_hosts_files()
相關文章
相關標籤/搜索