# Windows 免密码 SSH 连接指南 以从 Windows 设备(本地机)通过 SSH 连接到另一台 Windows 设备(远程机)为例。毕竟 Windows 是最难配置的,如果有一边是 Linux 设备会简单很多。 * 需要 Windows 10 或者更高的系统版本,以确认 OpenSSH 组件的安装。 * 不需要安装第三方 SSH 软件。 目录: - [本地机 OpenSSH 配置](#本地机-openssh-配置) - [远程机 OpenSSH 配置](#远程机-openssh-配置) - [如果要 SSH 到远程机 Admin 账户……](#如果要-ssh-到远程机-admin-账户) - [生成设备密钥](#生成设备密钥) - [将私钥添加到本地机 ssh-agent](#将私钥添加到本地机-ssh-agent) - [将公钥添加到远程机的受信列表](#将公钥添加到远程机的受信列表) - [最终测试](#最终测试) ----- ## 本地机 OpenSSH 配置 在本地机上,以**管理员身份**启动 Powershell,并按装 `OpenSSH.Client`: ```powershell Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*' Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 ``` ## 远程机 OpenSSH 配置 在远程机上,同样以**管理员身份**启动 Powershell。这次则需要安装 `OpenSSH.Server`: ```powershell Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*' Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 ``` 更改注册表键值,将 SSH 登录后的默认 shell 改完 Powershell(默认是 CMD): ```powershell New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "$(Get-Command powershell | % Source)" -PropertyType String -Force ``` 上述的 `Get-Command powershell | % Source` 实际上是返回 Windows 的默认 Powershell 路径。 最后,启动 `sshd` 服务,并设置为自动运行: ```powershell Start-Service sshd Set-Service -Name sshd -StartupType Automatic ``` ### 如果要 SSH 到远程机 Admin 账户…… *如果只需要 SSH 到远程机普通账户,可以跳过本节。* > **警告**:下述方法是一个不规范的懒人操作,它会使所有 `authorized_keys` 受信用户都能直接 SSH 到远程机的 Admin 账户,因此**存在显著的风险**。 > > 正确的做法是编辑 `administrators_authorized_keys` 文件,这可能还涉及到该文件的权限管理: > ```powershell > icacls.exe "C:\ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F" > ``` > > 请自行查询相关的内容。 如果你要从本地机 SSH 到远程机的 Admin 账户,你还需要在远程机上编辑 `C:\ProgramData\ssh\sshd_config` 文件。请在远程机上,以管理员模式启动 Powershell,并执行: ```powershell notepad C:\ProgramData\ssh\sshd_config ``` 在弹出的记事本编辑窗口中,找到最下方的这两行并注释掉: ``` #Match Group administrators # AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys ``` 如上所示,在这两行的前方各插入一个 `#` 来注释。这样 sshd 就不会查询该目录下的 `administrators_authorized_keys` 文件,而是查询默认的 `~/.ssh/authorized_keys` 文件。 在更改完成后,需要重启 SSH Server 服务。你可以运行 `services.msc` 并找到 OpenSSH SSH Server,右键选择重新启动。 ## 生成设备密钥 本地机上需要配置设备密钥,以方便进行 SSH 连接。 1. 打开本地机 `~\.ssh` 文件夹(`Invoke-Item ~/.ssh`),并检查其中的文件。 如果已经存在 `id_rsa`(私钥)以及 `id_rsa.pub`(公钥)文件,则说明已生成过 RSA 密钥,可以跳过本节,无须再生成一次。如果看到 `id_ed25519` (或其他类似文件名)则表示是用 ed25519 生成过密钥,也无须再生成一次。 2. 如果没有已生成的密钥,那么需要生成一个。从 Powershell 运行以下命令来默认生成一个 RSA 密钥: ```powershell ssh-keygen ``` 如果要生成 ed25519 密钥,则使用 `ssh-keygen -t ed25519` 命令。 3. 命令行提示你指定密钥文件保存位置,默认即可。 4. 它会提示你为密钥输入密码,建议指定一个密码。 5. 完成生成后,以 RSA 为例,你会在 `~\.ssh` 文件夹中看到 `id_rsa`(私钥)以及 `id_rsa.pub`(公钥)两个文件。 ## 将私钥添加到本地机 ssh-agent 要在 SSH 连接时免除输入密钥的密码,需要让本地机的 `ssh-agent` 服务托管该密钥。 1. 在本地机上以**管理员身份**运行 Powershell,并启动 ssh-agent 服务: ```powershell Get-Service ssh-agent | Set-Service -StartupType Manual Start-Service ssh-agent ``` 2. 添加密钥(私钥): ```powershell cd ~/.ssh ssh-add id_rsa ``` 如果使用的是 ed25519 或其他方式生成的密钥,请相应地更改上述 `id_rsa` 私钥名称。 ## 将公钥添加到远程机的受信列表 要在 SSH 连接远程机时免除输入远程机账户的密码,需要将本地的公钥(而不是私钥)文本内容添加到远程机的 `authorized_keys` 文件中。 1. 在本地机上打开 Powershell,复制本地的公钥(以 RSA 密钥为例)到剪贴板: ```powershell cat ~/.ssh/id_rsa.pub | clip ``` 2. 使用 SSH 命令登录到远程机的 `USER` 用户: ```powershell ssh USER@HOST ``` 以局域网为例:`ssh wklchris@192.168.x.x`。请注意,如果要使用局域网 IP 地址来访问远程机,请在路由器中为远程机分配一个固定的局域网 IP。如果你不知道远程机的局域网 IP,可以在远程机上,使用下述命令查询: ```powershell (Get-NetIPAddress -InterfaceAlias WLAN -AddressFamily IPv4).IPAddress ``` 3. 按 SSH 提示,输入远程机中 USER 账户的登录密码以建立连接。 4. 现在你已经成功连接到远程机的 Powershell 了。接下来需要把在步骤 1 中复制的本地机公钥添加到远程机的受信文件中。我们可以创建一个变量来保存刚才的复制文本(请将单引号内的 `PASTE` 替换为你复制的公钥文本): ```powershell $key='PASTE' ``` 5. 将它追加到远程机的 `authorized_keys` 文件末尾(已另起一行): ```powershell Add-Content ~/.ssh/authorized_keys "`n$key" ``` 6. 你可以打印该文件内容到 Powershell 来确认已添加: ```powershell cat ~/.ssh/authorized_keys ``` 7. 输入 `exit` 并回车,以退出远程机的 SSH 连接。此时你已经返回本地机的 Powershell 了。 ## 最终测试 至此,所有的配置均已完成了。但远程机仍可能需要对 SSH Server 服务进行一次重启。 1. 在远程机上,运行 `services.msc` 并找到 OpenSSH SSH Server,右键选择重新启动。 2. 在本地机上,打开 Powershell,并尝试用 `ssh` 命令连接远程机。 3. 此时, SSH 应该能无须输入任何密码地连接到远程机了。 4. 如一切测试无问题,在本地机上将 `ssh-agent` 服务设置为自动,以在下次启动电脑后仍能免密连接: ```powershell Get-service ssh-agent | Set-service -StartupType Automatic ```