第十三章 堡垒机
1.堡垒机的概念
2.堡垒机的实现
概念:
背景,公司为了主机系统的管理和安全,更有效的工作,产生的一种工作模式,往往一个公司有很多台服务器,这些服务器又有许多人需要去操作,运维、开发、测试等。人多
手杂,谁操作了什么,导致了什么问题,用户的管理。主机的管理,都需要高效的实现,堡垒机实现了这些管理上的方便。
直接说事
堡垒机执行流程:
1、管理员为用户在服务器上创建帐号(将公钥放置服务器,或者使用用户名密码)
2、用户登录堡垒机,输入堡垒机用户名密码,现实当前用户管理的服务器列表
3、用户选择服务器,并自动登录
4、执行操作并同时将用户操作记录
注:配置.brashrc实现ssh登录后自动执行脚本,如:/usr/bin/python /home/wulaoer/menu.py
实现过程
步骤一,使用用户登录
1 #!/usr/bin/env python
2 # --*--coding:utf-8 --*--
3 import getpass
4
5 user = raw_input('username:')
6 pwd = getpass.getpass('password:')
7 if user == 'wulaoer' and pwd == '123':
8 print '登陆成功'
9 else:
10 print '登陆失败'
步骤二,根据用户获取相关服务器列表
1 dic = {
2 'laowu': [
3 '172.16.103.189',
4 'c10.puppet.com',
5 'c11.puppet.com',
6 ],
7 'wu': [
8 'c100.puppet.com',
9 ]
10 }
11
12 host_list = dic['laowu']
13 #用户可以连接的主机IP
14 print 'please select:'
15 for index, item in enumerate(host_list, 1):
16 print index, item
17 #循环可以连接的主机
18 inp = raw_input('your select (No):')#选择要连接的IP
19 inp = int(inp)
20 hostname = host_list[inp-1]#连接的主机IP
21 port = 22
步骤三,根据用户名、私钥登录服务器
1 tran = paramiko.Transport((hostname, port,))
2 #连接服务器的端口和IP
3 tran.start_client()
4 default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
5 #连接方式,使用密钥
6 key = paramiko.RSAKey.from_private_key_file(default_path)
7 #密钥默认路径
8 tran.auth_publickey('wulaoer', key)
9 #连接用户名和密钥
10
11 # 打开一个通道
12 chan = tran.open_session()
13 # 获取一个终端
14 chan.get_pty()
15 # 激活器
16 chan.invoke_shell()
17
18 #########
19 # 利用sys.stdin,肆意妄为执行操作
20 # 用户在终端输入内容,并将内容发送至远程服务器
21 # 远程服务器执行命令,并将结果返回
22 # 用户终端显示内容
23 #########
用户监控日志:
1 while True:
2 # 监视用户输入和服务器返回数据
3 # sys.stdin 处理用户输入
4 # chan 是之前创建的通道,用于接收服务器返回信息
5 readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1)
6 if chan in readable:
7 try:
8 x = chan.recv(1024)
9 if len(x) == 0:
10 print '\r\n*** EOF\r\n',
11 break
12 sys.stdout.write(x)
13 sys.stdout.flush()
14 except socket.timeout:
15 pass
16 if sys.stdin in readable:
17 inp = sys.stdin.readline()
18 chan.sendall(inp)
1 # 获取原tty属性
2 oldtty = termios.tcgetattr(sys.stdin)
3 try:
4 # 为tty设置新属性
5 # 默认当前tty设备属性:
6 # 输入一行回车,执行
7 # CTRL+C 进程退出,遇到特殊字符,特殊处理。
8
9 # 这是为原始模式,不认识所有特殊符号
10 # 放置特殊字符应用在当前终端,如此设置,将所有的用户输入均发送到远程服务器
11 tty.setraw(sys.stdin.fileno())
12 chan.settimeout(0.0)
13
14 while True:
15 # 监视 用户输入 和 远程服务器返回数据(socket)
16 # 阻塞,直到句柄可读
17 r, w, e = select.select([chan, sys.stdin], [], [], 1)
18 if chan in r:
19 try:
20 x = chan.recv(1024)
21 if len(x) == 0:
22 print '\r\n*** EOF\r\n',
23 break
24 sys.stdout.write(x)
25 sys.stdout.flush()
26 except socket.timeout:
27 pass
28 if sys.stdin in r:
29 x = sys.stdin.read(1)
30 if len(x) == 0:
31 break
32 chan.send(x)
33
34 finally:
35 # 重新设置终端属性
36 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
1 def windows_shell(chan):
2 import threading
3
4 sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
5
6 def writeall(sock):
7 while True:
8 data = sock.recv(256)
9 if not data:
10 sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
11 sys.stdout.flush()
12 break
13 sys.stdout.write(data)
14 sys.stdout.flush()
15
16 writer = threading.Thread(target=writeall, args=(chan,))
17 writer.start()
18
19 try:
20 while True:
21 d = sys.stdin.read(1)
22 if not d:
23 break
24 chan.send(d)
25 except EOFError:
26 # user hit ^Z or F6
27 pass
注:密码验证t.auth_password(username,pw)
详见:paramiko源码demo
A wise man thinks all that he says, a fool says all that he thinks.