python连接linux堡垒机_利用Python Paramiko开发linux堡垒机

1.Paramiko模块下的demo.py程序

前面利用Python中的Paramiko模块可以进行SSH的连接,以及用来传送文件(SFTP),但是无论是哪一种方式,连接都是短暂的,并非是长连的,即一次执行一个命令或上传与下载一个文件,显然效率是不如直接使用Linux shell下的ssh连接命令来进行连接。其实在将Paramiko的源码解压出来后,里面有一个demo的文件夹,里面有一个demo.py的程序,利用它,我们就可以进行长连接,即像ssh一样连接远程主机:xpleaf@xpleaf-machine:/mnt/hgfs/Python/day6/sorftwares/demp_test/paramiko-1.7.7.1$ ls

demos  LICENSE      paramiko           PKG-INFO  setup.cfg        setup.py  tests

docs   MANIFEST.in  paramiko.egg-info  README    setup_helper.py  test.py

xpleaf@xpleaf-machine:/mnt/hgfs/Python/day6/sorftwares/demp_test/paramiko-1.7.7.1$ cd demos/

xpleaf@xpleaf-machine:/mnt/hgfs/Python/day6/sorftwares/demp_test/paramiko-1.7.7.1/demos$ ls -l demo.py

-rwxrwxrwx 1 root root 5340  6月 16  2010 demo.py

利用demo.py程序,我们可以进行ssh的长连接,比如这里有一台IP地址为192.168.1.124的远程主机需要进行连接,使用远程主机的账户名为xpleaf,如下:xpleaf@xpleaf-machine:/mnt/hgfs/Python/day6/sorftwares/demp_test/paramiko-1.7.7.1/demos$ python demo.py

Hostname: 192.168.1.124

*** Host key OK.

Username [xpleaf]: xpleaf

Auth by (p)assword, (r)sa key, or (d)ss key? [p]

Password for xpleaf@192.168.1.124:

*** Here we go!

Last login: Fri Oct  9 17:19:42 2015 from 192.168.1.13

[xpleaf@moban ~]$ pwd

/home/xpleaf

这样我们就可以像ssh连接一样在远程主机上执行相关的命令了,下面,我们就是通过观察demo.py程序的源代码来对相关的程序模块作修改,然后实现简单的堡垒主机监控程序的开发。

2.通过修改与demo.py相关的模块来达到堡垒主机监控的功能

堡垒主机可以监控运维人员在服务器上做的命令操作,这里要做的,只是可以监控运维人员在Linux服务器上执行命令的操作,下面先给出这个监控程序的示意图:

运维人员登陆认证示意图:

运维人员命令监控记录示意图:

基于上面两个图示的说明,以及对Paramiko模块中demo.py程序代码的理解,可以对demo.py模块以及相关的模块程序源代码作相应的修改,至于这个引导的过程,因为是Alex老师引导过来的,根据Alex老师修改源代码的一些思想,然后自己再进一步修改其它部分的源代码,所以这整一个探索的过程如果要讲出来,篇幅比较大,这里就不提及了,下面直接给代码:

修改后的demo.py源代码:#!/usr/bin/env python

import base64

from binascii import hexlify

import getpass

import os

import select

import socket

import sys

import threading

import time

import traceback

import paramiko

import interactive

def agent_auth(transport, username):

"""

Attempt to authenticate to the given transport using any of the private

keys available from an SSH agent.

"""

agent = paramiko.Agent()

agent_keys = agent.get_keys()

if len(agent_keys) == 0:

return

for key in agent_keys:

print 'Trying ssh-agent key %s' % hexlify(key.get_fingerprint()),

try:

transport.auth_publickey(username, key)

print '... success!'

return

except paramiko.SSHException:

print '... nope.'

def manual_auth(username, hostname,pw):

'''default_auth = 'p'

auth = raw_input('Auth by (p)assword, (r)sa key, or (d)ss key? [%s] ' % default_auth)

if len(auth) == 0:

auth = default_auth

if auth == 'r':

default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')

path = raw_input('RSA key [%s]: ' % default_path)

if len(path) == 0:

path = default_path

try:

key = paramiko.RSAKey.from_private_key_file(path)

except paramiko.PasswordRequiredException:

password = getpass.getpass('RSA key password: ')

key = paramiko.RSAKey.from_private_key_file(path, password)

t.auth_publickey(username, key)

elif auth == 'd':

default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_dsa')

path = raw_input('DSS key [%s]: ' % default_path)

if len(path) == 0:

path = default_path

try:

key = paramiko.DSSKey.from_private_key_file(path)

except paramiko.PasswordRequiredException:

password = getpass.getpass('DSS key password: ')

key = paramiko.DSSKey.from_private_key_file(path, password)

t.auth_publickey(username, key)

else:

pw = getpass.getpass('Password for %s@%s: ' % (username, hostname))

t.auth_password(username, pw)'''

t.auth_password(username,pw)

# setup logging

paramiko.util.log_to_file('demo.log')

username = ''

if len(sys.argv) > 1:

hostname = sys.argv[1]

if hostname.find('@') >= 0:

username, hostname = hostname.split('@')

else:

hostname = raw_input('Hostname: ')

if len(hostname) == 0:

print '*** Hostname required.'

sys.exit(1)

port = 22

if hostname.find(':') >= 0:

hostname, portstr = hostname.split(':')

port = int(portstr)

# now connect

try:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((hostname, port))

except Exception, e:

print '*** Connect failed: ' + str(e)

traceback.print_exc()

sys.exit(1)

try:

t = paramiko.Transport(sock)

try:

t.start_client()

except paramiko.SSHException:

print '*** SSH negotiation failed.'

sys.exit(1)

try:

keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))

except IOError:

try:

keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))

except IOError:

print '*** Unable to open host keys file'

keys = {}

# check server's host key -- this is important.

key = t.get_remote_server_key()

if not keys.has_key(hostname):

print '*** WARNING: Unknown host key!'

elif not keys[hostname].has_key(key.get_name()):

print '*** WARNING: Unknown host key!'

elif keys[hostname][key.get_name()] != key:

print '*** WARNING: Host key has changed!!!'

sys.exit(1)

else:

print '*** Host key OK.'

# get username

'''if username == '':

default_username = getpass.getuser()

username = raw_input('Username [%s]: ' % default_username)

if len(username) == 0:

username = default_username'''

#changed by xpleaf at 2015.10.9

username = sys.argv[2]

password = sys.argv[3]

sa_username = sys.argv[4]

agent_auth(t, username)

if not t.is_authenticated():

manual_auth(username, hostname,password)

if not t.is_authenticated():

print '*** Authentication failed. :('

t.close()

sys.exit(1)

chan = t.open_session()

chan.get_pty()

chan.invoke_shell()

print '*** Here we go!'

print

interactive.interactive_shell(chan,hostname,username,sa_username)

chan.close()

t.close()

except Exception, e:

print '*** Caught exception: ' + str(e.__class__) + ': ' + str(e)

traceback.print_exc()

try:

t.close()

except:

pass

sys.exit(1)

修改后的interactive.py源代码:import socket

import sys,time

# windows does not have termios...

try:

import termios

import tty

has_termios = True

except ImportError:

has_termios = False

def interactive_shell(chan,hostname,username,sa_username):

if has_termios:

posix_shell(chan,hostname,username,sa_username)

else:

windows_shell(chan)

def posix_shell(chan,hostname,username,sa_username):

import select

date = time.strftime('%Y_%m_%d') #Here is changed!

f = file('/tmp/%s_%s_record.log' % (sa_username,date),'a+') #Here is changed!

record = [] #Here is changed!

oldtty = termios.tcgetattr(sys.stdin)

try:

tty.setraw(sys.stdin.fileno())

tty.setcbreak(sys.stdin.fileno())

chan.settimeout(0.0)

while True:

date = time.strftime('%Y_%m_%d %H:%M:%S') #Here is changed!

r, w, e = select.select([chan, sys.stdin], [], [])

if chan in r:

try:

x = chan.recv(1024)

if len(x) == 0:

print '\r\n*** EOF\r\n',

break

sys.stdout.write(x)

sys.stdout.flush()

except socket.timeout:

pass

if sys.stdin in r:

x = sys.stdin.read(1)

if len(x) == 0:

break

#print x

record.append(x)

chan.send(x)

if x == '\r':    #Here is changed!Follow:

#print record

cmd = ''.join(record).split('\r')[-2]

log = "%s | %s | %s | %s\n" % (hostname,date,sa_username,cmd)

f.write(log)

f.flush()

f.close()    #Here is changed!Above:

finally:

termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)

# thanks to Mike Looijmans for this code

def windows_shell(chan):

import threading

sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")

def writeall(sock):

while True:

data = sock.recv(256)

if not data:

sys.stdout.write('\r\n*** EOF ***\r\n\r\n')

sys.stdout.flush()

break

sys.stdout.write(data)

sys.stdout.flush()

writer = threading.Thread(target=writeall, args=(chan,))

writer.start()

try:

while True:

d = sys.stdin.read(1)

if not d:

break

chan.send(d)

except EOFError:

# user hit ^Z or F6

pass

存放在堡垒主机下的Menus程序,这里命名为run_demo.py:#!/usr/bin/env python

import os,MySQLdb

os.system('clear')

print '='*35

print '''\033[32;1mWelcome to the Connecting System!\033[0m

Choose the Server to connect:

1.DNS Server:  192.168.1.124

2.DHCP Server: 192.168.1.134'''

print '='*35

choice = raw_input('Your choice:')

if choice == '1':

address = '192.168.1.124'

elif choice == '2':

address = '192.168.1.134'

sa_user = 'yonghaoye'

try:

conn = MySQLdb.connect(host = 'localhost', user = 'root', \

passwd = '123456', db = 'Server_list', port = 3306)

cur = conn.cursor()

cur.execute("select * from users where sa = '%s'" % sa_user)

qur_result = cur.fetchall()

for record in qur_result:

if record[3] == address:

hostname = record[3]

username = record[4]

password = record[5]

cur.close()

conn.close()

except MySQLdb.Error,e:

print 'Mysql Error Msg:',e

cmd = 'python /mnt/hgfs/Python/day6/sorftwares/paramiko-1.7.7.1/demos/demo.py %s %s %s %s' % (hostname,username,password,sa_user)

os.system(cmd)

在堡垒主机上添加数据库:添加了下面这样的数据库

mysql> show databases;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| Server_list        |

| ftp_user           |

| linkman            |

| mysql              |

| performance_schema |

| s6py               |

+--------------------+

7 rows in set (0.01 sec)

mysql> use Server_list

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A

Database changed

mysql> show tables;

+-----------------------+

| Tables_in_Server_list |

+-----------------------+

| users                 |

+-----------------------+

1 row in set (0.00 sec)

mysql> describe users;

+-----------------+------------------+------+-----+---------+----------------+

| Field           | Type             | Null | Key | Default | Extra          |

+-----------------+------------------+------+-----+---------+----------------+

| id              | int(10) unsigned | NO   | PRI | NULL    | auto_increment |

| sa              | char(20)         | NO   |     | NULL    |                |

| server_name     | char(20)         | NO   |     | NULL    |                |

| server_address  | char(20)         | NO   |     | NULL    |                |

| server_username | char(20)         | NO   |     | NULL    |                |

| server_password | char(20)         | NO   |     | NULL    |                |

+-----------------+------------------+------+-----+---------+----------------+

6 rows in set (0.00 sec)

mysql> selec * from users;

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'selec * from users' at line 1

mysql> select * from users;

+----+-----------+-------------+----------------+-----------------+-----------------+

| id | sa        | server_name | server_address | server_username | server_password |

+----+-----------+-------------+----------------+-----------------+-----------------+

|  1 | yonghaoye | DNS Server  | 192.168.1.124  | xpleaf          | 123456          |

|  2 | yonghaoye | DHCP Server | 192.168.1.134  | public          | 123456          |

+----+-----------+-------------+----------------+-----------------+-----------------+

2 rows in set (0.00 sec)

就不对数据库中的内容做解释说明了,其实看了前面的示意图,再看这里的代码就可以理解了。

3.监控程序演示

演示的网络环境如下:

由于我在堡垒主机上安装了shellinabox程序,所以在运维人员主机上,可以直接在web界面输入堡垒主机的IP地址进行远程连接,来看下面操作:

(1)运维人员主机登陆堡垒主机

(2)输入堡垒主机账号密码

(3)登陆成功并进入服务器连接列表选择界面

(4)选择连接相应服务器

(5)运维人员执行相关命令

(6)在堡垒主机上查看运维人员的命令操作xpleaf@xpleaf-machine:/tmp$ tail -f yonghaoye_2015_10_10_record.log

192.168.1.124 | 2015_10_10 00:36:44 | yonghaoye | pwd

192.168.1.124 | 2015_10_10 00:36:48 | yonghaoye | whoami

192.168.1.124 | 2015_10_10 00:37:13 | yonghaoye | echo $PATH

可以看到,在堡垒主机上生成了一个相对应用户的命令记录日志文件,这里可以查看用户执行的每一个命令,需要注意的是,这里记录了用户名“yonghaoye”,是堡垒主机上的用户,并不是Linux服务器上面的,该用户是分配给运维人员的,因此,也再一次看到,运维人员并不知道Linux服务器的账户和密码,这样就比较安全了。

3.不足与优化思路

通过上面的操作,这样的一个程序确实是可以记录运维人员在Linux服务器上做的操作,但是不足的是:

(1)程序还存在非常多的细节问题和Bug

(2)界面操作不够人性化

但不管怎么说,这个小程序只是作为学习过程中的一个练习程序而已,但思路基本上是没有问题的,根据上面的两个缺点,往后可以进一步修改源代码以保证程序运行的稳定性,同时对于界面问题,往后应该是要做成Web界面的,而不是借助shellinabox程序,这就需要调用Python中的Django模块来做Web方面的开发,当然还有其它技术。

刚过国庆放假期间,看到Alex老师开发了一个开源的堡垒机监控程序,大家可以去看看,而我这里所的这个小程序,作为入门来学习,其实也是非常不错的。

真的,那就非常了不得了,目前自己也在努力学习过程中,坚持下来就一定可以学到很多!Python不会让我们失望的!

4.对于堡垒主机监控程序的进一步开发计划

由于现在知道的真的是太少,往后会不断学习,希望以后也能以这里这个小程序的思路自己开发一个开源的堡垒主机监控系统,虽然目前已经有开源的了,但作为自己来练手我想也是非常不错的。

文章的思路写得有点唐突,因为实在是很难把这其中学习的一个完整的过程写下来,因为所花费时间非常多。所以我选择了在演示操作里进行了更多的说明,至于源代码的修改,有兴趣的朋友可以对比修改前的代码进行比对的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292232.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一款强大的Kubernetes API流量查看神器

点击上方蓝字关注 👆👆大家好,我是小碗汤,今天分享一个k8s流量查看器~mizu。mizu 是为 Kubernetes 提供的一个简单而强大的 API 流量查看器,可以查看微服务之间的所有 API 通信,以帮助调试和排除故障。相当…

辉光UIView的category

辉光UIView的category 本人视频教程系类 iOS中CALayer的使用 效果如下: 源码: UIViewGlowView.h 与 UIViewGlowView.m // // UIViewGlowView.h // YouXianClock // // Created by YouXianMing on 14-12-21. // Copyright (c) 2014年 YouXianMing. …

javascript 动态创建表格

<html><head><script>function createTable(rows,lines){this.rowsrows;this.lineslines;var Bodydocument.getElementById(body);var Tabledocument.createElement(table);//创建table标签元素Table.setAttribute(border,1);//给table标签添加其他属性for(v…

linux c之加入了加入原文件 math.h调用abs()函数出现implicit declaration of function错误

今天在vim 写C语言的时候 代码我已经导入了#include<math.h> 但是当我调用ads()函数的时候出现了下面错误 解决办法&#xff1a; 把abs函数改写成fabs函数就行&#xff0c;然后去网上找原因&#xff0c;发现fabs是求浮点数的&#xff0c;ads求整形的&#xff0c;以后在…

你的女神今日结婚了!!!你失恋了......

1 新垣结衣结了婚▼2 我和朋友最近的聊天内容&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 白粥盖浇饭&#xff1f;&#xff1f;&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 中国人的辈分可以复杂到什么程度&#xff1f;&#xff08…

我的技术回顾那些与ABP框架有关的故事-2017年

推荐阅读&#xff1a;我的技术回顾那些与ABP框架有关的故事-2015年从ABP框架国内社区发展回顾.NET技术变迁-2016年从2022年来回顾ABP框架&#xff0c;我们会发现无论是商业模式还是架构设计思路&#xff0c;如果没有良好的商业模式的话&#xff0c;ABP框架很容易进入难产的状态…

python之路 mysql 博客园_教为学:Python学习之路(二):MySQLdb的几种安装方式,以及用Python测试连接MySql...

教为学&#xff1a;Python学习之路(二)&#xff1a;MySQLdb的几种安装方式&#xff0c;以及用Python测试连接MySqlEasy_install安装MySQLdb很简单&#xff0c;以至于我不晓得该怎么说。一句话。sodu easy_install mysql-python假如报错了怎么办&#xff1f;报错&#xff0c;我也…

Camera360与全球1.8亿用户共同创造更美的照片

Camera360是成都品果科技有限公司推出的基于IOS、Windows Phone和安卓系统的功能强大的手机摄影软件。能拍摄出不同风格&#xff0c;不同特效的照片&#xff0c;同时具有互联网分享功能。Camera360在全球拥有1.8亿用户&#xff0c;国外0.95亿&#xff0c;国内0.85亿&#xff0c…

八皇后问题(一)

问题描述: 要在8*8的国际象棋棋盘中放8个皇后,使任意两个皇后都不能互相吃掉。规则是皇后能吃掉同一行、同一列、同一对角线的棋子。如下图即是两种方案: 思路: 比如我们搞个数组,数组的下表表示多少行,然后数值表示多少列,比如a[4] = 5,意思就代表第四行,第五列 首先…

CentOS学习笔记--程序管理

程序管理 一个程序被加载到内存当中运行&#xff0c;那么在内存内的那个数据就被称为程序(process)。程序是操作系统上非常重要的概念&#xff0c; 所有系统上面跑的数据都会以程序的型态存在。那么系统的程序有哪些状态&#xff1f;不同的状态会如何影响系统的运行&#xff1f…

linux shell 嵌套expect 与服务器交互脚本

2019独角兽企业重金招聘Python工程师标准>>> 我们与服务器进行交互是该用expect 脚本的&#xff0c;用 “/usr/bin/expect <<-EOF” 来开启expect 脚本 用spawn 来开启一个新的进程 expect 来接受命令&#xff0c;send来发送交互命令 结束用 EOF来over expect…

python读取mysql以html形式输出_python实现处理mysql结果输出方式

在运维过程中&#xff0c;经常需要读取mysql的结果输出并进行响应的处理&#xff0c;这节介绍如何用Python读取mysql结果表并进行相应的整理。进行mysql结果文件输出&#xff1a;mysql -h10.20.10.207 -uroot -ppasswd test -e "select sendorderid, (price*100),mob from…

SkyWalking集成与案例

今天我们通过代码的形式来了解下&#xff0c;如何在项目中使用Skywalking。前几篇文章可以参考&#xff1a;《学习Skywalking 搭建篇》《Skywalking执行效果 多图篇》《Skywalking的ES索引 收藏篇》今天说说代码篇。先说下比较常见的开源 APM 如下&#xff1a;CAT&#xff1…

Windows Azure 安全最佳实践 - 第 6 部分:Azure 服务如何扩展应用程序安全性

多种 Windows Azure服务可以帮助您将应用程序安全性扩展到云。 有三种服务可提供多个提供程序之间的身份标识映射、内部部署数据中心间的连接和相互发送消息的应用程序功能&#xff08;无论应用程序位于何处&#xff09;。 使用Windows Azure Active Directory&#xff0c;您…

2014-11-25nbsp;11:26

爱好&#xff1f; 会网球 羽毛球 确实能扩展社交 转载于:https://www.cnblogs.com/wangduqiang/p/4180834.html

八皇后问题(二)

1、八皇后问题(二) 思路:我们采取回溯的方法来解决,还是那样表示,比如数组a, a[1] = 8;表示这个放在第一行第八列 2、代码实现: #include<stdio.h> #include<math.h>int count = 0; int check_queen(int a[], int n) {for (int i = 1; i < n; i++)if (f…

Windows Server 2012活动目录基础配置与应用(新手教程)之3---将客户机加入到指定域...

在WIN 2012服务器上安装AD后&#xff0c;WIN2012就从普通的服务器变成了域控制器。一个域也就产生了。但遗憾的是&#xff0c;目前这个域的规模还很小&#xff0c;只有DC这一台主机-------光杆司令&#xff01;&#xff01;下面尝试扩大域的规模&#xff0c;将客户机加入到域。…

论物理学界的神预言

全世界只有3.14 % 的人关注了爆炸吧知识一沙见世界 一花窥天堂手心握无限 须臾纳永恒杨振宁曾说读上面的四句诗可以感受到物理的美但物理的美不止于此物理还有一种庄严美一种神秘美一种初窥宇宙奥秘的畏惧美物理就是如此的迷人任何语言在它的面前都很贫瘠数学让人摆脱了愚昧而…