The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
vimiix

写了一个 ssh 客户端,欢迎体验

  •  
  •   vimiix ·
    vimiix · Dec 15, 2023 · 5407 views
    This topic created in 904 days ago, the information mentioned may be changed or developed.

    需求来源

    对于一个后端程序员来说,在工作中免不了要和繁杂的服务器打交道,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

    37 replies    2024-01-26 14:39:54 +08:00
    Inn0Vat10n
        1
    Inn0Vat10n  
       Dec 15, 2023   ❤️ 1
    为什么不用 sshkey 呢,把集群 authorized_keys 刷一遍,所有机器登录都不用密码了
    vimiix
        2
    vimiix  
    OP
       Dec 15, 2023
    @Inn0Vat10n 大部分机器不是属于我的,不方便直接放公钥上去
    march1993
        3
    march1993  
       Dec 15, 2023
    ~/.ssh/config 够日常使用了吧。。而且可以复制到不同机器或者同事
    vimiix
        4
    vimiix  
    OP
       Dec 15, 2023
    @march1993 嗯,但 ssh/config 里得配置明文,或者刷私钥,我平时用的测试机可能涉及几十台,所以简单写了个工具玩玩 :P
    ( ssx 的数据文件是二进制文件,也可以直接拷贝共享
    LonnyWong
        5
    LonnyWong  
       Dec 15, 2023
    我写的这个 https://github.com/trzsz/trzsz-ssh ,在 V2 发过很多次了,OP 没看到?
    不过,自己写一次也很好,能学到不少东西。
    LonnyWong
        6
    LonnyWong  
       Dec 15, 2023   ❤️ 2
    提个小建议,放出来给大家用的,最好别用 `ssh.InsecureIgnoreHostKey()`:

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

    ```go
    func (e *Entry) GenSSHConfig() *ssh.ClientConfig {
    cfg := &ssh.ClientConfig{
    User: e.User,
    Auth: e.AuthMethods(),
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    Timeout: getConnectTimeout(),
    }
    cfg.SetDefaults()
    return cfg
    }
    ```
    JounQin
        7
    JounQin  
       Dec 15, 2023 via iPhone
    如果要传输密码信息那相信存储的时候也没法做非对称加密,那么用类似 base64 或者加盐的方式做编解码,其实安全性并不高?如果我判断有误,抱歉。
    LonnyWong
        8
    LonnyWong  
       Dec 15, 2023
    @JounQin #7 是的,最好是用公私钥,然后私钥要设置复杂密码,开机时将私钥 ssh-add 到 ssh agent 中,这样用起来也很方便。更好的是,使用私钥要刷指纹的那种 ssh agent 。
    vimiix
        9
    vimiix  
    OP
       Dec 15, 2023
    @LonnyWong 👍,之前没注意到,谢谢你的建议,确实应该考虑
    98842674
        10
    98842674  
       Dec 15, 2023
    之前看到有人在 V2 上发类似的工具,但是很能理解楼主自己重新写一个,因为其实我自己也用 Python 写过一个类似的 : )
    很多人的初衷就是为了实现一个自己顺手的工具,而每个人的诉求又不尽相同,所以还是写一个专门为自己打造的用起来更方便,而且可以随时根据自己的诉求添加新的功能。

    看看大家写的工具,也挺有趣的,觉得不错的点子,也可以在自己的工具里改进一下。
    LonnyWong
        11
    LonnyWong  
       Dec 15, 2023 via iPhone   ❤️ 1
    @vimiix #9 另外说一下,go 标准库中的 known_hosts 有两个小坑:
    https://github.com/golang/go/issues/29286
    https://github.com/golang/go/issues/53463

    有个第三方库解决了,我也为它贡献过几行代码:
    https://github.com/skeema/knownhosts
    vimiix
        12
    vimiix  
    OP
       Dec 15, 2023
    @98842674 嗯,第一诉求是满足自己的需求
    vimiix
        13
    vimiix  
    OP
       Dec 15, 2023
    @LonnyWong 好的,我学习一下,再次感谢
    QKgf555H87Fp0cth
        14
    QKgf555H87Fp0cth  
       Dec 15, 2023
    都是大佬
    wkong
        15
    wkong  
       Dec 15, 2023
    666 支持
    hytirrb
        16
    hytirrb  
       Dec 15, 2023
    牛蛙,哥你是参加了哪些教程写的,感觉挺牛的,适合初学者学习
    vimiix
        17
    vimiix  
    OP
       Dec 15, 2023
    @hytirrb 没有参加,go 是我平时的主力开发语言
    ljlljl0
        18
    ljlljl0  
       Dec 15, 2023
    UP 演示动图是用什么录制的呀,还挺清晰的
    adoal
        19
    adoal  
       Dec 15, 2023
    @vimiix “大部分机器不是属于我的,不方便直接放公钥上去”……这个不是放到用户自己家目录里就行了吗,就跟在家目录里放个吴梦梦潘甜甜小电影一样,还需要啥机器主人权限?
    adoal
        20
    adoal  
       Dec 15, 2023
    2. 可以配置用 ControlMaster 来复用 ssh 连接,一次认证连上去,后续的会话都用同一个连接开新 shell
    adoal
        21
    adoal  
       Dec 15, 2023
    不是否定 OP 针对自己个性化需求的开发。只是想说,openssh 演化了这么多年,其实功能非常强大,在最基本的日常用法之外有很多花样。当然,纯程序员可能更喜欢通过写代码来实现自己需求,而我主要是运维的身份,更喜欢尽量发掘现有成熟工具的潜力,没有谁高谁低的臧否。
    vimiix
        22
    vimiix  
    OP
       Dec 15, 2023   ❤️ 1
    @ljlljl0 asciinema + svg-term
    vimiix
        23
    vimiix  
    OP
       Dec 15, 2023
    @adoal 嗯嗯,赞同您的说法,ssh 肯定是成熟的工具,其肯定更适用于运维和生产环境。我写这个小工具主要目的是一个是解决我日常开发的一些显而易见的问题(也可能可以通过各种 ssh 的配置方式解决,但我比较懒,不想手动去配置,希望用朴素的方式连接后工具就可以自动帮我记下来,这个从安全的角度来说,不是个好的实践方案),另一方面也是想业余时间写点产品化的东西,这样有助于我建立产品思维。在生产上,我肯定是优先考虑用成熟的产品,但在个人工作流自动化方面,更愿意折腾自己写点东西的。:)
    trzzzz
        24
    trzzzz  
       Dec 15, 2023
    https://github.com/T-TRz879/scpw 。这是我之前写过一个 scp 的客户端,个人工作需要经常传包,每次 server 和包都比较固定,懒得敲那么多。OP 的 ssx 很不错
    lstz
        25
    lstz  
       Dec 15, 2023 via iPhone
    不敢苟同以上部分同学的观点,难道有了 A 工具就不能再写个 B 工具吗?
    我认为百家争鸣是最好也是最健康的状态,楼主加油,支持一个
    LonnyWong
        26
    LonnyWong  
       Dec 15, 2023
    @lstz #25 有人反对楼主自己写吗?
    lstz
        27
    lstz  
       Dec 15, 2023 via iPhone
    @LonnyWong 无需问我
    lstz
        28
    lstz  
       Dec 15, 2023 via iPhone
    看来是误会,我收回前面的话
    YaD2x
        29
    YaD2x  
       Dec 15, 2023
    貌似在 windows 终端登录后,不支持上下翻动历史命令,终端的高亮颜色显示也有变化。
    vimiix
        30
    vimiix  
    OP
       Dec 17, 2023
    @trzzzz 过奖,后面有规划在 ssx 里加上 scp 的能力,在设计中
    vimiix
        31
    vimiix  
    OP
       Dec 17, 2023
    @lstz #25 感谢支持
    vimiix
        32
    vimiix  
    OP
       Dec 17, 2023
    @YaD2x #29 我这边测试了下,windows 上颜色正常,上下左右键确实失效了。我下周排查下看能否解决,感谢提醒
    vimiix
        33
    vimiix  
    OP
       Dec 17, 2023
    @YaD2x #29 windows 中方向键失效的问题已在 v0.0.4 版本修复
    Songine
        34
    Songine  
       Jan 6, 2024 via Android
    不错诶,安卓 APP 上也可以直接跑,但是搞不懂怎样才可以附加命令给连接的主机呢?
    类似 ssh user@ip cmd 好像不行..
    vimiix
        35
    vimiix  
    OP
       Jan 9, 2024
    @Songine #34 直接执行一条命令然后就返回,这个意思吗?如果是的话,这个后面版本会增加
    Songine
        36
    Songine  
       Jan 12, 2024 via Android
    @vimiix 对的,就是执行单条命令返回,后续会有这个功能的话那就太好了(◦˙▽˙◦)
    vimiix
        37
    vimiix  
    OP
       Jan 26, 2024   ❤️ 1
    @Songine 执行单条命令的功能已经在 v0.0.6 版本中支持
    https://github.com/vimiix/ssx/releases/tag/v0.0.6
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2732 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 75ms · UTC 15:18 · PVG 23:18 · LAX 08:18 · JFK 11:18
    ♥ Do have faith in what you're doing.