将Gateone添加到django,实现WEB的ssh链接

背景交代

python3 + django2.1
Django project:accessgateway

gateone的安装

Gateone是一个web界面的交互工具,很多堡垒机都会使用到它,它的生命力很长久也很经得住考验(不过最近github上已经不再对它有更新了)。安装方法如下:

1
2
3
4
5
pip install --upgrade setuptools
pip install tornado==4.3
pip install Pillow
docker pull liftoff/gateone #拉取镜像,个人推荐把原有的镜像修改一下,添加vim等工具
docker run -t -p 8008:8000 -h GATEONE --name gateone liftoff/gateone gateone #创建容器

这样我们就创建了一个叫gateone的容器,宿主机端口是8008,此时通过浏览器访问https://IP:8008,就会看到效果:
akb48

默认的gateone是https访问,如果要改成http访问。那么就要修改容器里的/etc/gateone/conf.d文件夹下的10server.conf,修改如下两处:

1
2
"disable_ssl": true,	#改成http方式
"origins": ["localhost:8000", "127.0.0.1:8000", "594f279c70b0:8000", "django的外网IP:django端口"], #添加django的地址和端口

然后重启容器,改用http://IP:8008方式去访问,发现已经改成HTTP协议了。

gateone的配置

现在这个gateone容器需要已经指定准许django来访问,但是还要生成一个api,让django通过api来访问。在容器里执行gateone --new_api_key,发现在/etc/gateone/conf.d文件夹下多了一个30api_keys.conf
akb48

然后修改60docker.conf,把"auth": "none",改成"auth": "api",保存之后,此时如果重启容器,发现web界面已经不能访问了,会出现unauthenticated的提示,如图:
akb48

gateone集成到django

gateone部分暂时告于段落,现在配置Django,首先是views.py,注意!python2与python3有些地方不同,我这里是python3版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import time,hmac,hashlib,json

#web交互界面gateone
def gateone(request):
id = 1 #这里暂时写死只要id为1的服务器
svr = server.objects.get(id = id)
ip = svr.outIP
port = svr.port
username = svr.username #写死端口和用户名
return render(request,'aggateone.html',locals()) #返回aggateone.html页面

#gateone认证
def create_signature(secret,*parts):
hash = hmac.new(secret, digestmod=hashlib.sha1)
for part in parts:
hash.update(str(part).encode("utf-8"))
return hash.hexdigest()

def get_auth_obj(request):
# 安装gateone的服务器以及端口.
gateone_server = 'http://121.41.37.251:8008' #本地gateone的访问地址,注意http格式
# 生成的api_key 和secret
api_key = 'OGQxZGM5OGM1MGNlNDZkNmEwMTNmM2IyY2NlMGZlNjA3Z' #这里是30api_keys.conf文件里的key
secret = b'MDIzOWQyN2Y2MmU0NDdhMWIwN2Q3MjIzODU1MGFjYWVkY' #这里是30api_keys.conf文件里的secret
authobj = {
'api_key':api_key,
'upn':'gateone',
'timestamp':str(int(time.time() * 1000)),
'signature_method':'HMAC-SHA1',
'api_version':'1.2'
}
authobj['signature'] = create_signature(secret,authobj['api_key'],authobj['upn'],authobj['timestamp'])
auth_info_and_server = {'url':gateone_server,'auth':authobj}
return JsonResponse(auth_info_and_server)

然后新增两条路由到urls.py

1
2
path(r'gateone.html', views.gateone),
path(r'get_auth_obj.html',views.get_auth_obj,name="get_auth_obj"),

最后就是编写前端页面aggateone.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{% extends 'agbase.html' %}
{% load staticfiles %}
{% block title %}Gateone远程连接{% endblock %}

{% block css %}
<script src = "/static/jquery-3.3.1.min.js"></script>
<script src = "/static/gateone/gateone.js"></script> <!-- 这里需要手动复制一下gateone.js文件到django的静态文件夹里 -->
{% endblock %}

{% block content %}
<script>
$(function () {
<!--添加参数-->
var ip = '{{ ip }}';
var user = '{{ username }}';
var port = '{{ port }}';
var ssh_url = 'ssh://'+user+'@'+ip+':'+port;
//请求认证信息
<!--发起认证请求-->
$.ajax({
url:'{% url 'get_auth_obj' %}',
type:'GET',
dataType:'json',
success:function (data) {
var auth_message = data.auth;
var auth_url = data.url;
GateOne.init({
auth:auth_message,
url:auth_url,
theme:'solarized',
goDiv:'#gateone',
disableTermTransitions:'true',
autoConnectURL:ssh_url
});
}
});
<!--状态记录-->
GateOne.Base.superSandbox("GateOne.SomePlugin", ["GateOne", "GateOne.Net", "GateOne.Terminal.Input", "GateOne.Terminal"], function(window, undefined) {
var location = ip;
GateOne.prefs.autoConnectURL=ssh_url;
GateOne.prefs.fontSize="100%";
GateOne.prefs.scrollback = 10000; // scrollback buffer up to 10,000 lines
GateOne.Terminal.loadFont("Source Code Pro", "150%");
GateOne.Net.setLocation(location);
<!--记录登录状态-->
});
})
</script>
<div id = "gateone_container" style = "position:relative; width: 110em; height: 55em;">
<div id = "gateone">
</div>
</div>
{% endblock %}

重启django进程,浏览器打开gateone.html页面看一下效果:
akb48

可见我们已经成功的把gateone嵌入到django里了,而且自动就链接”id=1”这台服务器。大功告成,剩下的就是修改一下细节,给所有服务器一个按钮,只要点击这个按钮就会打开对应的远程链接界面。

事后补充

刚才那个views.py里“gateone认证”那两个def函数上面不要加上@login_required,会出现AttributeError: 'bytes' object has no attribute 'user'错误:
akb48

这是因为@login_required这个装饰器首先回去判断user是否是登录状态,会从request里获取User,但是在下面的函数里并没有传递这个User,所以就会报错。如果说非要加上@login_required这个装饰器,那么就要把User传入当做第一个函数。

详情可见:https://stackoverflow.com/questions/13423022/django-str-object-has-no-attribute-user

参考资料

http://blog.codecp.org/2018/03/23/Django%E5%9F%BA%E7%A1%80Gateone%E5%AE%9E%E7%8E%B0Web%E7%BB%88%E7%AB%AFSSH%E5%8A%9F%E8%83%BD/
https://github.com/liftoff/GateOne/issues/257
https://www.jianshu.com/p/b8123a8178de

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------