0%

使用Docker隔离easyconnect

前情提要

远程办公需要连接到公司的内网,公司提供了深信服的easyconnect来连接,但是easyconnect实在不好用,主要有以下几个方面

  1. 强制安装SSL根证书:官方的说法是为了更好的浏览体验,但总归会让人觉得会泄露隐私

  2. 组件自启动:easyconnect并不是只有连接的时候才会运行,在系统启动的时候就会运行几个后台服务,比如EasyMonitor和ECAgent,并且会提权到root运行,权限非常大,耗资源不说,谁知道会不会偷偷摸摸做什么事情呢?

  3. 修改系统路由表和DNS:其实以上两点对我个人影响都不大,反正现在的人上网冲浪,跟脱了裤子裸奔也没啥区别,但是还是有一点实在是影响体验。首先,easyconnect客户端运行并不稳定,有时客户端报错退出后,系统的路由表并没有还原回正常的路由表,导致无法上网。另一点在于,easyconnect连接的时候,会强制系统使用easyconnect的DNS服务器,强制使用也就算了,这玩意返回的IP地址又不干净,或者性能不好,毕竟我是CV(Ctrl C + Ctrl V)工程师,面相github和stackoverflow编程,easyconnect的DNS结果经常让我无法访问某G开头的网站,十分影响开发体验。

我自己总结了一下,其实理论上我使用easyconnect时,只需要访问特定网段的某些ip地址即可了,即公司配发的台式机的IP、堡垒机的IP以及一些内网服务的IP,我并不需要easyconnect提供的一条龙服务。

解决办法

解决办法就是使用Docker来封印easyconnect,仓库地址是:https://github.com/docker-easyconnect/docker-easyconnect,这个仓库是由一个学生维护的,因为挺多学校也是提供easyconnect来访问校内资源。

原理就是,通过Docker运行一个Linux最小系统,在Linux里安装easyconnect,这样需要连接公司内网的时候将docker启动即可,不使用的时候退出docker后台服务,也不会有额外的资源消耗。docker容器会暴露出socks5和http代理端口供宿主机使用,宿主机也可以通过配置静态路由的方式,实现透明代理。

运行的方法也很简单,目前有三种登录方式,分别为GUI登录、命令模式登录以及web登录。

GUI登录的方式即在Docker内运行一个GUI的easyconnect客户端,宿主机用vnc连接到docker的显示画面后,按正常的方式输入vpn地址,账号密码就可以了。
命令模式则是将用户名和密码写到配置中,启动的时候可以自动登录。
web登录的方式,则是通过打开浏览器访问vpn地址,点击登录后,docker容器内的ECAgent会捕获到登录请求,并执行登录操作。

具体的使用方式可以参考项目组提供的文档:https://github.com/docker-easyconnect/docker-easyconnect/blob/master/doc/usage.md

遇到的一些坑

easyconnect版本问题

公司目前使用的easyconnect版本应该是7.6.3,但只提供了Windows和macOS的客户端连接,Linux版本使用的是bin插件的方式,所以我不能使用GUI登录的方式,因此docker启动的时候要暴露54530端口,使用web登录的方式。

1
docker run --device /dev/net/tun --cap-add NET_ADMIN -ti -e PASSWORD=xxxx -v $HOME/.ecdata:/root -p 127.0.0.1:5901:5901 -p 127.0.0.1:2080:1080 -p 127.0.0.1:8888:8888 -p 127.0.0.1:54530:54530 -e IPTABLES_LEGACY=1 hagb/docker-easyconnect:7.6.3

easyconnect 架构问题

我目前使用的笔记本是M1 Pro的,基于arm64,一开始尝试使用web登录的时候,登录页面一直跳转到下载客户端的页面,相当于没有识别到54530端口开放,或者无法正常通信。 因为web登录的时候,需要先访问https://127.0.0.1:54530去信任easyconnect的自签证书,我发先用docker部署的easyconnect访问54530的时候提示的并不是证书无法信任,而是tls版本过低。

在网上查询一番后发现,深信服对arm架构似乎并不上心,针对arm版本提供的easyconnect版本比较低,因此无法被我现在使用的版本识别。那我就只能尝试使用amd64架构的了,好在苹果提供了Rosetta转换工具能够让M1 Pro运行amd64的二进制程序,进而让使用amd64架构的docker成为可能。docker desktop和orbstack都有提供对Rosetta的支持,使用的时候加入platform信息即可

1
docker run --platform linux/amd64 --device /dev/net/tun --cap-add NET_ADMIN -ti -e PASSWORD=xxxx -v $HOME/.ecdata:/root -p 127.0.0.1:5901:5901 -p 127.0.0.1:2080:1080 -p 127.0.0.1:8888:8888 -p 127.0.0.1:54530:54530 -e IPTABLES_LEGACY=1 hagb/docker-easyconnect:7.6.3

使用上面的命令运行amd64版本的docker容器后,成功通过web登录

IP Forward透明代理

docker-easyconnect 项目虽然提供了socks5和http代理的方式供你访问内网资源,但是这种方式使用起来并不方便,因为有些软件可能没有加入代理的支持,即便使用的软件支持配置代理,远程的时候就要使用跟在公司时不一样的配置才行,沉浸感不好,因此,我希望能在使用的过程中,没有代理的感觉,即透明代理。

项目本身也支持通过配置静态路由的方式,来直接访问内网资源,即在宿主机上配置要访问的内网资源的下一跳地址指向Docker容器的地址,但是我在mac上配置了很长时间都没搞定,一直ping不通。

又是一番网上冲浪,我了解到了,在mac和Windows平台的Docker,宿主机和容器的网络是隔离的,并不能直接访问,而orbstack虽然提供了访问容器ip功能,但是实际上内部运行的时候,还是会经过一个网关转发,即便我在宿主机上配置了路由规则,尝试访问内网资源时,由于中间途径的网关并没有配置相关的规则,最终的结果也只能”无路可走”,表现就是ping不通,没有回应。而orbstack并没有提供中间那个网关的静态路由配置功能。

在docker的官方文档也有介绍到这个限制问题

1
2
3
4
5
**There is no docker0 bridge on the host**
Because of the way networking is implemented in Docker Desktop, you cannot see a docker0 interface on the host. This interface is actually within the virtual machine.

**I cannot ping my containers**
Docker Desktop can't route traffic to Linux containers. However if you're a Windows user, you can ping the Windows containers.

因此,想要在mac平台上使用透明代理的方案,我就需要能够直接连到容器内才行。这时,我们需要借助mac-docker-connector工具,将docker容器和宿主机通过vpn的方式,配置成可以直接互相访问。项目地址:https://github.com/wenjunxiao/mac-docker-connector

graph TD;
0[宿主机]
1[mac-docker-connector容器]
2[easyconnect-docker容器]
0-->1;
1-->2;

虽然从流程上看,宿主机如果需要访问内网资源,数据还是会经过中间的一层网关,即mac-docker-connector,但是由于mac-docker-connector本身也是个容器,我可以直接进入mac-docker-connector容器内,配置静态路由规则,这样宿主机访问内网资源的请求,经过mac-docker-connector容器时,也能找到下一跳,就不会发现ping不通了