常用 ssh 客户端命令的几个最佳实践

·4 分钟阅读时长

很多文档或网络搜索结果中的 SSH 命令行操作已经过时了,例如生成 SSH 密钥还在推荐用 RSA 算法等。本文记录的一些常用的 SSH 客户端操作,尽可能采用了较新的操作实践。

生成 SSH 密钥

推荐命令👇

ssh-keygen -t ed25519 -C "your@example.com"
  • ed25519 是 OpenSSH 8.5+ 推荐的默认算法1),在加解密速度和安全性上都更有优势,生成的密钥文本还更短。
  • -C 参数加上备注信息,用来区分多个密钥的不同用途2
  • ⚠️非常不建议使用空密码,嫌输入密码麻烦的话应该使用 ssh-agent
  • 💡 keepassxc 等密码管理软件能与 ssh-agent 集成。

备选命令

ssh-keygen -t rsa -b 4096 -C "your@example.com"

在目标服务只兼容 RSA 类型密钥时才使用,并且加上 -b 指定 4096 位长度以增强安全性。

提示

  • 默认生成的密钥文件在 ~/.ssh 下,私钥默认文件名为 id_ed25519 或 id_rsa,公钥文件名多一个 .pub 的扩展后缀。
  • 前述 ssh-keygen 命令可以加上 -f my_ed25519 的参数来指定生成的密钥文件名。生成之后手动重命名也没问题,不会影响使用。

授权或信任公钥

生成的密钥需要提交公钥给远程 SSH 主机或服务,让主机或服务信任并关联到具体用户。

  • GitHub、Gitlab 或亚马逊、阿里云之类云服务等等,一般需要通过 Web 管理界面填写公钥的内容。
  • 对于开放 SSH 访问的远程主机,需要把公钥追加到远程主机的 ~/.ssh/authorized_keys 文件:
    ssh-copy-id user@remotehost
    
    • 注意把 user@remotehost 替代成自己的用户名和主机地址
  • 如果没有 ssh-copy-id,用以下 shell 命令替代:
    cat ~/.ssh/id_ed25519.pub \
    | ssh user@remotehost "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
    

SSH 用密钥连接

命令行参数

ssh -i ~/.ssh/my_ed25519 user@remotehost

配置文件3

  • ssh 命令按照下列顺序获取配置:
    1. 命令行参数
    2. 用户配置文件(~/.ssh/config)
    3. 系统配置文件(/etc/ssh/ssh_config)
  • 直接运行 ssh [user@]remotehost,如果远程主机需要密钥验证则
    • SSH 客户端会根据配置文件 来确定用户名和密钥文件
    • 如果配置文件里未指定,会尝试使用默认密钥文件名如 id_ed25519 或 id_rsa

典型用户配置示例

通过 ~/.ssh/config 为不同的主机或服务指定主机名或 IP 地址、端口、用户名,以及登录认证的重点——私钥文件。

Host dev-demo
    Hostname 192.168.100.50
    User ops-user
    IdentityFile ~/.ssh/dev_ed25519

Host 192.168.200.* !192.168.200.1
    User test-user
    IdentityFile ~/.ssh/test_ed25519

Host api.cloud
    Port 2222
    IdentityFile ~/.ssh/api_rsa
  • Host 可以是真实主机名、别名(真实主机名用 Hostname 指定)、IP 地址(可用通配符 *?!用来排除)
    • 利用通配符可以批量配置选项,也可以用来区分公司与个人项目的不同密钥等
    • 同一个主机例如 github.com,可以用别名来区分使用不同的密钥(工作与个人项目)
  • 更多配置选项参考官方文档 https://man.openbsd.org/ssh_config.5

ssh-agent

ssh-agent 的主要用途是两个:

  • 一是作为私钥的运行时安全存储,不需要每次使用的时候都提示输入密码;
  • 二是能把对私钥的访问转发给远程主机,但不暴露私钥本身。用途二实际上也包含了用途一。

前提

ssh-agent 需要作为服务或后台提前运行。macOS 操作系统以及大多数 Linux 系统下 ssh-agent 已经自动运行了。Windows 系统默认没有启动 ssh-agent,可以在 Win+X 快捷菜单中打开 Powershell (管理员权限)窗口,执行下列命令自动启动服务:

Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent

添加私钥

ssh-add ~/.ssh/secret_ed25519
  • ssh-add 命令把私钥添加到正在运行的 ssh-agent 中,需要密码的私钥只需要在这时候输入一次。重复运行命令可以添加多个私钥。
  • 注意:添加过一次后,当前 Windows 和 Linux 用户下次登录操作系统(哪怕重启后)还能继续使用添加过的私钥,一样不需要输入密码。macOS 则不一样,可以参考 https://apple.stackexchange.com/a/250572
  • ssh-add -L 可以查看已添加的私钥,另外删除已添加的私钥等功能可以参考文档

转发

如果要在远程主机上使用本地 ssh-agent 保存的私钥:

  • 方法一,带参数 -A 连接远程主机,例如 ssh -A user@remote.example.org
  • 方法二,在 ~/.ssh/config 里使用如下配置之后再连接到远程主机:
Host remote.example.org
    ForwardAgent Yes

安全操作

  • -x-X 可以使用密码锁定和解锁 ssh-agent。
  • -t 可以在添加私钥时指定有效时间
  • OpenSSH 8.9 开始可以限制指定的私钥只用于特定主机、跳板甚至用户名等: ssh-add -h "yourhost.example.org" ~/.ssh/id_ed25519,参考官方文档

错误处理

删除或更新 HostKey

有时访问远程主机服务的 SSH 指纹发生了变化,会出现如下提示:

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
......

在确认安全(例如系统重装或重新生成了证书等,不存在中间人攻击)的情况下,有几个处理方式:

  • 删除 ~/.ssh/known_hosts 中旧的服务器指纹,一般直接用 vi 编辑就行。
  • 有时 known_hosts 文件中的主机名是哈希过的,不能分辨该删除哪一行,可以使用命令: ssh-keygen -f ~/.ssh/known_hosts -R github.com
  • 使用参数接受新的指纹4 (OpenSSH >= 6.5):ssh -o StrictHostKeyChecking=accept-new user@remotehost
  • 使用参数临时忽略主机密钥检查:ssh -o StrictHostKeyChecking=no user@remotehost
  • 如果用的是 PuTTY ,需要用注册表编辑器到 HKEY_CURRENT_USER\SOFTWARE\SimonTatham\PuTTY\SshHostKeys 查找和删除对应的键值

退出无响应的会话

要退出无响应的 SSH 会话,可以连续按键 Enter~.

scp

💡 复杂的文件下载上传或同步(涉及是否覆盖、删除等),建议使用 rsync

上传单个文件到远程主机:

scp testfile.txt user@remotehost:/path

上传整个文件夹到远程主机路径:

scp -rp source_dir user@remotehost:/dest_dir
  • 从远程主机下载文件或目录,只需要把前面命令行中的源与目标掉换。
  • 参数 -p 的作用是保留文件修改和访问时间及权限位设置,-P 2222 才是指定 SSH 端口。

转载许可声明

CC-BY 4.0本作品采用知识共享-署名-相同方式共享 4.0 国际许可协议 进行许可,转载时请注明原文链接。