python【第十三篇】可以写一个堡垒机了
前景介绍
到目前为止,很多公司对堡垒机依然不太感冒,其实是没有充分认识到堡垒机在IT管理中的重要作用的,很多人觉得,堡垒机就是跳板机,其实这个认识是不全面的,跳板功能只是堡垒机所具备的功能属性中的其中一项而已,下面我就给大家介绍一下堡垒机的重要性,以帮助大家参考自己公司的业务是否需要部署堡垒机。
堡垒机有以下两个至关重要的功能:
权限管理
当你公司的服务器变的越来越多后,需要操作这些服务器的人就肯定不只是一个运维人员,同时也可能包括多个开发人员,那么这么多的人操作业务系统,如果权限分配不当就会存在很大的安全风险,举几个场景例子:
设想你们公司有300台Linux服务器,A开发人员需要登录其中5台WEB服务器查看日志或进行问题追踪等事务,同时对另外10台hadoop服务器有root权限,在有300台服务器规模的网络中,按常理来讲你是已经使用了ldap权限统一认证的,你如何使这个开发人员只能以普通用户的身份登录5台web服务器,并且同时允许他以管理员的身份登录另外10台hadoop服务器呢?并且同时他对其它剩下的200多台服务器没有访问权限
目前据我了解,很多公司的运维团队为了方面,整个运维团队的运维人员还是共享同一套root密码,这样内部信任机制虽然使大家的工作方便了,但同时存在着极大的安全隐患,很多情况下,一个运维人员只需要管理固定数量的服务器,毕竟公司分为不同的业务线,不同的运维人员管理的业务线也不同,但如果共享一套root密码,其实就等于无限放大了每个运维人员的权限,也就是说,如果某个运维人员想干坏事的话,他可以在几分钟内把整个公司的业务停转,甚至数据都给删除掉。为了降低风险,于是有人想到,把不同业务线的root密码改掉就ok了么,也就是每个业务线的运维人员只知道自己的密码,这当然是最简单有效的方式,但问题是如果你同时用了ldap,这样做又比较麻烦,即使你设置了root不通过ldap认证,那新问题就是,每次有运维人员离职,他所在的业务线的密码都需要重新改一次。
其实上面的问题,我觉得可以很简单的通过堡垒机来实现,收回所有人员的直接登录服务器的权限,所有的登录动作都通过堡垒机授权,运维人员或开发人员不知道远程服务器的密码,这些远程机器的用户信息都绑定在了堡垒机上,堡垒机用户只能看到他能用什么权限访问哪些远程服务器。
在回收了运维或开发人员直接登录远程服务器的权限后,其实就等于你们公司生产系统的所有认证过程都通过堡垒机来完成了,堡垒机等于成了你们生产系统的SSO(single sign on)模块了。你只需要在堡垒机上添加几条规则就能实现以下权限控制了:
允许A开发人员通过普通用户登录5台web服务器,通过root权限登录10台hadoop服务器,但对其余的服务器无任务访问权限
多个运维人员可以共享一个root账户,但是依然能分辨出分别是谁在哪些服务器上操作了哪些命令,因为堡垒机账户是每个人独有的,也就是说虽然所有运维人员共享了一同一个远程root账户,但由于他们用的堡垒账户都是自己独有的,因此依然可以通过堡垒机控制每个运维人员访问不同的机器。
审计管理
审计管理其实很简单,就是把用户的所有操作都纪录下来,以备日后的审计或者事故后的追责。在纪录用户操作的过程中有一个问题要注意,就是这个纪录对于操作用户来讲是不可见的,什么意思?就是指,无论用户愿不愿意,他的操作都会被纪录下来,并且,他自己如果不想操作被纪录下来,或想删除已纪录的内容,这些都是他做不到的,这就要求操作日志对用户来讲是不可见和不可访问的,通过堡垒机就可以很好的实现。
堡垒机架构
堡垒机的主要作用权限控制和用户行为审计,堡垒机就像一个城堡的大门,城堡里的所有建筑就是你不同的业务系统 , 每个想进入城堡的人都必须经过城堡大门并经过大门守卫的授权,每个进入城堡的人必须且只能严格按守卫的分配进入指定的建筑,且每个建筑物还有自己的权限访问控制,不同级别的人可以到建筑物里不同楼层的访问级别也是不一样的。还有就是,每个进入城堡的人的所有行为和足迹都会被严格的监控和纪录下来,一旦发生犯罪事件,城堡管理人员就可以通过这些监控纪录来追踪责任人。
堡垒要想成功完全记到他的作用,只靠堡垒机本身是不够的, 还需要一系列安全上对用户进行限制的配合,堡垒机部署上后,同时要确保你的网络达到以下条件:
- 所有人包括运维、开发等任何需要访问业务系统的人员,只能通过堡垒机访问业务系统
- 回收所有对业务系统的访问权限,做到除了堡垒机管理人员,没有人知道业务系统任何机器的登录密码
- 网络上限制所有人员只能通过堡垒机的跳转才能访问业务系统
- 确保除了堡垒机管理员之外,所有其它人对堡垒机本身无任何操作权限,只有一个登录跳转功能
- 确保用户的操作纪录不能被用户自己以任何方式获取到并篡改
堡垒机功能实现需求
- 兼顾业务安全目标与用户体验,堡垒机部署后,不应使用户访问业务系统的访问变的复杂,否则工作将很难推进,因为没人喜欢改变现状,尤其是改变后生活变得更艰难
- 保证堡垒机稳定安全运行, 没有100%的把握,不要上线任何新系统,即使有100%把握,也要做好最坏的打算,想好故障预案
功能需求:
- 所有的用户操作日志要保留在数据库中
- 每个用户登录堡垒机后,只需要选择具体要访问的设置,就连接上了,不需要再输入目标机器的访问密码
- 允许用户对不同的目标设备有不同的访问权限,例:
- 对10.0.2.34 有mysql 用户的权限
- 对192.168.3.22 有root用户的权限
- 对172.33.24.55 没任何权限
- 分组管理,即可以对设置进行分组,允许用户访问某组机器,但对组里的不同机器依然有不同的访问权限
表结构设计:
表结构示例代码:
#! /usr/bin/env python3
# -*- coding:utf-8 -*- from sqlalchemy import Table, Column, Enum,Integer,String,DateTime, ForeignKey,UniqueConstraint
from sqlalchemy.orm import relationship,sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_utils import ChoiceType
from sqlalchemy import create_engine # 该模块主要定义程序所需的表,及它们之间的相互关系 Base = declarative_base() # 主机和主机账户多对多
user_m2m_bindhost = Table('user_m2m_bindhost', Base.metadata,
Column('userprofile_id', Integer, ForeignKey('user_profile.id')),
Column('bindhost_id', Integer, ForeignKey('bind_host.id')),
) # 主机和主机账户联合唯一表 与 主机分组 多对多
bindhost_m2m_hostgroup = Table('bindhost_m2m_hostgroup', Base.metadata,
Column('bindhost_id', Integer, ForeignKey('bind_host.id')),
Column('hostgroup_id', Integer, ForeignKey('host_group.id')),
) # 主机账户表 与 主机分组 多对多
user_m2m_hostgroup = Table('userprofile_m2m_hostgroup', Base.metadata,
Column('userprofile_id', Integer, ForeignKey('user_profile.id')),
Column('hostgroup_id', Integer, ForeignKey('host_group.id')),
) class Host(Base):
"""定义主机表"""
__tablename__ = 'host'
id = Column(Integer,primary_key=True)
hostname = Column(String(64),unique=True)
ip = Column(String(64),unique=True)
port = Column(Integer,default=22) def __repr__(self):
return self.hostname class HostGroup(Base):
"""主机分组表"""
__tablename__ = 'host_group'
id = Column(Integer, primary_key=True)
name = Column(String(64), unique=True)
# 主机组与(主机及用户联合)多对多,这里可反查。
bind_hosts = relationship("BindHost",secondary="bindhost_m2m_hostgroup",backref="host_groups") def __repr__(self):
return self.name class RemoteUser(Base):
"""主机上的用户名"""
__tablename__ = 'remote_user'
__table_args__ = (UniqueConstraint('auth_type', 'username','password', name='_user_passwd_uc'),) id = Column(Integer, primary_key=True)
AuthTypes = [
('ssh-password','SSH/Password'),
('ssh-key','SSH/KEY'),
]
auth_type = Column(ChoiceType(AuthTypes))
username = Column(String(32))
password = Column(String(128)) def __repr__(self):
return self.username class BindHost(Base):
'''
远程主机ip和主机上的账户表,两者联合唯一。
192.168.1.11 web
192.168.1.11 mysql '''
__tablename__ = "bind_host"
__table_args__ = (UniqueConstraint('host_id','remoteuser_id', name='_host_remoteuser_uc'),) id = Column(Integer, primary_key=True)
host_id = Column(Integer,ForeignKey('host.id'))
remoteuser_id = Column(Integer, ForeignKey('remote_user.id'))
host = relationship("Host",backref="bind_hosts")
remote_user = relationship("RemoteUser",backref="bind_hosts")
audit_logs = relationship('AuditLog')
def __repr__(self):
return "<%s -- %s >" % (self.host.ip,self.remote_user.username) class UserProfile(Base):
"""堡垒机账户"""
__tablename__ = 'user_profile' id = Column(Integer, primary_key=True)
username = Column(String(32),unique=True)
password = Column(String(128))
bind_hosts = relationship("BindHost", secondary='user_m2m_bindhost',backref="user_profiles")
host_groups = relationship("HostGroup",secondary="userprofile_m2m_hostgroup",backref="user_profiles") def __repr__(self):
return self.username class AuditLog(Base):
"""日志记录"""
__tablename__ = 'audit_log'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('user_profile.id'))
bind_host_id = Column(Integer, ForeignKey('bind_host.id'))
action_choices = [
(0, 'CMD'),
(1, 'Login'),
(2, 'Logout'),
(3, 'GetFile'),
(4, 'SendFile'),
(5, 'Exception'),
]
action_choices2 = [
(u'cmd', u'CMD'),
(u'login', u'Login'),
(u'logout', u'Logout'),
# (3,'GetFile'),
# (4,'SendFile'),
# (5,'Exception'),
]
action_type = Column(ChoiceType(action_choices2))
# action_type = Column(String(64))
cmd = Column(String(255))
date = Column(DateTime) user_profile = relationship("UserProfile")
bind_host = relationship("BindHost") def __repr__(self):
return "<bind_host_id:%s -- action_type:%s -- cmd:%s -- date:%s>" % (self.bind_host_id,self.action_type,
self.cmd,self.date) if __name__ == "__main__":
engine = create_engine("mysql+pymysql://root:Root-123@192.168.100.156/test_db?charset=utf8" )
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine) # 创建表结构
# Base.metadata.drop_all(engine) h1 = Host(hostname="host1", ip="192.168.100.156")
h2 = Host(hostname="host2", ip="192.168.100.157")
u1 = RemoteUser(auth_type='ssh-password', username="root", password="admin")
u2 = RemoteUser(auth_type='ssh-password', username="root", password="admin123")
b1 = BindHost(host_id=1, remoteuser_id=1)
b2 = BindHost(host_id=1, remoteuser_id=2)
b3 = BindHost(host_id=2, remoteuser_id=2) g1 = HostGroup(name="bj_group")
g1.bind_hosts = [b1]
g2 = HostGroup(name="sh_group")
g2.bind_hosts = [b2,b3] uh1 = UserProfile(username="lyy1", password="")
uh1.bind_hosts = [b1,b2,b3]
uh1.host_groups = [g1,g2] SessionCls = sessionmaker(bind=engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
session = SessionCls() session.add_all([h1,h2,u1,u2,b1,b2,b3,g1,g2,uh1])
session.commit()
python【第十三篇】可以写一个堡垒机了的更多相关文章
- python 之路,Day27 - 主机管理+堡垒机系统开发
python 之路,Day27 - 主机管理+堡垒机系统开发 本节内容 需求讨论 构架设计 表结构设计 程序开发 1.需求讨论 实现对用户的权限管理,能访问哪些机器,在被访问的机器上有哪些权限 实 ...
- 第二篇 -- Django写一个接口并用Jmeter进行测试
第一节学习了Jmeter的下载和安装,那么第二节就来看看具体怎么使用. 本篇介绍的是使用Jmeter进行http接口测试,那么接口程序使用Django开发的一个小接口. 一.Django编写接口 这一 ...
- linux设备驱动第三篇:写一个简单的字符设备驱动
在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分 ...
- Python开发一个堡垒机
项目实战:运维堡垒机开发 前景介绍 到目前为止,很多公司对堡垒机依然不太感冒,其实是没有充分认识到堡垒机在IT管理中的重要作用的,很多人觉得,堡垒机就是跳板机,其实这个认识是不全面的,跳板功能只是堡垒 ...
- Python基础之用PyQt5写一个tabview
前面学习了menu的画图,现在学习tabview的画图,关于怎么打开designer.exe部分就不详细介绍了. 第一步:拖动一个Tab Widget控件到窗口去. 将控件拖上去之后就是这个样子,默认 ...
- QT学习日记篇-03-仿写一个智能家居界面
课程大纲: <1>让界面漂亮起来,仿写一个智能家居界面 ->第一:给QT工程添加图片 进入下一步: <注意路径和名称一定不能有中文> ...
- Python开发【第九章】:堡垒机实例
一.堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块基于SSH用于连接远程服务器并执行相关操作 模块安装 C:\Program Files\Python 3.5\Scri ...
- Python+Selenium中级篇之-封装一个自己的类-浏览器引擎类
前一篇文章我们知道了,如何去封装几个简单的Selenium方法到我们自定义的类,这次我们编写一个类,叫浏览器引擎类,通过更改一个字符串的值,利用if语句去判断和控制启动那个浏览器.这里我们暂时,支持三 ...
- Python+Selenium基础篇之5-第一个完整的自动化测试脚本
前面文章,我们介绍了如何采用XPath表达式去定位网页元素,在掌握了如何抓取或者如何书写精确的XPath表达式后,我们可以开始写自己的第一个真正意义上的webui 自动化测试脚本,就相当于,你在学习P ...
随机推荐
- kafka rebalance 部分分区没有owner
转发请注明原创地址http://www.cnblogs.com/dongxiao-yang/p/6234673.html 最近业务同学反馈kafka上线的时候某个topic的部分分区一直没有owner ...
- 如何判断Linux是否适合你
如果你厌烦了windows,或者想延长旧pc的寿命,也或者想给小孩使用一款os,linux都能满足你. 开源操作系统linux的关键优势: - 免费的. - 大部分linux软件也是免费的. - li ...
- ios 记录支付宝集成遇到的坑及解决方法
今天项目中要开始动手集成支付宝支付,在此小结一下.(目前新版的支付宝SDK有较大改版,去集成还需要自己去开发平台详细的按照集成步骤来完成https://doc.open.alipay.com/docs ...
- 百度UEditor开发案例(JSP)
本案例的开发环境:MyEclipse+tomcat+jdk 本案例的开发内容: 用百度编辑器发布新闻(UEditor的初始化开发部署) 编辑已发过的新闻(UEditor的应用——编辑旧文章) ...
- springMVC3学习(八)--全球异常处理
在springMVC在配置文件: <bean id="exceptionResolver" class="org.springframework.web.servl ...
- QT皮肤系统的动态切换
应用需求: 提供皮肤切换选项,在不重启应用程序的情况下实现皮肤的动态切换. 理论基础: 1) 图片资源是如何被利用的 这里先简要说明一下实现原理,皮肤的动态切换其关键在于图片资源的加载方式.QT中每个 ...
- 墙裂推荐 iOS 资源大全
这是个精心编排的列表,它包含了优秀的 iOS 框架.库.教程.XCode 插件.组件等等. 这个列表分为以下几个部分:框架( Frameworks ).组件( Components ).测试( Tes ...
- git操作github
转自http://www.cnblogs.com/fnng/archive/2012/01/07/2315685.html 怕找不到~ 本文在我之前的那篇<git/github学习笔记>的 ...
- git提交时的冲突处理
转自http://www.cnblogs.com/mengdd/p/3585038.html 当两条分支对同一个文件的同一个文本块进行了不同的修改,并试图合并时,Git不能自动合并的,称之为冲突(co ...
- android线程与线程池-----AsyncTask(一)《android开发艺术与探索》
线程在android是个重要的概念,从用途上讲,线程分为主线程和子线程,主线程负责页面相关,子线程负责耗时操作. 在android中除了Thread本身还有 AsyncTask IntentServ ...