我的python之路【第十章】堡垒机与数据库操作

在实现堡垒机之前,我们首先要了解paramiko模块

paramiko模块的作用就是基于ssh来连接服务器并执行命令操作的。用于连接远程服务器并执行基本命令大大

  1.基于用户名密码连接-远程执行命令

# 用于连接远程服务器并执行基本命令

import paramiko
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.12.78', port=22, username='root', password='123456')

# 执行命令
stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
result = stdout.read()
print(result.decode())
# 关闭连接
ssh.close()
'''
#SSHClient封装Transport

import paramiko
transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', password='123')

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command('df')
print stdout.read()

transport.close()
'''
用户名密码连接

  2.基于用户名密钥连接-远程执行命令

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#liuhao
import paramiko
#需要将key保存在一个独立的文件中
private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.12.78', port=22, username='root', pkey=private_key)

# 执行命令
stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
result = stdout.read()

# 关闭连接
ssh.close()


'''
#SSHClient封装Transport
import paramiko

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', pkey=private_key)

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command('df')

transport.close()

SSHClient 封装 Transport
'''
用户名密钥连接

  3.基于私钥字符串连接-远程执行命令

import paramiko
from io import StringIO

key_str = """-----BEGIN RSA PRIVATE KEY-----
MIIEoAIBAAKCAQEAofI560WqI22It/D8PfTjnVrZLIjdhlExExAnfL9ZhQEZknew
8gVeThaZKwx/tqa8DIEGbtoYAHr6jBg76IrsPS1sljpWDTlIPt+40eaUZizFNtD9
/k4V6swa45Bvdrk3QWco8EKQyUiNZ8kHmW+0xl5i+cB/5yUX0QujeZN9ooHSsCIo
0GERZT+aJR6PlPaH7R/wLuAMLVRegJIzCu7jRubKBxepINo4AsvWzhI86cMWsS/o
A1brFfnOFeohbXlNuiRpjzbbyXV5OP23BbfnvODpWjnTz+LMaAp5CPmKigyXNVO+
xBCVcobxdV6pKJgoBIeKGOcU6cMlhDjvAZYeGwIBIwKCAQBly3TdBze+f11Aa5c8
4xK6riIb/kIZ6eRVIBjSEeB/fQjCdx7EA1/ZUAiBdZIbCbgH3BKsFA8WPqwdi5Ne
+Dy4vXd0Xy7Ge8cC8wZ1TxtzbJk4Zhv+70D5/KMv9GNR8MOldAsarX+Udr9IjP12
Y3jxt6vtca97WSTpzM0n2Q0kUJn7m14N7TYqikqlzLmfM7kwOximj8zFDwpFFtV3
hTQDAYTPudsE8YC9lTgcJA7uj0O66hPkT90CZu3F+A3g/C8kMKudBS9Q2NDWl4TF
uLk8m+BqvdKf2pIcuxbWMrS8ozaMjbDgKm3qEsazFj7el5oOh+AuzTFrkbSqRio2
UI/7AoGBANek+QKfGorwOzJRrsgHXTLJzSx3iOULtrV0NngrA7ia7viHJm3rM8n+
TxnEyPTgvVQw6/W0AX7DtItVEaowZP0qc4x4Iw8RIyMNuJgsAdxwTxboMGQv9EZt
MSyDZ5SVU4DILHuG4BA/G7ty3QRhC/mqJTap3tvaSpUy0Ev//SdfAoGBAMBAsflJ
qjvrhXy0ZEMnmH/5gGJRQ9W5kV6HK8Rb9FftAQnYYNMiJjh5yYat+KSkxL95z4zY
eUbluMh6QjKc93ntY276XQFx4iEy9voqylj3yGHIOIlEhykqO0sZhxw8+z+k0XtM
7QTh8D+3DMxlbHNxz/pqZLBBbdmfm+t8pG7FAoGAaL3YCJZr+ldtNbKlWdew7Mhq
+FdRHsss28q7XvBSQ7j3uorJhdikIEhSTlhEWa7837/9lJlCjgdJEHnGwGCmFJD2
S4rPMzQ1o0/OsE/jpZWiwfu/u6JDcqoQkfaup0E3L+wy3Om9SbhAq4DvAiCCKM78
Id1639BtXmkjWB1AcjUCgYAxb7i8cgcz+rvs3e3lYfQDpo66Midi1/IuQAPwqe5f
wJnd9c/BQ0uoH1EUANmJbDKXovrbExffB98O+t3SgCJhLmoGmCaLV8xu79kbwdxC
w19pmeKm9F1FGXz2DeDqAQ1oIxFLl3Al07LOjifcyZ+LZmiuG1u4S1bC7oct7NnT
VwKBgFuagfheJiwLkqUMsm6Cwi2+UpNqTC+ZjQ7G0nZtovafC6X0i+opkpMFbJzf
n3Yj+7sLm8sCx3SUhYLEmlhDPuPZflyLuOyz927veXpJGHd9TdaktZhyPX/BdkQh
LRxssxuDBvd8eJagIdCNfDN7TKRkHulwZdCcEP8wb3MPO7oR
-----END RSA PRIVATE KEY-----"""
ssh = paramiko.SSHClient()
private_key = paramiko.RSAKey(file_obj=StringIO(key_str))
# paramiko.RSAKey.from_private_key()
transport = paramiko.Transport(('172.16.50.192', 22))
#注意这里的是pkey
transport.connect(username='root', pkey=private_key)

ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command('df')
result = stdout.read().decode()

ssh.close()

print(result)
私钥字符串连接

  4.基于用户名密码上传下载

import paramiko

transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', password='123')

sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('/tmp/location.py', '/tmp/test.py')
# 将remove_path 下载到本地 local_path
sftp.get('remove_path', 'local_path')

transport.close()
用户名密码上传下载

  5.基于用户名秘钥上传下载

import paramiko

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', pkey=private_key)

sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('/tmp/location.py', '/tmp/test.py')
# 将remove_path 下载到本地 local_path
sftp.get('remove_path', 'local_path')

transport.close()
View Code

 python通过pymysql操作数据

import pymysql

# 创建连接
conn = pymysql.connect(host='172.16.50.192', port=3306, user='root', passwd='123456', db='db')
# 创建游标
cursor = conn.cursor()
username = input('请输入用户名:')
pwd = input('请输入密码:')
# cursor.execute 执行SQL,并返回受影响行数
effect_row = cursor.execute("select * from userinfo where name=%s and password = %s", (username,pwd,))
print(effect_row)
# root or 1==1 --
# adfasdf       会出现sql注入
# sql =  "select * from userinfo where username=%s and pwd = %s" %(username,pwd,)
# select * from userinfo where username=root or 1==1 --  and pwd = %s
# effect_row = cursor.execute(sql)

# 提交,不然无法保存新建或者修改的数据
conn.commit()
#获取返回信息
ret=cursor.fetchall()
print(ret)
# 关闭游标
cursor.close()
# 关闭连接
conn.close()
View Code

 通过以上的内容,我们可以简单的做一个堡垒机的功能了

实现功能:
- 用户登录 (用户表中做验证,id)
通过连接数据库查询user表,实现用户登录验证
- 显示当前用户管理的所有主机列表()
通过输入主机id进行批量管理主机,

- 选中一批机器远程执行命令:
通过线程池批量执行命令:
根据host表中pwd_type类型区分验证方式:用户名密码验证 和 用户名私钥验证
需求介绍

 部分代码展示

1.首先我们要创建一个数据库,这里我使用的是mysql数据库

/*
Navicat MySQL Data Transfer

Source Server         : 172.16.50.192
Source Server Version : 50532
Source Host           : 192.168.0.106:3306
Source Database       : db

Target Server Type    : MYSQL
Target Server Version : 50532
File Encoding         : 65001

Date: 2017-03-31 00:05:49
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for host
-- ----------------------------
DROP TABLE IF EXISTS `host`;
CREATE TABLE `host` (
  `host_id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` char(32) DEFAULT NULL,
  `port` char(32) DEFAULT NULL,
  `username` char(32) DEFAULT NULL,
  `password` text,
  `pwd_type` char(32) DEFAULT NULL,
  PRIMARY KEY (`host_id`),
  UNIQUE KEY `host` (`ip`) USING HASH
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of host
-- ----------------------------
INSERT INTO `host` VALUES ('1', '192.168.0.102', '22', 'root', '123456', 'pwd');
INSERT INTO `host` VALUES ('2', '192.168.0.103', '22', 'root', '-----BEGIN RSA PRIVATE KEY-----\r\nMIIEoAIBAAKCAQEAofI560WqI22It/D8PfTjnVrZLIjdhlExExAnfL9ZhQEZknew\r\n8gVeThaZKwx/tqa8DIEGbtoYAHr6jBg76IrsPS1sljpWDTlIPt+40eaUZizFNtD9\r\n/k4V6swa45Bvdrk3QWco8EKQyUiNZ8kHmW+0xl5i+cB/5yUX0QujeZN9ooHSsCIo\r\n0GERZT+aJR6PlPaH7R/wLuAMLVRegJIzCu7jRubKBxepINo4AsvWzhI86cMWsS/o\r\nA1brFfnOFeohbXlNuiRpjzbbyXV5OP23BbfnvODpWjnTz+LMaAp5CPmKigyXNVO+\r\nxBCVcobxdV6pKJgoBIeKGOcU6cMlhDjvAZYeGwIBIwKCAQBly3TdBze+f11Aa5c8\r\n4xK6riIb/kIZ6eRVIBjSEeB/fQjCdx7EA1/ZUAiBdZIbCbgH3BKsFA8WPqwdi5Ne\r\n+Dy4vXd0Xy7Ge8cC8wZ1TxtzbJk4Zhv+70D5/KMv9GNR8MOldAsarX+Udr9IjP12\r\nY3jxt6vtca97WSTpzM0n2Q0kUJn7m14N7TYqikqlzLmfM7kwOximj8zFDwpFFtV3\r\nhTQDAYTPudsE8YC9lTgcJA7uj0O66hPkT90CZu3F+A3g/C8kMKudBS9Q2NDWl4TF\r\nuLk8m+BqvdKf2pIcuxbWMrS8ozaMjbDgKm3qEsazFj7el5oOh+AuzTFrkbSqRio2\r\nUI/7AoGBANek+QKfGorwOzJRrsgHXTLJzSx3iOULtrV0NngrA7ia7viHJm3rM8n+\r\nTxnEyPTgvVQw6/W0AX7DtItVEaowZP0qc4x4Iw8RIyMNuJgsAdxwTxboMGQv9EZt\r\nMSyDZ5SVU4DILHuG4BA/G7ty3QRhC/mqJTap3tvaSpUy0Ev//SdfAoGBAMBAsflJ\r\nqjvrhXy0ZEMnmH/5gGJRQ9W5kV6HK8Rb9FftAQnYYNMiJjh5yYat+KSkxL95z4zY\r\neUbluMh6QjKc93ntY276XQFx4iEy9voqylj3yGHIOIlEhykqO0sZhxw8+z+k0XtM\r\n7QTh8D+3DMxlbHNxz/pqZLBBbdmfm+t8pG7FAoGAaL3YCJZr+ldtNbKlWdew7Mhq\r\n+FdRHsss28q7XvBSQ7j3uorJhdikIEhSTlhEWa7837/9lJlCjgdJEHnGwGCmFJD2\r\nS4rPMzQ1o0/OsE/jpZWiwfu/u6JDcqoQkfaup0E3L+wy3Om9SbhAq4DvAiCCKM78\r\nId1639BtXmkjWB1AcjUCgYAxb7i8cgcz+rvs3e3lYfQDpo66Midi1/IuQAPwqe5f\r\nwJnd9c/BQ0uoH1EUANmJbDKXovrbExffB98O+t3SgCJhLmoGmCaLV8xu79kbwdxC\r\nw19pmeKm9F1FGXz2DeDqAQ1oIxFLl3Al07LOjifcyZ+LZmiuG1u4S1bC7oct7NnT\r\nVwKBgFuagfheJiwLkqUMsm6Cwi2+UpNqTC+ZjQ7G0nZtovafC6X0i+opkpMFbJzf\r\nn3Yj+7sLm8sCx3SUhYLEmlhDPuPZflyLuOyz927veXpJGHd9TdaktZhyPX/BdkQh\r\nLRxssxuDBvd8eJagIdCNfDN7TKRkHulwZdCcEP8wb3MPO7oR\r\n-----END RSA PRIVATE KEY-----', 'private_key');

-- ----------------------------
-- Table structure for user_to_host
-- ----------------------------
DROP TABLE IF EXISTS `user_to_host`;
CREATE TABLE `user_to_host` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_to_id` int(11) NOT NULL,
  `host_to_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `host_id_wj` (`host_to_id`),
  KEY `user_id_wj` (`user_to_id`),
  CONSTRAINT `host_id_wj` FOREIGN KEY (`host_to_id`) REFERENCES `host` (`host_id`),
  CONSTRAINT `user_id_wj` FOREIGN KEY (`user_to_id`) REFERENCES `userinfo` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_to_host
-- ----------------------------
INSERT INTO `user_to_host` VALUES ('1', '1', '1');
INSERT INTO `user_to_host` VALUES ('2', '1', '2');
INSERT INTO `user_to_host` VALUES ('3', '2', '1');

-- ----------------------------
-- Table structure for user_type
-- ----------------------------
DROP TABLE IF EXISTS `user_type`;
CREATE TABLE `user_type` (
  `type_id` int(2) NOT NULL AUTO_INCREMENT,
  `type` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`type_id`),
  KEY `type` (`type`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_type
-- ----------------------------
INSERT INTO `user_type` VALUES ('2', '普通用户');
INSERT INTO `user_type` VALUES ('1', '管理员');

-- ----------------------------
-- Table structure for userinfo
-- ----------------------------
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(20) NOT NULL,
  `password` char(20) NOT NULL,
  `user_type` int(255) DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  KEY `user_type_wj` (`user_type`),
  CONSTRAINT `user_type_wj` FOREIGN KEY (`user_type`) REFERENCES `user_type` (`type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of userinfo
-- ----------------------------
INSERT INTO `userinfo` VALUES ('1', 'liuhao', 'liuhao', '2');
INSERT INTO `userinfo` VALUES ('2', 'alex', 'alex', '2');
INSERT INTO `userinfo` VALUES ('3', 'administrator', '123456', '1');
View Code

堡垒机程序目录结构

/core/main.py

2.程序主体/core/main.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#liuhao
from concurrent.futures import ThreadPoolExecutor
import paramiko,pymysql
from conf.setting import *
from io import StringIO
import time
import threading



# print(config['host'])
class myconn(object):
    def __init__(self):
        self.user_id=False
        self.all_host=False
        self.pool = ThreadPoolExecutor(5)
        # conn = pymysql.connect(host='172.16.50.192', port=3306, user='root', passwd='123456', db='db')
        self.conn=pymysql.connect(host=config['host'],port=int(config['port']),user=config['user'],passwd=config['passwd'],db=config['db'])
        self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)

    def auth(self):
        self.username = input('请输入用户名:')
        pwd = input('请输入密码:')
        # cursor.execute 执行SQL,并返回受影响行数
        effect_row = self.cursor.execute("select * from userinfo where name=%s and password = %s", (self.username, pwd,))
        if effect_row >0:

        # 提交,不然无法保存新建或者修改的数据
            self.conn.commit()
        # 获取返回信息
            ret = self.cursor.fetchall()
            self.user_id=ret[0]['user_id']
            print(ret)
        # 关闭游标
        # self.cursor.close()
        return self.user_id

    def show_host(self):
        if self.user_id:
            row=self.cursor.execute("select host_id,ip,port,username,pwd_type from user_to_host left join host on user_to_host.host_to_id = host.host_id where user_to_id =%s",(int(self.user_id)))
            if row >0:
                self.all_host=self.cursor.fetchall()
                print('用户:%s 可以管理下列主机:'%self.username)

                for line in self.all_host:
                    print('''
               ID:{host_id}
               IP:{ip}
               Port:{port}
               pwd_type:{pwd_type}
               '''.format(host_id=line['host_id'],ip=line['ip'],port=line['port'],pwd_type=line['pwd_type']))
            else:
                print('用户:%s没有可以管理的主机,请联系管理员!')

            print('\t共计%s台机器'%len(self.all_host))

    def main(self):
        self.user_id=self.auth()
        if self.user_id:
            self.show_host()
            self.command()
    # def show_res(self,res):
        # result=res.result()
        # if result:
            # print('\033[32;1m%s\033[0m' % result.decode())
        # self.ssh.close()

    def excute(self,data):
        #time.sleep(2)
        cmd_str, id_num=data[0],data[1]
        cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute("select ip,port,username,pwd_type,password from host where host_id=%s", (int(id_num)))
        host_data = cursor.fetchall()
        #print(host_data)
        # print('正在执行:',id_num)
        for host in host_data:

            ssh = paramiko.SSHClient()
            if host['pwd_type'] == 'pwd':
                # print('使用密码')
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                ssh.connect(hostname=host['ip'], port=int(host['port']), username=host['username'],
                                 password=host['password'])
                stdin, stdout, stderr = ssh.exec_command(cmd_str)
                result = stdout.read()
                ssh.close()
            elif host['pwd_type']=='private_key':
                # print('使用私钥')
                private_key = paramiko.RSAKey(file_obj=StringIO(host['password']))
                transport = paramiko.Transport((host['ip'], int(host['port'])))
                transport.connect(username=host['username'], pkey=private_key)
                ssh._transport = transport
                stdin, stdout, stderr = ssh.exec_command(cmd_str)
                result = stdout.read()
                ssh.close()
            print('\n\033[34;1m主机:%s 执行结果:\033[0m' % host['ip'])
            if result:
                print('\033[32;1m%s\033[0m' % result.decode())

            # return result


    def command(self):
        while True:
            id_str=input('请输入想要操作的主机id,[批量操作,分割]:').strip(',')
            if not id_str:continue
            id_list=id_str.split(',')
            #print(self.all_host)
            for id_tt in id_list:

                flag = 0
                # if not isinstance(id, int):exit()
                for host in self.all_host:
                    try:

                        if int(id_tt) == host['host_id']:
                            flag+=1
                    except ValueError as e:pass
                if flag==0:
                    print('\033[31;1m ID 错误:%s\033[0m'%id)
                    break
            if flag!=0:
                cmd_str=input('请输入要操作的命令:')

                for id_num in id_list:
                    print('开始执行:',id_num)
                    self.pool.submit(self.excute,(cmd_str,id_num))
                    # print('\033[32;1m%s\033[0m' % fu.result().decode())


def run():
    a=myconn()
    a.main()
View Code

/conf/setting.py

3.配置文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#liuhao

config={
    'host':'192.168.0.106',
    'port':'3306',
    'user':'root',
    'passwd':'123456',
    'db':'db',
}
View Code

/bin/run.py

4.程序启动

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#liuhao

config={
    'host':'192.168.0.106',
    'port':'3306',
    'user':'root',
    'passwd':'123456',
    'db':'db',
}
View Code

 

posted @ 2017-06-05 19:00  saynobody  阅读(572)  评论(0编辑  收藏  举报