为了便于管理数据库,乐得RDS为高权限用户提供了基于网页的终端(web terminal),可以直接登录数据库所在的服务器来执行操作系统命令。本篇文章就来给列位看官说道一下我们是怎么实现这个功能的。
在最初开发阶段,我们曾使用wetty来实现web terminal功能。wetty是使用Node.js和websockets开发的一个开源网页终端,调用了纯JavaScript写的chromeOS的终端模拟器(hterm),在性能上比较有保证。但是在使用过程中,我们发现wetty存在以下几个问题:
1
不支持同时SSH到多台服务器。从安全角度考虑,我们只允许在一台中心服务器A上对外提供wetty的服务(A上运行的wetty本身可以通过SSH连接到其他的数据库服务器)。此时如果有用户想要登录数据库服务器B和数据库服务器C,就需要在A的不同端口上启动两个wetty服务端,分别连接到B和C;并且此时需要以A上的两个wetty服务端口来区分B、C的连接,依靠前置的nginx根据url参数来做动态转发,实现起来比较复杂。
2
不自带安全认证。假设在中心服务器A上开启服务端口1234之后,在任何拥有A:1234访问权限的机器上使用浏览器就能进入wetty提供的终端,因为wetty本身不提供任何访问控制。并且由于上一条所说,A可能会同时开放多个服务端口,更是增加了风险。
3
没有连接检测机制。一旦启动wetty服务端,无论有没有用户访问,都会一直保持到目标机器的SSH连接,这对资源也是一种浪费。虽然可以在应用层实现用户连接检测的机制,但是感觉还是不靠谱。
由于以上几点原因,尤其是对安全问题的担忧,推动我们继续去寻找可以替代的产品。在搜集了更多的资料后,我们发现了一个比较理想的解决方案——Gate One。
Gate One是一个开源的、基于web的终端模拟器,拥有强大的插件系统,功能上比较全面。除了解决了上述的三个问题之外,它还额外提供了一些比较实用的功能,例如显示图片和pdf、图形化的提示信息、记录和回放用户操作、ssh key管理等。官方文档的支持也比较好。
废话不多说,撸起袖子干。
安装
1
依赖:python 2.7+ or 3.2+,tornado 2.2+
源码:git clone https://github.com/liftoff/GateOne.git
安装:cd GateOne; python setup.py install
验证:whereis gateone
配置
2
默认的配置文件放在/etc/gateone/conf.d下,涉及修改的有以下几个文件:
10server.conf
Gate One的主设置文件,在官方文档http://liftoff.github.io/GateOne/About/configuration.html列出了具体的参数的用途。RDS由于前端有用nginx做https服务,这里把”disable_ssl”改为ture,在“origins”里添加RDS应用服务器的ip以允许来自应用的连接,设置“port”为”8001”。
20authentication.conf
Gate One支持包括的认证方式包括api, cas, google, ssl, pam等,把GateOne嵌入到别的应用中时需要使用api的方式。在RDS中就使用了这种方式在视图层做认证,实现方式会在后面讲到。此处把“auth”改为”api”,即只有经过api认证后才可以进入Gate One的界面。
30api_keys.conf
使用api认证需要配置key:secret密钥对,如果还没有这个文件,可以使用gateone --new_api_key命令来自动生成,里面会包含随机密钥对。
至此Gate One的配置就差不多改完,可以使用service gateone start或者gateone命令启动gateone服务器了。
嵌入RDS
3
首先需要在view里生成api的token:
这里注意upn是RDS根据想要连接的服务器按照规则生成的用户名,当一个新的upn连接到Gate One之后会在/var/lib/gateone/users下建立以upn命名的目录,里面保存了此用户的session、日志文件以及最重要的.ssh目录;如果已经存在这个upn目录,就会使用已有的这些信息。为了方便标识,RDS中upn的命名方式是user@ip,这样在.ssh目录下先成ssh秘钥对并把公钥加入到想要连接的数据库服务器的账号的authorizied_keys之后,一旦RDS用户在网页进入Gate One执行SSH,就会使用此upn下的密钥进行连接。
前台加载Gate One的js代码:
前台从view接收到的变量除了valid_json_auth_object这个令牌之外,还有ssh_url和location。ssh_url是用来设置进入Gate One之后自动连接的ssh连接串,例如“ssh://mysql@10.11.12.13:22”,这样就可以避免用户手动输入;location这个参数就比较关键,它用来保证不同的RDS用户即使同时登录同一台目标服务器也不至于出现“串台”的异常:因为这些RDS用户的令牌里会有相同的upn,不设置location就会使得多个用户都访问此upn用户的location=“default”终端,出现看到一样的终端的情况。另外可以看到此处并没有出现Gate One服务器的ip和8001服务端口,这是因为已经在RDS的前置Nginx里配置了把/gateone的访问请求路由到真正的地址的相关参数,此处不再赘述。最后,有一部分代码是放在GateOne.Base.superSandbox中执行的,大家查看官方文档就可以找到这么做的原因。
* 成功访问后执行top命令 *
可能遇到的情况
4
api token验证失败
说明到Gate One服务的网络是通的,需要去检查下后台返回的令牌是否有错误。
ssh登录失败
出现ssh配置不当导致的无法连接,一般是权限问题。
参考资料:
官方文档:http://liftoff.github.io/GateOne/
应用嵌入Gate One:https://www.jianshu.com/p/b8123a8178de
Ngixn配置:https://laucyun.com/135bc31db22920069ec1ac3e2fbe038a.html
领取专属 10元无门槛券
私享最新 技术干货