Golang Go语言中写了一个ssh客户端,欢迎体验

发布于 1周前 作者 phonegap100 来自 Go语言

需求来源

对于一个后端程序员来说,在工作中免不了要和繁杂的服务器打交道,ssh 是不可或缺的开发工具。但每次登录都需要输入密码的行为,对于认为一切皆可自动化的程序员来说,肯定是有点繁琐的(如果您是使用图形化界面的用户可忽略)。

所以我在前段时间考虑,我应该自己实现一个 ssh 客户端,它不需要拥有许多复杂的功能,只需要满足我以下这几个需求即可满足日常使用:

  • 和 ssh 保持差不多的使用习惯
  • 仅在第一次登录时询问我密码,后续使用无需再提供密码
  • 可以给服务器它任意的标签,这样我就可以自由地通过 IP 或者标签来登录

于是乎,近期我在业余时间就设计并编写了 ssx 这个轻量级的具有记忆的 ssh 客户端。它完美的实现了上面我所需要的功能,也已经被我愉快的应用到了日常的开发中。

项目源码地址:https://github.com/vimiix/ssx

使用方式

下面就简单介绍一下 ssx 的使用方式。

ssx 是通过 golang 开发的一个独立的二进制文件,安装方式就是从 release 页面下载对应平台的软件包,解压后把 ssx 二进制放到系统的任意目录下,这里我习惯放到 /usr/local/bin 目录下,如果你选择其他目录下,需要确保存放的目录添加到 $PATH 环境变量中,这样后续使用我们就不用再添加路径前缀,直接通过 ssx 命令就可以运行了。

登录服务器

使用 ssx 登录服务器的时候,基本和 ssh 使用习惯一致,下面是基本命令模式:

ssx [-s] [USER@]HOST[:PORT] [-k IDENTITY_FILE]

在这个命令中,USER 是可以省略的,如果省略则是系统当前用户名;PORT 是可以省略的,默认是 22 ,-k IDENTITY_FILE 代表如果是使用私钥登录,则通过 -k 来指定私钥的路径,也是可以省略的,默认是 ~/.ssh/id_rsa,当然了,前提是这个文件存在。所以最精简的登录命令就是:ssx <ip>

当首次登录,不存在可用私钥时,会通过交互方式来让用户输入密码,一旦登录成功,这个密码就会被 ssx 保存到本地的数据文件中 (默认为 ~/.ssx/db, 可通过环境变量 SSX_DB_PATH 进行自定义),下次登录时,仍然执行 ssx <ip> 即可自动登录。

注意,登录过的服务器,再次登录时,我嫌输入全部 IP 比较麻烦,所以 ssx 支持输入 IP 中的部分字符,自动搜索匹配进行登录。

为服务器打标签

当我们成功登录过一次服务器后,就可以通过 ssx list 命令来查看目前 ssx 存储的所有服务器列表。下面是一个列表示例:

# output example
# Entries (stored in ssx)
#  ID |       Address        |          Tags
#-----+----------------------+--------------------------
#  1  | [email protected]:22  | centos

ssx 会给每个服务器分配一个唯一的 ID ,我们在打标签时就需要通过 ID 来指定服务器条目。

当然,既然服务器有唯一 ID ,ssx 也支持通过 ID 来进行登录:ssx -i <ID>

打标签需要通过 ssx 的子命令 tag 来完成,下面是 tag 命令的模式:

ssx tag -i <ENTRY_ID> [-t TAG1 [-t TAG2 ...]] [-d TAG3 [-d TAG4 ...]]
  • -i 指定 list 命令输出的要操作的服务器对应的 ID 字段
  • -t 指定要添加的标签名,可以多次指定就可以同时添加多个标签
  • -d 指定要删除的标签名,同样也可以多次指定

当我们完成对服务器的打标签后,比如上面示例中的服务器,我增加了一个 centos 的标签,那么我此时就可以通过标签来进行登录了:

// -t 可省略
ssx [-t] centos

删除服务器记录

ssx 也支持删除服务器记录,命令如下:

ssx delete -i <ID>

一旦删除,ssx 不会保留该服务器的任何信息,所以下次登录时会等同于新的服务器来对待,ID 也会重新生成。

目前支持的环境变量

除了上面提到的 SSX_DB_PATH 可以指定存储数据的文件外,ssx 还支持:

  • SSX_CONNECT_TIMEOUT:SSH 连接超时时间,默认为 10s
  • SSX_IMPORT_SSH_CONFIG:是否引用用户 ssh 配置,默认为空

这里我解释一下 SSX_IMPORT_SSH_CONFIG 的作用,这个环境变量不设置时,ssx 默认是不会读取用户的 ~/.ssh/config 文件的,ssx 只使用自己存储文件进行检索。如果将这个环境变量设置为非空(任意字符串),ssx 就会在初始化的时候加载用户 ssh 配置文件中存在的服务器条目,但 ssx 仅读取用于检索和登录,并不会将这些条目持久化到 ssx 的存储文件中,所以,如果 ssx IP 登录时,这个 IP 是 ~/.ssh/config 文件中已经配置过登录验证方式的服务器,ssx 匹配到就直接登录了。但 ssx list 查看时,该服务器会被显示到 found in ssh config 的表格中,这个表格中的条目是不具有 ID 属性的,以下是一个示例:

export SSX_IMPORT_SSH_CONFIG=true
ssx list
# output example
# Entries (stored in ssx)
#  ID |       Address        |          Tags
#-----+----------------------+--------------------------
#  1  | [email protected]:22  | centos
#
# Entries (found in ssh config)
#               Address              |           Tags
# -----------------------------------+----------------------------
#   [email protected]:22            | github.com

操作演示

最后通过一个演示动画来感受一下这个小可爱的功能吧。

demo


Golang Go语言中写了一个ssh客户端,欢迎体验

更多关于Golang Go语言中写了一个ssh客户端,欢迎体验的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

38 回复

为什么不用 sshkey 呢,把集群 authorized_keys 刷一遍,所有机器登录都不用密码了

更多关于Golang Go语言中写了一个ssh客户端,欢迎体验的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


大部分机器不是属于我的,不方便直接放公钥上去

~/.ssh/config 够日常使用了吧。。而且可以复制到不同机器或者同事

嗯,但 ssh/config 里得配置明文,或者刷私钥,我平时用的测试机可能涉及几十台,所以简单写了个工具玩玩 :P
( ssx 的数据文件是二进制文件,也可以直接拷贝共享

我写的这个 https://github.com/trzsz/trzsz-ssh ,在 V2 发过很多次了,OP 没看到?
不过,自己写一次也很好,能学到不少东西。

提个小建议,放出来给大家用的,最好别用 ssh.InsecureIgnoreHostKey()

https://github.com/vimiix/ssx/blob/ee6c0166ed0c447aa398f4c0c11b7c9f69770e18/ssx/entry/entry.go#L65

go<br>func (e *Entry) GenSSHConfig() *ssh.ClientConfig {<br> cfg := &amp;ssh.ClientConfig{<br> User: e.User,<br> Auth: e.AuthMethods(),<br> HostKeyCallback: ssh.InsecureIgnoreHostKey(),<br> Timeout: getConnectTimeout(),<br> }<br> cfg.SetDefaults()<br> return cfg<br>}<br>

如果要传输密码信息那相信存储的时候也没法做非对称加密,那么用类似 base64 或者加盐的方式做编解码,其实安全性并不高?如果我判断有误,抱歉。

#7 是的,最好是用公私钥,然后私钥要设置复杂密码,开机时将私钥 ssh-add 到 ssh agent 中,这样用起来也很方便。更好的是,使用私钥要刷指纹的那种 ssh agent 。

👍,之前没注意到,谢谢你的建议,确实应该考虑

之前看到有人在 V2 上发类似的工具,但是很能理解楼主自己重新写一个,因为其实我自己也用 Python 写过一个类似的 : )
很多人的初衷就是为了实现一个自己顺手的工具,而每个人的诉求又不尽相同,所以还是写一个专门为自己打造的用起来更方便,而且可以随时根据自己的诉求添加新的功能。

看看大家写的工具,也挺有趣的,觉得不错的点子,也可以在自己的工具里改进一下。

#9 另外说一下,go 标准库中的 known_hosts 有两个小坑:
https://github.com/golang/go/issues/29286
https://github.com/golang/go/issues/53463

有个第三方库解决了,我也为它贡献过几行代码:
https://github.com/skeema/knownhosts

嗯,第一诉求是满足自己的需求

好的,我学习一下,再次感谢

牛蛙,哥你是参加了哪些教程写的,感觉挺牛的,适合初学者学习

没有参加,go 是我平时的主力开发语言

UP 演示动图是用什么录制的呀,还挺清晰的

“大部分机器不是属于我的,不方便直接放公钥上去”……这个不是放到用户自己家目录里就行了吗,就跟在家目录里放个吴梦梦潘甜甜小电影一样,还需要啥机器主人权限?

  1. 可以配置用 ControlMaster 来复用 ssh 连接,一次认证连上去,后续的会话都用同一个连接开新 shell

不是否定 OP 针对自己个性化需求的开发。只是想说,openssh 演化了这么多年,其实功能非常强大,在最基本的日常用法之外有很多花样。当然,纯程序员可能更喜欢通过写代码来实现自己需求,而我主要是运维的身份,更喜欢尽量发掘现有成熟工具的潜力,没有谁高谁低的臧否。

asciinema + svg-term

嗯嗯,赞同您的说法,ssh 肯定是成熟的工具,其肯定更适用于运维和生产环境。我写这个小工具主要目的是一个是解决我日常开发的一些显而易见的问题(也可能可以通过各种 ssh 的配置方式解决,但我比较懒,不想手动去配置,希望用朴素的方式连接后工具就可以自动帮我记下来,这个从安全的角度来说,不是个好的实践方案),另一方面也是想业余时间写点产品化的东西,这样有助于我建立产品思维。在生产上,我肯定是优先考虑用成熟的产品,但在个人工作流自动化方面,更愿意折腾自己写点东西的。:)

https://github.com/T-TRz879/scpw 。这是我之前写过一个 scp 的客户端,个人工作需要经常传包,每次 server 和包都比较固定,懒得敲那么多。OP 的 ssx 很不错

不敢苟同以上部分同学的观点,难道有了 A 工具就不能再写个 B 工具吗?
我认为百家争鸣是最好也是最健康的状态,楼主加油,支持一个

#25 有人反对楼主自己写吗?

看来是误会,我收回前面的话

貌似在 windows 终端登录后,不支持上下翻动历史命令,终端的高亮颜色显示也有变化。

过奖,后面有规划在 ssx 里加上 scp 的能力,在设计中

#25 感谢支持

#29 我这边测试了下,windows 上颜色正常,上下左右键确实失效了。我下周排查下看能否解决,感谢提醒

#29 windows 中方向键失效的问题已在 v0.0.4 版本修复

不错诶,安卓 APP 上也可以直接跑,但是搞不懂怎样才可以附加命令给连接的主机呢?
类似 ssh user@ip cmd 好像不行…

#34 直接执行一条命令然后就返回,这个意思吗?如果是的话,这个后面版本会增加

对的,就是执行单条命令返回,后续会有这个功能的话那就太好了(◦˙▽˙◦)

执行单条命令的功能已经在 v0.0.6 版本中支持
https://github.com/vimiix/ssx/releases/tag/v0.0.6

很高兴看到你使用Go语言开发了一个SSH客户端,这是一个非常实用且有趣的项目。以下是一些专业的反馈和建议:

  1. 安全性:SSH协议本身已经相对安全,但确保你的客户端正确处理密钥管理、密码验证以及防止中间人攻击等安全特性至关重要。建议采用公钥认证方式,并避免在代码中硬编码密码或私钥。

  2. 错误处理:在编写网络应用时,错误处理是一个非常重要的环节。确保你的SSH客户端能够优雅地处理各种网络错误和认证失败的情况,并向用户提供清晰的错误信息。

  3. 并发支持:Go语言以其出色的并发处理能力而闻名。如果你的SSH客户端需要处理多个并发连接或操作,考虑使用goroutines和channels来优化性能。

  4. 代码质量:确保你的代码遵循Go语言的最佳实践,包括清晰的命名、合理的代码结构以及适当的注释。这将有助于其他开发者(包括未来的你自己)更好地理解和维护代码。

  5. 文档和测试:提供详细的文档,说明如何使用你的SSH客户端,以及它支持的功能和限制。同时,编写单元测试来验证你的代码在各种情况下的行为,这将有助于提高代码的可靠性和稳定性。

最后,恭喜你完成了一个SSH客户端的开发!如果你愿意分享项目的链接或代码仓库,我将非常乐意进一步查看并给出更具体的建议。期待你的作品能够为用户带来便利和价值!

回到顶部