运维开发之堡垒机(Fortress Machine for Operation and Development)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

开发运维之堡垒机

技能目标:

- 了解堡垒机特点及架构
- 理解堡垒机应用场景
- 掌握使用 Python 编写堡垒机的方法

8.1 案例分析

8.1.1 案例概述

网络安全是互联网企业重要关注的一个问题,随着信息化步伐加快而变得越来越重要,
对网络安全的认知和防范也要重视起来。创鑫公司的 IT 系统出现问题,当地的 IT 运维人员
无法解决时,就会向总部发起求助。而此时,总部的技术工程师根本无法获悉最原始的问题,
因为原来的问题在经过分部的运维工程师的操作后,已经面目全非,还可能引入了新的问题,
整个过程没有记录,没有管控,找不到解决问题的线索。所以总部工程师迫切希望知道,从
一开始问题的表象,到分支机构的运维人员的运维操作,都是什么情况。数据实际是存储在
服务器上的,因此,保障服务器安全性是最后一道关口。本章节将从服务器入口增加一道防
御手段 -- 堡垒机。

8.1.2 案例前置知识点

1.什么是堡垒机

运维堡垒机的理念起源于跳板机。在早期,有一定运维规模的公司为了对运维人员的远
程登录进行集中管理,会单独在一台服务器上部署跳板机。运维人员在维护服务器时,先登
录到这台跳板机上,然后再从这台服务器再登录到目标服务器上进行维护。

2.堡垒机特点

任何操作都有记录,有依据可追溯;
根据系统账户区分工作角色,人员流动不影响;
约束执行命令,避免人为失误。

3. 堡垒机主要作用

(1)权限管理

当公司服务器越来越多后,操作这些服务器的人肯定就不只是一个运维人员,同时也可
能包括多个开发人员。目前,不少公司现状是多个运维共用一个 root 账户和密码,这就放
大了运维权限和泄露风险。如果某个运维心情不好随时能把业务停止,甚至删除数据,很难
追查谁干的。
(2)审计管理
审计是把用户的所有操作记录下来,以备日后追查问题提供依据。
针对上面问题,使用堡垒机很简单就可以实现:
即使多个运维人员共享一个 root 账户,但依然能分辨谁再哪台服务器上操作了哪些命
令,因为每个人登录堡垒机的账户是独有的。
对登录的堡垒机账户以基准做记录。
4.堡垒机架构
如图 8.1 所示,堡垒机在服务器前面增加一层。
8.1 堡垒机架构
堡垒机的主要作用是权限控制和用户行为审计,例如一个住宅小区,小区里的房屋就是
不同的业务服务器,外部人员要想访问业主,就必须经过小区门口安保人员的授权,他们就
像堡垒机一样;而进入小区的人的所有行为和足迹都会被摄像头监控和记录下来。一旦发生
犯罪事件,小区安保人员就可以通过这些监控记录追踪到人。
要想使用堡垒机也要满足以下条件:
回收所有人员已有的访问权限,做到除了堡垒机管理员,没有人知道业务服务器的登录
权限。
网络上限制所有人员只能通过堡垒机才能访问业务服务器。
服务器创建共享账户。

8.1.3 案例环境

1.本案例环境

本案例环境如表 8-1 所示。
8-1 创建并管理堡垒机案例环境
主机操作系统主机名/IP 地址主要软件及版本
堡垒机CentOS 7.3BLJ /192.168.0.10MySQLPython3.6
服务器CentOS 7.3Server1 /192.168.0.11/
服务器CentOS 7.3Server1 /192.168.0.12/

具体的拓扑如图 8.2 所示。

图 8.2 案例拓扑

2.案例需求

1 )所有的用户操作日志保留在 MySQL 数据库中。
2 )用户人员在维护过程中,首先连接到堡垒机,然后选择要访问的服务器(只能查
看自己权限内的服务器),不需要再输入目标机器的访问密码。
3 )每个用户对不同的服务器有不同的访问权限,例如:对 192.168.0.10 有普通用户
权限,对 192.168.0.11 sudo 权限,对 192.168.0.12 没有任何权限。
4 )管理员登录堡垒机,可查看其它账户操作记录。
5 )确保堡垒机管理员除外,其他用户只提供堡垒机登录跳转功能。

3.实现思路

1 )通过 paramiko 模块远程登录服务器交互执行命令,通过堡垒机权限检查。
2 )通过 sqlalchemy 模块操作 MySQL 数据库存放操作记录。
3 )利用 Python 数据类型处理数据。

8.2 案例实施

8.2.1 设计表结构

本案例需要在 MySQL 实例中创建 test 数据库, test 数据库中有创建 user 表(用户信
息表)、 host 表(主机信息表)和 cmd_log 表(工作日志表)。三张表没有主外键关系, user
表主要功能是保存授权用户对应的授权主机, host 表用来保存被管理主机 ip 对应的端口号,
cmd_log 表是用于保存授权用户在操作授权主机时所产生的记录比如操作命令、时间等。
8-2 user 表的结构,
序号字段名称字段说明类型长度备注
1id编号int自动编号,主键
2username用户名varchar50非空
3hosts授权的主机text
8-3 host
序号字段名称字段说明类型长度备注
1id编号自动编号,主键
2ipIP 地址varchar50非空

表 8-4 cmd_log

序号字段名称字段说明类型长度备注
1id编号int自动编号,主键
2login_user登录用户名varchar16feikong
3share_user目标主机共享账户varchar16非空
4
server_ip
目标主机 IP 地址
varchar50非空
5
shell_command
用户操作的 Shell 命令
varchar255非空
6
datetime
操作命令日期时间
varchar30非空

8.2.2 功能模块规划

实现本案例需求,需要规划 Python 目录结构:
├── bin
│ ├── __init__.py
│ ├── manager_menu.py
│ └── user_menu.py
├── config
│ ├── config.py
│ ├── __init__.py
└── modules
├── db_conn.py
├── __init__.py
├── interactive.py
├── manager_handle.py
├── ssh_login.py
└── table_init.py
在每个目录下有一个空的 __init__.py 文件,说明这个目录是一个包,可导入。 __init__.py
文件定义了包的属性和方法。其实它可以什么也不定义,它可以只是一个空文件,但是必须
存在。如果 __init__.py 不存在,这个目录就仅仅是一个目录,而不是一个包,它就不能被
导入或者包含其它的模块和嵌套包。
8-5 Python 工程目录结构中所包含的模块
目录
模块名
描述
描述
bin
manager_menu
管理菜单
bin
user_menu
用户菜单
config
confg
数据库配置文件
modules
table_init.py
数据库表创建与映射
modules
db_conn
数据库连接
modules
interactive
SSH 交互式
modules
ssh_login
SSH 登录
modules
manager_handle
管理菜单处理程序

8.2.3 功能实现

通常,开发项目先从依赖的关系写,例如 : 用到数据库,需要先将数据库相关逻辑弄清
楚,方便写功能时调用调试。
本案例编写模块顺序: config -> modules -> bin

1. 数据库配置模块

[root@BLJ baoleiji]# vim config/config.py
database='test'
ip='127.0.0.1'
port=3306
user='root'
password='123456'
engine_param = 'mysql+pymysql://%s:%s@%s:%d/%s?charset=utf8' %(user, password, ip, port,
database)

2. 数据库连接模块

[root@BLJ baoleiji]# vim modules/db_conn.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from modules.table_init import *
from config.config import engine_param
engine=create_engine(engine_param)
# 创建会话
Session = sessionmaker(bind=engine)
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()

3. 创建表并映射模块

[root@BLJ baoleiji]# vim modules/table_init.py
#!/usr/local/bin/python3.6
import os,sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text
from config import config
# 创建对象的基类
Base = declarative_base()
# 定义 User 对象
class User(Base):
__tablename__ = 'user'
id = Column(Integer, autoincrement=True, primary_key=True)
username = Column(String(50))
hosts = Column(Text, default="{'sudo': [], 'no-sudo': []}")
class Host(Base):
__tablename__ = 'host'
id = Column(Integer, autoincrement=True, primary_key=True)
ip = Column(String(50))
port = Column(Integer, default=22)
class Cmd_log(Base):
__tablename__ = 'cmd_log'
id = Column(Integer, autoincrement=True, primary_key=True)
login_user = Column(String(16))
share_user = Column(String(16))
server_ip = Column(String(50))
shell_command = Column(String(255))
datetime = Column(String(30))
if __name__ == "__main__":
engine=create_engine(config.engine_param)
Base.metadata.create_all(engine) # 创建表结构

4. SSH 交互式处理和登录模块

[root@BLJ baoleiji]# vim modules/interactive.py
import os,sys
#BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#sys.path.append(BASE_DIR)
import socket
import termios
import tty
from datetime import datetime
from modules.table_init import *
from modules.db_conn import session
def interactive_shell(channel, login_user, share_user, server_ip):
import select
oldtty = termios.tcgetattr(sys.stdin)
try:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
channel.settimeout(0.0)
cmd = ''
tab_key = False
while True:
r, w, e = select.select([channel, sys.stdin], [], [])
if channel in r:
try:
x = channel.recv(1024).decode()
if tab_key:
if x not in ('\t','\r\n'):
cmd += x
tab_key = False
if len(x) == 0:
sys.stdout.write('\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 '\r' != x:
cmd +=x # 输入字符不包含回车,则命令还未输入完成,包含回车且输入字
符长度大于 0 ,则记录日志
if '\r' == x and len(cmd) > 0:
add_log = Cmd_log(login_user=login_user,
share_user=share_user,
server_ip=server_ip,
shell_command=cmd,
datetime=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
session.add(add_log)
session.commit()
cmd = ''
if '\t' == x:
tab_key = True
channel.send(x)
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
[root@BLJ baoleiji]# vim modules/ssh_login.py
import os,sys
#BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#sys.path.append(BASE_DIR)
import paramiko
from modules.interactive import interactive_shell
def ssh_login(login_user, share_user, server_ip, server_port, password):
# 建立 ssh 连接
ssh=paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(server_ip, server_port, share_user, password)
# 建立交互式 shell 连接
channel=ssh.invoke_shell()
# 建立交互式管道
interactive_shell(channel, login_user, share_user, server_ip)
# 关闭连接
channel.close()
ssh.close()
if __name__ == "__main__":
# 手动执行测试
login_user = "xiaoming"
share_user = "user2"
password = "123456"
server_ip = "192.168.0.11"
server_port = 22
ssh_login(login_user, share_user, server_ip, server_port, password)

5. 管理接口模块

[root@BLJ baoleiji]# vim bin/manager_menu.py
#!/usr/local/bin/python3.6
import os,sys,io
# 添加当前目录到 Python 模块搜索路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
# 改变标准输出的默认编码,解决中文编码错误 :UnicodeEncodeError
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')
from modules.manager_handle import *
choices = {
"1": " 添加用户名 ",
"2": " 授权用户名访问主机 ",
"3": " 添加主机 ",
"4": " 删除主机 ",
"5": " 查看日志 ",
"6": " 退出 "
}
while True:
print(" 菜单 :")
for k, v in choices.items():
print(k + ". " + v)
choice = input(" 请输入编号 : ")
choice = str(choice).strip()
if choice in choices.keys():
if choice == "1":
add_user()
elif choice == "2":
authorized()
elif choice == "3":
add_host()
elif choice == "4":
del_host()
elif choice == "5":
view_log()
elif choice == "6":
quit()
else:
print(" 编号错误,请重新输入 !")
continue
[root@BLJ baoleiji]# vim modules/manager_handle.py
#!/usr/local/bin/python3.6
#import os,sys
#BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#sys.path.append(BASE_DIR)
import re
from modules.table_init import *
from modules.db_conn import session
def add_user():
username = input(" 请输入要添加的用户名 : ").strip()
user = User(username=username)
session.add(user)
session.commit()
print(" 添加成功 .")
def authorized():
n = 1
while True:
username = input(" 请输入要授权的用户名 : ").strip()
user = session.query(User).filter(User.username==username).first()
if user:
break
else:
if n == 3:
print(" 错误次数达到 3 , 退出 !")
return
print(" 用户名不存在 , 请重新输入 !")
n += 1
continue
n = 1
while True:
ip = input(" 请输入要授权的主机 IP 地址 : ").strip()
host = session.query(Host).filter(Host.ip==ip).first()
if host:
break
else:
if n == 3:
print(" 错误次数达到 3 , 退出 !")
return
print(" 主机 IP 地址不存在 , 请重新输入 !")
n += 1
continue
n = 1
while True:
sudo = input(" 需要 sudo root 权限 ?(Y/N): ").strip()
if sudo in ['y','Y', 'n', 'N']:
break
else:
if n == 3:
print(" 错误次数达到 3 , 退出 !")
return
print(" 输入错误 , 请重新输入 !")
n += 1
continue
hosts = eval(user.hosts)
if sudo in ['y', 'y']:
hosts['sudo'].append(ip)
elif sudo in ['n', 'N']:
hosts['no-sudo'].append(ip)
user = session.query(User).filter(User.username==username).update({"hosts": str(hosts)})
session.commit()
print(" 添加成功 .")
def add_host():
n = 1
while True:
ip = input(" 请输入要添加的 IP: ").strip()
ip_match = re.match('^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$', ip)
if ip_match:
host = Host(ip=ip)
session.add(host)
session.commit()
print(" 添加成功 .")
break
else:
if n == 3:
print(" 错误次数达到 3 , 退出 !")
break
print("IP 地址错误 , 请重新输入 !")
n +=1
continue
def del_host():
n = 1
while True:
ip = input(" 请输入要删除的 IP 地址 : ").strip()
host = session.query(Host).filter(Host.ip==ip).first()
if host:
session.delete(host)
session.commit()
print(" 删除成功 .")
break
else:
if n == 3:
print(" 错误次数达到 3 , 退出 !")
break
print("IP 地址不存在 , 请重新输入 !")
n +=1
continue
def view_log():
logs = session.query(Cmd_log).all()
if logs:
for i in logs:
print("login_user: %s | share_user: %s | server_ip: %s | shell_command: %s |
datetime: %s"
%(i.login_user, i.share_user, i.server_ip, i.shell_command, i.datetime))
else:
print(" 没有日志记录 .")
def quit():
sys.exit()

6. 用户接口模块

[root@BLJ baoleiji]# vim bin/user_menu.py
#!/usr/local/bin/python3.6
import os,sys,io
# 添加当前目录到 Python 模块搜索路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
# 改变标准输出的默认编码,解决中文编码错误 :UnicodeEncodeError
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')
from modules.table_init import *
from modules.db_conn import session
from modules.ssh_login import ssh_login
import getpass
login_user = getpass.getuser()
server_port = 22
share_user = {'sudo': 'admin', 'no-sudo': 'user', 'password': '123456'}
user_host = session.query(User).filter(User.username==login_user).first()
# 如果 root 登陆说明是管理员,则退出不执行
if login_user == "root":
sys.exit()
if not user_host:
print(" 数据库未记录该登录用户 , 请联系管理员 !")
sys.exit()
sudo = set(eval(user_host.hosts)['sudo'])
no_sudo = set(eval(user_host.hosts)['no-sudo'])
def display_menu():
print(" 主机列表 :")
if not sudo and not no_sudo:
print(" 没有授权的主机 !")
for i in sudo:
print(i + " sudo")
for i in no_sudo:
print(i)
n = 1
while True:
display_menu()
server_ip = input(str(" 请输入要登录的主机 IP 地址 : "))
if server_ip in sudo:
ssh_login(login_user,share_user['sudo'],server_ip,server_port,share_user['password'])
elif server_ip in no_sudo:
ssh_login(login_user,share_user['no-sudo'],server_ip,server_port,share_user['password'])
else:
if n == 3:
print(" 错误次数达到 3 , 退出 !")
os.system("exit")
print("IP 地址错误,请重新输入 !")
n +=1
Continue

8.2.4 部署

部署之前需要先将程序放到 /opt 目录下。

1. 安装模块

[root@BLJ baoleiji]# pip3 install paramiko pymysql sqlalchemy

2. 配置数据库信息

[root@BLJ baoleiji]# vim config/config.py
database='test'
ip='127.0.0.1'
port=3306
user='root'
password='123456'
engine_param = 'mysql+pymysql://%s:%s@%s:%d/%s?charset=utf8' %(user, password,
ip, port, database)
把对应字段值修改为自己的数据库信息。

3. 初始化数据库表

下面是创建 test 数据库的命令:
[root@BLJ baoleiji]# mysql –uroot -p
mysql> create database test;
初始化数据库表:
[root@BLJ baoleiji]# python3 modules/table_init.py
执行完成后,进数据库核实下是否创建如下表:
[root@BLJ baoleiji]# mysql –uroot -p
mysql> use test;
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| cmd_log
|
| host
|
| user
|
+----------------+
3 rows in set (0.00 sec)

4. 被管理主机创建登录账号

Server1 Server2 主机中分别创建 admin user 账号,该账号用于跳板机 SSH
到被管理主机登录时的账号。下面以 Server1 为例:
[root@server1 ~]# useradd admin
[root@server1 ~]# passwd admin
[root@server1 ~]# useradd user
[root@server1 ~]# passwd user
密码均设置为 123456
这两个账号配置在程序里:
[root@BLJ baoleiji]# cat bin/user_menu.py
......
share_user = {'sudo': 'admin', no-sudo: 'user', 'password': '123456'}
......

5. 配置用户登录自动执行用户菜单程序

[root@BLJ baoleiji]# vim /etc/profile.d/baoleiji.sh
python3 /opt/baoleiji/bin/user_menu.py
注意:在 Linux 中,通过配置用户家目录下的 .bashrc 文件,实现自动执行脚本。

6. 将被管理主机 IP 添加到堡垒机数据库

[root@BLJ baoleiji]# python3 bin/manager_menu.py
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 3
请输入要添加的 IP: 192.168.0.11
添加成功 .
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 3
请输入要添加的 IP: 192.168.0.12
添加成功 .
8.2.5 测试
工作流程:
(1) 管理员为用户在服务器上创建系统账号与添加此账号到堡垒机数据库。
(2) 用户登录堡垒机,输入系统账户与密码,认证通过后显示可访问的主机列表。
(3) 用户输入主机 IP 自动登录。
(4) 用户操作记录到数据库。
下面是测试过程:
1. 管理员使用 root 账户登录到堡垒机为同事创建系统账号
[root@BLJ ~]# useradd zhangsan
[root@BLJ ~]# passwd zhangsan
[root@BLJ ~]# useradd lisi
[root@BLJ ~]# passwd lisi
2. 添加系统账号到堡垒机数据库
[root@BLJ baoleiji]# python3 bin/manager_menu.py
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 1
请输入要添加的用户名 : zhangsan
添加成功 .
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 1
请输入要添加的用户名 : lisi
添加成功 .
3. 授权用户名访问主机
[root@BLJ baoleiji]# python3 bin/manager_menu.py
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 2
请输入要授权的用户名 : zhangsan
请输入要授权的主机 IP 地址 : 192.168.0.11
需要 sudo root 权限 ?(Y/N): y
添加成功 .
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 2
请输入要授权的用户名 : zhangsan
请输入要授权的主机 IP 地址 : 192.168.0.12
需要 sudo root 权限 ?(Y/N): n
添加成功 .
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 2
请输入要授权的用户名 : lisi
请输入要授权的主机 IP 地址 : 192.168.0.12
需要 sudo root 权限 ?(Y/N): n
添加成功 .
说明:上述授权 zhangsan 用户对 192.168.0.11 有可 sudo root 权限,对 192.168.0.12
sudo 权限。授权 lisi 用户对 192.168.0.12 sudo 权限。
4. 用户登录测试
(1)使用 zhangsan 用户登录 Server1 服务器
[root@BLJ ~]# login as: zhangsan
Localhost login zhangsan
password:
主机列表:
192.168.0.11 sudo
192.168.0.12
请输入要登录的主机 IP 地址 : 192.168.0.11
[admin@localhost ~]$ ip addr
# 查看是否连接到了目标服务器
(2)使用 lisi 用户登录 Server2 服务器。
[root@BLJ ~]# login as: lisi
Localhost login lisi
password:
主机列表:
192.168.0.12
请输入要登录的主机 IP 地址 : 192.168.0.12
[user@localhost ~]$ ip addr
# 查看是否连接到了目标服务器
5. 管理员查看操作日志
[root@BLJ ~]# python3 /opt/baoleiji/bin/manager_menu.py
菜单 :
1. 添加用户名
2. 授权用户名访问主机
3. 添加主机
4. 删除主机
5. 查看日志
6. 退出
请输入编号 : 5
login_user: zhangsan | share_user: admin | server_ip: 192.168.0.11 | shell_command: echo
"zhangsan" | datetime: 2020-07-14 14:29:27
login_user: zhangsan | share_user: admin | server_ip: 192.168.0.11 | shell_command: ls | datetime:
2020-07-14 14:29:30
login_user: lisi | share_user: user | server_ip: 192.168.0.12 | shell_command: echo "lisi | datetime:
2020-07-14 14:29:52
login_user: lisi | share_user: user | server_ip: 192.168.0.12 | shell_command: ls | datetime: 2020-07-14 14:29:54
本项目实现了基本的堡垒机功能,相比生产环境的使用功能还有待完善,这里的目的是
让大家熟悉堡垒机项目开发流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux运维老纪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值