背景
看到这个标题,你可能很奇怪,已经登录到Linux上了,为什么还要 ssh localhost
,这个问题要从一个需求说起。
需求是这样的:
某一个springboot开发的带有界面的管理后台,有一个功能需求叫 “SSH控制台”,要求点击这个功能的时候,呈现一个黑色的和我们日常使用其他 shell 工具看到的界面一样的界面,并且要自动连接到这个 springboot 所在的 Linux 控制台,要点是自动进入,不需要输入任何host和账号密码。
效果如下截图:
浏览器前端这个效果,是通过 xterm.js 实现的。
-
如果springboot运行在普通的Linux服务器上,那么这个控制台就是自动连接到这个服务器上,对应的用户就是启动 springboot 的 Linux 用户。
-
如果这个springboot运行在docker容器里,那么这个控制台就是自动连接到这个docker容器的控制台上,对应的用户也是docker中默认启动这个服务的用户(docker一般默认不带ssh,你如果有这个需求,你需要在制作docker镜像的时候内置ssh服务)。
对于实现这个场景的功能,我画了一个草图(示意一下,大家将就看),如下:
对这个图解释一下:
1、浏览器和springboot服务建立websocket连接,用来实时传输数据。
2、springboot使用ssh localhost
的方式与所在Linux系统的ssh建立连接(使用JSch库)。
3、websocket 和 JSch 合作完成这个工作。
综上所述,我们就回到主题了。就是本文为什么要实现 ssh localhost 免密连接的原因了。
实现
如上,背景内容有点多,下面轮到实现了,总结了一下,实现本机 ssh 免密连接比较简单,就是生成本地密钥即可,细节不多说,看下面操作:
首先,springboot 在收到 websocket 建立连接的时候需要检测本机是否已经存在ssh免密登录的key
- 先判断文件 ~/.ssh/id_dsa 是否存在
- 然后判断文件 ~/.ssh/authorized_keys 是否存在
- 再使用命令 whoami (查看当前用户) 和 文件 /etc/hostname 的内容(当前主机hostname)分别获取当前用户和当前主机hostname
- 判断~/.ssh/authorized_keys中是否存在
用户@hostname
结尾的记录
然后,根据以上每个步骤的判断情况,对应执行如下命令(Java 执行 shell 命令不难吧?这个自己找个库解决)
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
或者
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
dsa 和 rsa 的方式为加密实现方式不同,均可以实现本文需求
最后,就可以执行命令 ssh localhost
验证结果了(对应在 springboot 中使用 JSch 免密连接 localhost 即可)。
因为登录可能会出现提示你输入yes/no 的确认提示,所以在使用 JSch 的时候,记得连接时
设置属性 StrictHostKeyChecking 为 no
后者一劳永逸直接修改 ssh 配置文件/etc/ssh/ssh_config
将其中的# StrictHostKeyChecking ask
改成StrictHostKeyChecking no
总结:本文的核心逻辑就是将生成的公钥放到 ssh 目标机器的 authorized_keys
文件中,因为我们是需要连接自己,所以就是将公钥放到自己系统的 authorized_keys
文件里,从而实现了 ssh localhost 的逻辑。
(END)