Python 13 简单项目-堡垒机

本节内容

项目实战:运维堡垒机开发

前景介绍

到目前为止,很多公司对堡垒机依然不太感冒,其实是没有充分认识到堡垒机在IT管理中的重要作用的,很多人觉得,堡垒机就是跳板机,其实这个认识是不全面的,跳板功能只是堡垒机所具备的功能属性中的其中一项而已,下面我就给大家介绍一下堡垒机的重要性,以帮助大家参考自己公司的业务是否需要部署堡垒机。

堡垒机有以下两个至关重要的功能:

权限管理

当你公司的服务器变的越来越多后,需要操作这些服务器的人就肯定不只是一个运维人员,同时也可能包括多个开发人员,那么这么多的人操作业务系统,如果权限分配不当就会存在很大的安全风险,举几个场景例子:

  1. 设想你们公司有300台Linux服务器,A开发人员需要登录其中5台WEB服务器查看日志或进行问题追踪等事务,同时对另外10台hadoop服务器有root权限,在有300台服务器规模的网络中,按常理来讲你是已经使用了ldap权限统一认证的,你如何使这个开发人员只能以普通用户的身份登录5台web服务器,并且同时允许他以管理员的身份登录另外10台hadoop服务器呢?并且同时他对其它剩下的200多台服务器没有访问权限
  2. 目前据我了解,很多公司的运维团队为了方面,整个运维团队的运维人员还是共享同一套root密码,这样内部信任机制虽然使大家的工作方便了,但同时存在着极大的安全隐患,很多情况下,一个运维人员只需要管理固定数量的服务器,毕竟公司分为不同的业务线,不同的运维人员管理的业务线也不同,但如果共享一套root密码,其实就等于无限放大了每个运维人员的权限,也就是说,如果某个运维人员想干坏事的话,他可以在几分钟内把整个公司的业务停转,甚至数据都给删除掉。为了降低风险,于是有人想到,把不同业务线的root密码改掉就ok了么,也就是每个业务线的运维人员只知道自己的密码,这当然是最简单有效的方式,但问题是如果你同时用了ldap,这样做又比较麻烦,即使你设置了root不通过ldap认证,那新问题就是,每次有运维人员离职,他所在的业务线的密码都需要重新改一次。

其实上面的问题,我觉得可以很简单的通过堡垒机来实现,收回所有人员的直接登录服务器的权限,所有的登录动作都通过堡垒机授权,运维人员或开发人员不知道远程服务器的密码,这些远程机器的用户信息都绑定在了堡垒机上,堡垒机用户只能看到他能用什么权限访问哪些远程服务器。

在回收了运维或开发人员直接登录远程服务器的权限后,其实就等于你们公司生产系统的所有认证过程都通过堡垒机来完成了,堡垒机等于成了你们生产系统的SSO(single sign on)模块了。你只需要在堡垒机上添加几条规则就能实现以下权限控制了:

  1. 允许A开发人员通过普通用户登录5台web服务器,通过root权限登录10台hadoop服务器,但对其余的服务器无任务访问权限
  2. 多个运维人员可以共享一个root账户,但是依然能分辨出分别是谁在哪些服务器上操作了哪些命令,因为堡垒机账户是每个人独有的,也就是说虽然所有运维人员共享了一同一个远程root账户,但由于他们用的堡垒账户都是自己独有的,因此依然可以通过堡垒机控制每个运维人员访问不同的机器。

审计管理

审计管理其实很简单,就是把用户的所有操作都纪录下来,以备日后的审计或者事故后的追责。在纪录用户操作的过程中有一个问题要注意,就是这个纪录对于操作用户来讲是不可见的,什么意思?就是指,无论用户愿不愿意,他的操作都会被纪录下来,并且,他自己如果不想操作被纪录下来,或想删除已纪录的内容,这些都是他做不到的,这就要求操作日志对用户来讲是不可见和不可访问的,通过堡垒机就可以很好的实现。

堡垒机架构

堡垒机的主要作用权限控制和用户行为审计,堡垒机就像一个城堡的大门,城堡里的所有建筑就是你不同的业务系统 , 每个想进入城堡的人都必须经过城堡大门并经过大门守卫的授权,每个进入城堡的人必须且只能严格按守卫的分配进入指定的建筑,且每个建筑物还有自己的权限访问控制,不同级别的人可以到建筑物里不同楼层的访问级别也是不一样的。还有就是,每个进入城堡的人的所有行为和足迹都会被严格的监控和纪录下来,一旦发生犯罪事件,城堡管理人员就可以通过这些监控纪录来追踪责任人。

堡垒要想成功完全记到他的作用,只靠堡垒机本身是不够的, 还需要一系列安全上对用户进行限制的配合,堡垒机部署上后,同时要确保你的网络达到以下条件:

  • 所有人包括运维、开发等任何需要访问业务系统的人员,只能通过堡垒机访问业务系统

    • 回收所有对业务系统的访问权限,做到除了堡垒机管理人员,没有人知道业务系统任何机器的登录密码
    • 网络上限制所有人员只能通过堡垒机的跳转才能访问业务系统
  • 确保除了堡垒机管理员之外,所有其它人对堡垒机本身无任何操作权限,只有一个登录跳转功能
  • 确保用户的操作纪录不能被用户自己以任何方式获取到并篡改  

堡垒机功能实现需求

业务需求:

  1. 兼顾业务安全目标与用户体验,堡垒机部署后,不应使用户访问业务系统的访问变的复杂,否则工作将很难推进,因为没人喜欢改变现状,尤其是改变后生活变得更艰难
  2. 保证堡垒机稳定安全运行, 没有100%的把握,不要上线任何新系统,即使有100%把握,也要做好最坏的打算,想好故障预案

功能需求:

  1. 所有的用户操作日志要保留在数据库中
  2. 每个用户登录堡垒机后,只需要选择具体要访问的设置,就连接上了,不需要再输入目标机器的访问密码
  3. 允许用户对不同的目标设备有不同的访问权限,例:
    1. 对10.0.2.34 有mysql 用户的权限
    2. 对192.168.3.22 有root用户的权限
    3. 对172.33.24.55 没任何权限
  4. 分组管理,即可以对设置进行分组,允许用户访问某组机器,但对组里的不同机器依然有不同的访问权限  

这段sqlalchemy建立表结构的代码就有点凶残了,慢慢看,总而言之,表结构设计好了就没有什么很难的东西了。就是这样,sqlalchemy用多了就熟悉了。

  1 #!/user/bin/env python
  2 # -*-coding: utf-8-*-
  3
  4 from sqlalchemy import Table, Column, String, Integer, create_engine, ForeignKey, UniqueConstraint, DateTime
  5 from sqlalchemy.orm import sessionmaker, relationship
  6 from sqlalchemy.ext.declarative import declarative_base
  7 from sqlalchemy_utils import ChoiceType
  8
  9 Base = declarative_base()  # 生成一个ORM基类
 10
 11 userprofile_2_hostgroup = Table(‘userprofile_2_hostgroup‘, Base.metadata,  # 堡垒机登录名跟主机组的关联关系
 12                                 Column(‘userprofile_id‘, ForeignKey(‘user_profile.id‘)),
 13                                 Column(‘hostgroup_id‘, ForeignKey(‘host_group.id‘))
 14                                 )
 15
 16 bindhost_2_hostgroup = Table("bindhost_2_hostgroup", Base.metadata,
 17                              Column(‘bind_host_id‘, ForeignKey(‘bind_host.id‘)),
 18                              Column(‘host_group_id‘, ForeignKey(‘host_group.id‘))
 19                              )
 20
 21 userprofile_2_bindhost = Table(‘userprofile_2_bindhost‘, Base.metadata,
 22                                Column(‘user_profile_id‘, ForeignKey(‘user_profile.id‘)),
 23                                Column(‘bind_host_id‘, ForeignKey(‘bind_host.id‘))
 24                                )
 25
 26
 27 class UserProfile(Base):
 28     """登陆堡垒机账户表:id, 用户名, 密码"""
 29     __tablename__ = "user_profile"
 30     id = Column(Integer, primary_key=True, autoincrement=True)
 31     username = Column(String(64), unique=True, nullable=False)
 32     password = Column(String(128), unique=True, nullable=False)
 33
 34     host_groups = relationship(‘HostGroup‘, secondary=userprofile_2_hostgroup, backref=‘user_profile‘)
 35     bind_hosts = relationship(‘BindHost‘, secondary=userprofile_2_bindhost, backref=‘user_profile‘)
 36     audit_logs = relationship(‘AuditLog‘)
 37
 38     def __repr__(self):
 39         return "<UserProfile(id=‘%s‘,username=‘%s‘)>" % (self.id,
 40                                                          self.username)
 41
 42
 43 class HostGroup(Base):
 44     """主机组:id, 主机组名称"""
 45     __tablename__ = "host_group"
 46     id = Column(Integer, primary_key=True, autoincrement=True)
 47     name = Column(String(64), unique=True, nullable=False)
 48     user_profiles = relationship(‘UserProfile‘, secondary=userprofile_2_hostgroup, backref=‘host_group‘)
 49     bind_hosts = relationship(‘BindHost‘, secondary=bindhost_2_hostgroup, backref=‘host_group‘)
 50
 51     def __repr__(self):
 52         return "<HostGroup(id=‘%s‘,name=‘%s‘)>" % (self.id,
 53                                                    self.name)
 54
 55
 56 class Host(Base):
 57     """主机列表: id, hostname, ip, port """
 58     __tablename__ = "host"
 59     id = Column(Integer, primary_key=True, autoincrement=True)
 60     hostname = Column(String(64), unique=True, nullable=False)
 61     ip = Column(String(64), unique=True, nullable=False)
 62     port = Column(Integer, default=22)
 63
 64     def __repr__(self):
 65         return "<Host(id=‘%s‘,hostname=‘%s‘)>" % (self.id,
 66                                                   self.hostname)
 67
 68
 69 class RemoteUser(Base):
 70     __tablename__ = "remote_user"
 71     AuthType = [
 72         (u‘ssh-password‘, u‘SSH/Password‘),
 73         (u‘ssh-key‘, u‘SSH/KEY‘)
 74     ]
 75     id = Column(Integer, primary_key=True, autoincrement=True)
 76     username = Column(String(64), nullable=False)
 77     password = Column(String(128))
 78     auth_type = Column(ChoiceType(AuthType))
 79     __table_args__ = (UniqueConstraint(‘auth_type‘, ‘username‘, ‘password‘, name="_user_psd_uc"),)
 80     def __repr__(self):
 81         return "<Remote User(id=‘%s‘, user=‘%s‘, auth_type=‘%s‘)>" % (self.id, self.username, self.auth_type)
 82
 83
 84 class BindHost(Base):
 85     """主机对应主机登陆名关联"""
 86     __tablename__ = ‘bind_host‘
 87     id = Column(Integer, primary_key=True, autoincrement=True)
 88     host_id = Column(Integer, ForeignKey(‘host.id‘))
 89     remote_user_id = Column(Integer, ForeignKey(‘remote_user.id‘))
 90
 91     host = relationship(‘Host‘)
 92     remote_user = relationship(‘RemoteUser‘)
 93     audit_logs = relationship(‘AuditLog‘)
 94     host_groups = relationship("HostGroup", secondary=bindhost_2_hostgroup, backref=‘bind_host‘)
 95     user_profiles = relationship("UserProfile", secondary=userprofile_2_bindhost, backref=‘bind_host‘)
 96
 97     __table_args__ = (UniqueConstraint(‘host_id‘, ‘remote_user_id‘, name=‘_host_remote_user_uc‘), )
 98
 99     def __repr__(self):
100         return "<BindHost(ID=‘%s‘, host_name=‘%s‘, remote_user_name=‘%s‘)>" % (self.id,
101                                                                                self.host.hostname,
102                                                                                self.remote_user.username)
103
104
105 class AuditLog(Base):
106     """audit table 记录user的每一条命令"""
107     __tablename__ = ‘audit_log‘
108     id = Column(Integer, primary_key=True, autoincrement=True)
109     user_id = Column(Integer, ForeignKey(‘user_profile.id‘))
110     bind_host_id = Column(Integer, ForeignKey(‘bind_host.id‘))
111
112     action_list = [
113         (u‘cmd‘, u‘CMD‘),
114         (u‘login‘, u‘Login‘),
115         (u‘logout‘, u‘Logout‘),
116     ]
117
118     action_type = Column(ChoiceType(action_list))
119     cmd = Column(String(255))
120     action_date = Column(DateTime)
121
122     user_profiles = relationship(‘UserProfile‘)
123     bind_hosts = relationship(‘BindHost‘)
124
125     def __repr__(self):
126         return "<Audit Log(user:‘%s‘, host:‘%s‘, action:‘%s‘, cmd:‘%s‘, date time:‘%s‘)>" % 127                (self.user_profiles.username, self.bind_hosts.host.name, self.action_type, self.cmd, self.action_date)
128
129 if __name__ == ‘__main__‘:
130     sql = "mysql+pymysql://root:[email protected]/test1?charset=utf8"
131     engine = create_engine(sql)
132     Base.metadata.create_all(engine)
133
134     SessionCls = sessionmaker(bind=engine)
135     session = SessionCls()
136
137     obj = UserProfile(username=‘dandy‘, password=‘password.1‘)
138     session.add(obj)
139     session.commit()

ssh公钥登录过程

使用密码登录,每次都必须输入密码,非常麻烦。好在SSH还提供了公钥登录,可以省去输入密码的步骤。

所谓"公钥登录",原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个:

  $ ssh-keygen

运行上面的命令以后,系统会出现一系列提示,可以一路回车。其中有一个问题是,要不要对私钥设置口令(passphrase),如果担心私钥的安全,这里可以设置一个。

运行结束以后,在$HOME/.ssh/目录下,会新生成两个文件:id_rsa.pub和id_rsa。前者是你的公钥,后者是你的私钥。

这时再输入下面的命令,将公钥传送到远程主机host上面:

  $ ssh-copy-id [email protected]

好了,从此你再登录,就不需要输入密码了。

附上Alex的代码:https://github.com/triaquae/py3_training/tree/master/%E5%A0%A1%E5%9E%92%E6%9C%BA

  1 # Copyright (C) 2003-2007  Robey Pointer <[email protected]>
  2 #
  3 # This file is part of paramiko.
  4 #
  5 # Paramiko is free software; you can redistribute it and/or modify it under the
  6 # terms of the GNU Lesser General Public License as published by the Free
  7 # Software Foundation; either version 2.1 of the License, or (at your option)
  8 # any later version.
  9 #
 10 # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
 11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 12 # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 13 # details.
 14 #
 15 # You should have received a copy of the GNU Lesser General Public License
 16 # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
 17 # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 18
 19
 20 import socket
 21 import sys
 22 from core import models
 23 import datetime
 24 from paramiko.py3compat import u
 25
 26 # windows does not have termios...
 27 try:
 28     import termios
 29     import tty
 30     has_termios = True
 31 except ImportError:
 32     has_termios = False
 33
 34
 35 def interactive_shell(chan, user_obj, bind_host_obj, log_recording):
 36     if has_termios:
 37         posix_shell(chan, user_obj, bind_host_obj, log_recording)
 38     else:
 39         windows_shell(chan, user_obj, bind_host_obj, log_recording)
 40
 41
 42 def posix_shell(chan, user_obj, bind_host_obj, log_recording):
 43     import select
 44
 45     oldtty = termios.tcgetattr(sys.stdin)
 46     try:
 47         tty.setraw(sys.stdin.fileno())
 48         tty.setcbreak(sys.stdin.fileno())
 49         chan.settimeout(0.0)
 50         cmd_list = []
 51
 52         while True:
 53             r, w, e = select.select([chan, sys.stdin], [], [])
 54             if chan in r:
 55                 try:
 56                     x = u(chan.recv(1024))
 57                     if len(x) == 0:
 58                         sys.stdout.write(‘\r\n*** EOF\r\n‘)
 59                         break
 60                     sys.stdout.write(x)
 61                     sys.stdout.flush()
 62                 except socket.timeout:
 63                     pass
 64             if sys.stdin in r:
 65                 x = sys.stdin.read(1)
 66                 if len(x) == 0:
 67                     break
 68                 if x == ‘\r‘:
 69                     cmd = ‘‘.join(cmd_list)
 70                     obj = models.AuditLog(user_id=user_obj.id,
 71                                           bind_host_id=bind_host_obj.id,
 72                                           action_type=‘cmd‘,
 73                                           cmd=cmd,
 74                                           action_date=datetime.datetime.now())
 75                     log_recording(obj)
 76                     cmd_list.clear()
 77                 else:
 78                     cmd_list.append(x)
 79                 chan.send(x)
 80
 81     finally:
 82         termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
 83
 84
 85 # thanks to Mike Looijmans for this code
 86 def windows_shell(chan, user_obj, bind_host_obj, log_recording):
 87     import threading
 88
 89     sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
 90
 91     def writeall(sock):
 92         while True:
 93             data = sock.recv(256)
 94             if not data:
 95                 sys.stdout.write(‘\r\n*** EOF ***\r\n\r\n‘)
 96                 sys.stdout.flush()
 97                 break
 98             sys.stdout.write(data)
 99             sys.stdout.flush()
100
101     writer = threading.Thread(target=writeall, args=(chan,))
102     writer.start()
103
104     try:
105         while True:
106             d = sys.stdin.read(1)
107             if not d:
108                 break
109             chan.send(d)
110     except EOFError:
111         # user hit ^Z or F6
112         pass

paramiko库里面的文件,稍微修改一下,就可以记录cmd命令了,再写入数据库。
可以去官网下载,文件名interactive.py

时间: 2024-10-10 10:07:52

Python 13 简单项目-堡垒机的相关文章

Python之路:堡垒机实例以及数据库操作

Python之路:堡垒机实例以及数据库操作 一.堡垒机前戏 开发堡垒机之前,先学习Python的paramiko模块,该模块基于SSH用于连接远程服务器并执行相关操作. SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: #!/usr/bin/env  python# --*--coding:utf-8 --*--import paramiko #创建SSH对象ssh = paramiko.SSHClient()# 允许连接不在know_hosts文件中的主机ssh.se

简单的堡垒机模型

刚学python,写了一个简单的堡垒机模型,功能自己添加 #!/usr/bin/env python #coding:utf-8 import MySQLdb import paramiko #connect mysql conn = MySQLdb.connect("218.197.119.18","zhangpan","845896787","baoleiji") cur = conn.cursor() sqlUser =

Python之路,Day13 - 堡垒机

项目实战:运维堡垒机开发 前景介绍 到目前为止,很多公司对堡垒机依然不太感冒,其实是没有充分认识到堡垒机在IT管理中的重要作用的,很多人觉得,堡垒机就是跳板机,其实这个认识是不全面的,跳板功能只是堡垒机所具备的功能属性中的其中一项而已,下面我就给大家介绍一下堡垒机的重要性,以帮助大家参考自己公司的业务是否需要部署堡垒机. 堡垒机有以下两个至关重要的功能: 权限管理 当你公司的服务器变的越来越多后,需要操作这些服务器的人就肯定不只是一个运维人员,同时也可能包括多个开发人员,那么这么多的人操作业务系

使用python 的paramiko制作堡垒机

堡垒机-readme: (数据库为mysql) 1.如果数据库不存在,就创建数据库,对数据库的用户授权,创建表结构,和初始化一些数据 2.如果数据库存在,就跳到下一步 3.用户登录堡垒机进行验证 4.如果此堡垒机用户存在,验证成功,就列出该堡垒机用户所有的主机组,和该用户的主机组里可以使用的主机数量. 5.用户选择某个主机组,就可以看到可用主机和用户的列表. 6.用户选择使用某个用户进入某个主机,或者批量执行命令. 7.如果堡垒机用户,选择使用某个用户进入单台主机,就使用paramiko加载本地

堡垒机的简单应用

堡垒机的定义: 即在一个特定的网络环境下,为了保障网络和数据不受来自外部和内部用户的入侵和破坏,而运用各种技术手段实时收集和监控网络环境中每一个组成部分的系统状态.安全事件.网络活动,以便集中报警.及时处理及审计定责. 堡垒机的功能: 账号管理 设备支持统一账户管理策略,能够实现对所有服务器.网络设备.安全设备等账号进行集中管理 完成对账号整个生命周期的监控 对设备进行特殊角色设置如:审计巡检员.运维操作员.设备管理员等自定义设置,以满足审计需求 账号登陆 支持对X11.linux.unix.数

文成小盆友python-num13 整个堡垒机

本节主要内容: 1.pymsql的使用 2.SQLAchemy使用 3.Paramiko 4.通过ORM功能使用和Paramiko的使用实现一个简单的堡垒机模型. 一.pymsql的使用 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同. 下载安装: pip3 install pymysql 使用 1.执行SQL # -*- coding:utf-8 -*- import pymysql # 创建连接 conn = pymysql.connect(host='

哪些免费堡垒机品牌更好用?

我来说一下,我此前在中小创业企业工作过几年,现在某国企分公司任职运维经理.关于免费堡垒机品牌这个问题,我个人有一些经验之谈分享给大家,不喜勿喷. 一些初创企出于成本的考虑,会考虑找台免费堡垒机来保障运维安全.我用过不同类型的免费堡垒机产品,大体分为开源堡垒机和免费商用堡垒机. 先说下开源堡垒机.大部分开源堡垒机的功能相对简单,就是基础的堡垒机架构,其实并不好用,但上手容易.如果你的公司选开源,可能要考虑后期运维成本的问题,开源堡垒机需要一个即熟悉公司业务又懂Linux和Python的专人进行维护

(转)用Python写堡垒机项目

原文:https://blog.csdn.net/ywq935/article/details/78816860 前言 堡垒机是一种运维安全审计系统.主要的功能是对运维人员的运维操作进行审计和权限控制,风险规避.同时堡垒机还有账号集中管理,单点登陆的功能. 堡垒机有以下两个至关重要的功能: 集中管理 安全审计 当公司的服务器变的越来越多后,需要操作这些服务器的人就肯定不只是一个运维人员,同时也可能包括多个开发人员,那么这么多的人操作业务系统,如果权限分配不当就会存在很大的安全风险,举几个场景例子

Python 13:程序:堡垒机开发

Python 13:程序:堡垒机开发 1.需求 2.表结构 3.readme 4.目录结构 5.代码 6.测试样图 一.需求 功能需求: 1.所有的用户操作日志要保留在数据库中(先存到redis中防止数据断线丢失)2.每个用户登录堡垒机后,只需要选择具体要访问的设置,就连接上了,不需要再输入目标机器的访问密码3.允许用户对不同的目标设备有不同的访问权限,例: 1.对192.168.1.113有mysql 用户的权限 2.对192.168.1.105有root用户的权限 3.对192.168.1.