背景交代
python3 + django2.1
Django project:accessgateway
gateone的安装
Gateone是一个web界面的交互工具,很多堡垒机都会使用到它,它的生命力很长久也很经得住考验(不过最近github上已经不再对它有更新了)。安装方法如下:
1
2
3
4
5pip 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
,就会看到效果:
默认的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
:
然后修改60docker.conf
,把"auth": "none"
,改成"auth": "api"
,保存之后,此时如果重启容器,发现web界面已经不能访问了,会出现unauthenticated
的提示,如图:
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
34import 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
2path(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
页面看一下效果:
可见我们已经成功的把gateone嵌入到django里了,而且自动就链接”id=1”这台服务器。大功告成,剩下的就是修改一下细节,给所有服务器一个按钮,只要点击这个按钮就会打开对应的远程链接界面。
事后补充
刚才那个views.py
里“gateone认证”那两个def函数上面不要加上@login_required
,会出现AttributeError: 'bytes' object has no attribute 'user'
错误:
这是因为@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