到目前为止,很多公司对堡垒机依然不太感冒,其实是没有充分认识到堡垒机在IT管理中的重要作用的,很多人觉得,堡垒机就是跳板机,其实这个认识是不全面的,跳板功能只是堡垒机所具备的功能属性中的其中一项而已,下面我就给大家介绍一下堡垒机的重要性,以帮助大家参考自己公司的业务是否需要部署堡垒机。
堡垒机有以下两个至关重要的功能:
当你公司的服务器变的越来越多后,需要操作这些服务器的人就肯定不只是一个运维人员,同时也可能包括多个开发人员,那么这么多的人操作业务系统,如果权限分配不当就会存在很大的安全风险,举几个场景例子:
其实上面的问题,我觉得可以很简单的通过堡垒机来实现,收回所有人员的直接登录服务器的权限,所有的登录动作都通过堡垒机授权,运维人员或开发人员不知道远程服务器的密码,这些远程机器的用户信息都绑定在了堡垒机上,堡垒机用户只能看到他能用什么权限访问哪些远程服务器。
在回收了运维或开发人员直接登录远程服务器的权限后,其实就等于你们公司生产系统的所有认证过程都通过堡垒机来完成了,堡垒机等于成了你们生产系统的SSO(single sign on)模块了。你只需要在堡垒机上添加几条规则就能实现以下权限控制了:
审计管理其实很简单,就是把用户的所有操作都纪录下来,以备日后的审计或者事故后的追责。在纪录用户操作的过程中有一个问题要注意,就是这个纪录对于操作用户来讲是不可见的,什么意思?就是指,无论用户愿不愿意,他的操作都会被纪录下来,并且,他自己如果不想操作被纪录下来,或想删除已纪录的内容,这些都是他做不到的,这就要求操作日志对用户来讲是不可见和不可访问的,通过堡垒机就可以很好的实现。
堡垒机的主要作用权限控制和用户行为审计,堡垒机就像一个城堡的大门,城堡里的所有建筑就是你不同的业务系统 , 每个想进入城堡的人都必须经过城堡大门并经过大门守卫的授权,每个进入城堡的人必须且只能严格按守卫的分配进入指定的建筑,且每个建筑物还有自己的权限访问控制,不同级别的人可以到建筑物里不同楼层的访问级别也是不一样的。还有就是,每个进入城堡的人的所有行为和足迹都会被严格的监控和纪录下来,一旦发生犯罪事件,城堡管理人员就可以通过这些监控纪录来追踪责任人。
堡垒要想成功完全记到他的作用,只靠堡垒机本身是不够的, 还需要一系列安全上对用户进行限制的配合,堡垒机部署上后,同时要确保你的网络达到以下条件:
表结构设计:
表结构示例代码:
1 #! /usr/bin/env python3
2 # -*- coding:utf-8 -*-
3
4 from sqlalchemy import Table, Column, Enum,Integer,String,DateTime, ForeignKey,UniqueConstraint
5 from sqlalchemy.orm import relationship,sessionmaker
6 from sqlalchemy.ext.declarative import declarative_base
7 from sqlalchemy_utils import ChoiceType
8 from sqlalchemy import create_engine
9
10
11 # 该模块主要定义程序所需的表,及它们之间的相互关系
12
13
14 Base = declarative_base()
15
16 # 主机和主机账户多对多
17 user_m2m_bindhost = Table('user_m2m_bindhost', Base.metadata,
18 Column('userprofile_id', Integer, ForeignKey('user_profile.id')),
19 Column('bindhost_id', Integer, ForeignKey('bind_host.id')),
20 )
21
22 # 主机和主机账户联合唯一表 与 主机分组 多对多
23 bindhost_m2m_hostgroup = Table('bindhost_m2m_hostgroup', Base.metadata,
24 Column('bindhost_id', Integer, ForeignKey('bind_host.id')),
25 Column('hostgroup_id', Integer, ForeignKey('host_group.id')),
26 )
27
28 # 主机账户表 与 主机分组 多对多
29 user_m2m_hostgroup = Table('userprofile_m2m_hostgroup', Base.metadata,
30 Column('userprofile_id', Integer, ForeignKey('user_profile.id')),
31 Column('hostgroup_id', Integer, ForeignKey('host_group.id')),
32 )
33
34
35 class Host(Base):
36 """定义主机表"""
37 __tablename__ = 'host'
38 id = Column(Integer,primary_key=True)
39 hostname = Column(String(64),unique=True)
40 ip = Column(String(64),unique=True)
41 port = Column(Integer,default=22)
42
43 def __repr__(self):
44 return self.hostname
45
46
47 class HostGroup(Base):
48 """主机分组表"""
49 __tablename__ = 'host_group'
50 id = Column(Integer, primary_key=True)
51 name = Column(String(64), unique=True)
52 # 主机组与(主机及用户联合)多对多,这里可反查。
53 bind_hosts = relationship("BindHost",secondary="bindhost_m2m_hostgroup",backref="host_groups")
54
55 def __repr__(self):
56 return self.name
57
58
59 class RemoteUser(Base):
60 """主机上的用户名"""
61 __tablename__ = 'remote_user'
62 __table_args__ = (UniqueConstraint('auth_type', 'username','password', name='_user_passwd_uc'),)
63
64 id = Column(Integer, primary_key=True)
65 AuthTypes = [
66 ('ssh-password','SSH/Password'),
67 ('ssh-key','SSH/KEY'),
68 ]
69 auth_type = Column(ChoiceType(AuthTypes))
70 username = Column(String(32))
71 password = Column(String(128))
72
73 def __repr__(self):
74 return self.username
75
76
77 class BindHost(Base):
78 '''
79 远程主机ip和主机上的账户表,两者联合唯一。
80 192.168.1.11 web
81 192.168.1.11 mysql
82
83 '''
84 __tablename__ = "bind_host"
85 __table_args__ = (UniqueConstraint('host_id','remoteuser_id', name='_host_remoteuser_uc'),)
86
87 id = Column(Integer, primary_key=True)
88 host_id = Column(Integer,ForeignKey('host.id'))
89 remoteuser_id = Column(Integer, ForeignKey('remote_user.id'))
90 host = relationship("Host",backref="bind_hosts")
91 remote_user = relationship("RemoteUser",backref="bind_hosts")
92 audit_logs = relationship('AuditLog')
93 def __repr__(self):
94 return "<%s -- %s >" % (self.host.ip,self.remote_user.username)
95
96
97 class UserProfile(Base):
98 """堡垒机账户"""
99 __tablename__ = 'user_profile'
100
101 id = Column(Integer, primary_key=True)
102 username = Column(String(32),unique=True)
103 password = Column(String(128))
104 bind_hosts = relationship("BindHost", secondary='user_m2m_bindhost',backref="user_profiles")
105 host_groups = relationship("HostGroup",secondary="userprofile_m2m_hostgroup",backref="user_profiles")
106
107 def __repr__(self):
108 return self.username
109
110
111
112 class AuditLog(Base):
113 """日志记录"""
114 __tablename__ = 'audit_log'
115 id = Column(Integer, primary_key=True)
116 user_id = Column(Integer, ForeignKey('user_profile.id'))
117 bind_host_id = Column(Integer, ForeignKey('bind_host.id'))
118 action_choices = [
119 (0, 'CMD'),
120 (1, 'Login'),
121 (2, 'Logout'),
122 (3, 'GetFile'),
123 (4, 'SendFile'),
124 (5, 'Exception'),
125 ]
126 action_choices2 = [
127 (u'cmd', u'CMD'),
128 (u'login', u'Login'),
129 (u'logout', u'Logout'),
130 # (3,'GetFile'),
131 # (4,'SendFile'),
132 # (5,'Exception'),
133 ]
134 action_type = Column(ChoiceType(action_choices2))
135 # action_type = Column(String(64))
136 cmd = Column(String(255))
137 date = Column(DateTime)
138
139 user_profile = relationship("UserProfile")
140 bind_host = relationship("BindHost")
141
142 def __repr__(self):
143 return "<bind_host_id:%s -- action_type:%s -- cmd:%s -- date:%s>" % (self.bind_host_id,self.action_type,
144 self.cmd,self.date)
145
146
147 if __name__ == "__main__":
148 engine = create_engine("mysql+pymysql://root:Root-123@192.168.100.156/test_db?charset=utf8" )
149 Base.metadata.drop_all(engine)
150 Base.metadata.create_all(engine) # 创建表结构
151 # Base.metadata.drop_all(engine)
152
153 h1 = Host(hostname="host1", ip="192.168.100.156")
154 h2 = Host(hostname="host2", ip="192.168.100.157")
155 u1 = RemoteUser(auth_type='ssh-password', username="root", password="admin")
156 u2 = RemoteUser(auth_type='ssh-password', username="root", password="admin123")
157 b1 = BindHost(host_id=1, remoteuser_id=1)
158 b2 = BindHost(host_id=1, remoteuser_id=2)
159 b3 = BindHost(host_id=2, remoteuser_id=2)
160
161 g1 = HostGroup(name="bj_group")
162 g1.bind_hosts = [b1]
163 g2 = HostGroup(name="sh_group")
164 g2.bind_hosts = [b2,b3]
165
166 uh1 = UserProfile(username="lyy1", password="123")
167 uh1.bind_hosts = [b1,b2,b3]
168 uh1.host_groups = [g1,g2]
169
170 SessionCls = sessionmaker(bind=engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
171 session = SessionCls()
172
173 session.add_all([h1,h2,u1,u2,b1,b2,b3,g1,g2,uh1])
174 session.commit()