使用公钥认证设置Windows的OpenSSH

124

我在为Windows设置OpenSSH时遇到了问题,使用公钥验证。

我已经在我的本地桌面上实现了这个功能,并且可以通过Unix机器或其他OpenSSH for Windows机器使用密钥进行ssh连接。

我已经将构建复制到服务器上,我可以成功使用密码验证,但是当我使用密钥时,出现以下问题:

debug1: Authentications that can continue: publickey,password,keyboard-interactive
debug3: start over, passed a different list publickey,password,keyboard-interactive
debug3: preferred publickey,keyboard-interactive,password
debug3: authmethod_lookup publickey
debug3: remaining preferred: keyboard-interactive,password
debug3: authmethod_is_enabled publickey
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /cygdrive/c/sshusers/jsadmint2232/.ssh/id_rsa
debug3: send_pubkey_test
debug2: we sent a publickey packet, wait for reply
Connection closed by 127.0.0.1

为了测试,我一直在尝试连接本地主机的SSH,但即使远程尝试,我也遇到了同样的问题。

更奇怪的是,在sshd_config中启用密码和公钥时,它只会尝试使用密钥,然后以上述消息崩溃,并且甚至不会尝试使用密码。

我已经执行了以下步骤:

  1. 安装Windows的OpenSSH
  2. mkgroup -l >>..\etc\group(添加本地群组)
  3. mkgroup -d >>..\etc\group(添加域群组)
  4. mkpasswd -L -u openssh >>..\passwd(添加我的本地用户)
  5. mkpasswd -D -u jsadmint2232 >>..\passwd(添加我的域用户)
  6. 编辑文件passwd中的homedir,将其指向c:\sshusers%USER%,其中%USER%是用户名
  7. 启用密码身份验证,禁用密钥身份验证
  8. 为jsadmint2232/OpenSSH创建SSH密钥,并确保文件已创建在主目录中
  9. 在每个用户的.ssh目录中添加authorized_keys文件,并为传入连接的用户添加密钥
  10. net stop opensshd/ net start opensshd
  11. 测试本地和远程是否都可以使用密码身份验证
  12. 更新sshd_config以启用密钥身份验证-重新启动opensshd
  13. 测试连接并获得上述错误。此外,它甚至不会尝试使用密码身份验证。
  14. 更新sshd_config以完全禁用密码身份验证-重新启动opensshd
  15. 测试连接,仍然获得以上错误

看起来服务器因某种原因终止了连接。

13个回答

364
以下是Windows 10 v.1803(2018年4月更新)中随附的OpenSSH的设置步骤。请注意,根据本帖的评论,它可能不适用于1809版本。
服务器设置(以管理员权限运行PowerShell):
1. 安装OpenSSH服务器:`Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0`。
2. 启动代理和sshd服务:`Start-Service ssh-agent; Start-Service sshd`(这将自动生成主机密钥和默认配置文件,保存在`$env:ProgramData\ssh`目录下)。
3. 【可选】安装OpenSSHUtils PowerShell模块:`Install-Module -Force OpenSSHUtils`。
客户端设置(非管理员权限运行PowerShell):
  1. 生成用户密钥:cd $env:USERPROFILE\.ssh; ssh-keygen.exe,按照提示操作,同意默认建议的文件位置。这将创建2个文件:id_rsaid_rsa.pub

  2. [可选] 将密钥添加到身份验证代理中,这样每次使用时就不必输入密码:ssh-add .\id_rsa(或生成的任何文件);

服务器设置继续(非提升的 PowerShell):

  1. 以使用公钥身份验证的用户身份登录
  2. cd $env:USERPROFILE; mkdir .ssh; cd .ssh; New-Item authorized_keys;
  3. 将客户端中的id_rsa.pub文件内容粘贴到上一步骤中的.ssh\authorized_keys文件中。确保它以UTF-8编码。
  4. 正确设置权限(非常重要!!!):
  5. 运行start .以打开当前文件夹($env:USERPROFILE\.ssh)的资源管理器;
  6. 右键单击authorized_keys,转到属性 -> 安全 -> 高级
  7. 点击“禁用继承”;
  8. 在提示时选择“将继承的权限转换为此对象上的显式权限”;
  9. (真的非常重要)除了SYSTEM你自己之外,删除文件上的所有权限。文件上必须有仅两个权限条目。一些指南建议运行Repair-AuthorizedKeyPermission $env:USERPROFILE\.ssh\authorized_keys - 这将尝试将sshd用户添加到权限列表中,并且它会破坏身份验证,因此不要这样做,或者至少不要同意添加sshd用户。 SYSTEM和你自己应该对文件拥有完全控制权。
  10. 如果您的Windows版本是1809或更高版本,则需要注释掉C:\ProgramData\ssh\sshd_config文件中的以下行。然后重新启动sshd服务。
    # Match Group administrators                                                    
    #       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys  
    

客户端:

  1. 运行 ssh <serverusername>@<serverhostname>。此时应该可以正常工作。

我已经尝试在 Windows 10 作为服务器,Debian Linux 作为客户端的情况下进行了测试。


7
你是我的英雄@n0rd...我努力了好几个小时才设定权限,但似乎执行Repair-AuthorizedKeyPermission时设置了sshd用户,结果却导致出现问题!(我本以为这个设置是为了让OpenSSH SSH服务器进程可以查看它)。非常感谢! - gabn88
3
谢谢!我处理这个问题已经很长时间了,直到读了你的回答! - rhcpfan
40
我的问题需要另一个跟进和解决方案:在Windows 10 1809中,C:\ProgramData\ssh\sshd_config有一个新的特殊配置条目,它定义了对于管理员用户,密钥将从__PROGRAMDATA__/ssh/administrators_authorized_keys读取。同样,这个文件需要特殊的权限,只有系统用户和管理员组才能访问它。 - kayahr
8
这对我帮助很大,但权限仍然是个问题。这3个命令解决了它:'icacls C:\ProgramData\ssh\administrators_authorized_keys /remove "NT AUTHORITY\Authenticated Users"'、'icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r'以及'get-acl C:\ProgramData\ssh\ssh_host_dsa_key | set-acl C:\ProgramData\ssh\administrators_authorized_keys'。[来源] - bitinerant
11
谢谢!为了能够使用无密码密钥身份验证,在“user/.ssh”目录下的authorized_keys文件中,我需要注释掉以下几行: `# Match Group administrators

AuthorizedKeysFile PROGRAMDATA/ssh/administrators_authorized_keys`,然后重新启动“OpenSSH SSH Server”服务。

- trogne
显示剩余32条评论

32

请使用PowerShell中的以下命令序列来更正administrators_authorized_keys的权限。

$acl = Get-Acl C:\ProgramData\ssh\administrators_authorized_keys
$acl.SetAccessRuleProtection($true, $false)
$administratorsRule = New-Object system.security.accesscontrol.filesystemaccessrule("Administrators","FullControl","Allow")
$systemRule = New-Object system.security.accesscontrol.filesystemaccessrule("SYSTEM","FullControl","Allow")
$acl.SetAccessRule($administratorsRule)
$acl.SetAccessRule($systemRule)
$acl | Set-Acl

只有SYSTEM和管理员组在文件中没有继承权限。

管理员_授权密钥的权限设置


4
似乎有些令人惊讶,上述解决方案只适用于语言设置为英语的系统。例如,在使用法语语言的 Windows 10 上,您需要用“Administrateurs”替换“Administrators”,用“Système”替换“System”。很惊讶吧? - John Smith Optional
1
@JohnSmithOptional 最好使用已经存在的acl来创建文件: get-acl C:\ProgramData\ssh\ssh_host_dsa_key | set-acl C:\ProgramData\ssh\administrators_authorized_keys - SolomidHero
1
感谢你的提示,SolomidHero。那是一个有趣的解决方案,但这假设你手头有一个你知道具有正确acl的文件。话虽如此,了解到你可以像那样从一个文件复制acl还是很好的。 - John Smith Optional

25

一个额外的提示,如果你卡住了,可以尝试以调试模式运行sshd。我是这样做的:

  1. 停止sshd服务
  2. 以管理员权限打开PowerShell控制台
  3. 键入“sshd -d”
  4. 从我的客户机上键入login

后来发现密钥需要放在例如C:\ProgramData\ssh\administrators_authorized_keys而不是在C:\Users\yourUsser.ssh\authorized_keys中。


4
对我来说非常有用的答案。它不仅回答了“问题是什么”,而且还告诉了我如何下次解决类似问题。 - Arty

8
我解决了这个问题...
这与启动服务的帐户有关 - 它使用了“本地系统”帐户 - 这使得它无法访问公钥和authorized_keys文件。
一旦我停止了服务,并以我尝试连接的用户身份启动,它就工作了!
所以基本上,您需要从服务帐户开始,然后外部用户以该用户的身份连接。

3
你说的“停止服务并以我尝试连接的用户身份启动”是什么意思?我想你不是指让我使用我的实际域用户账户。然后你建议我从一个服务账户开始,但是哪一个账户呢? - ShieldOfSalvation
2
在查看本回答之前,我建议先阅读@n0rd下面的回答。 - Michael
这也解决了我的问题 - 但我不认为这是正确的解决方案。 - Joshua Flanagan

7
n0rd的解决方案是正确的,但对于那些也属于管理员组的用户来说,有一个额外的复杂性。如果您正在寻找以下情况的解决方案:
  • 您想基于每个用户使用公钥(或者您不想使用administrators_authorized_keys文件)。
  • 并且您不想使用PasswordAuthentication。
  • 而且一些用户也属于管理员组。
我遇到的问题是,在尝试n0rd的解决方案时,它不能满足上述条件下的用户。经过一些调试,我找到了一个适用于我的一致性解决方案。请遵循n0rd的解决方案,并只更改以下内容:
ssh_config中,请确保设置以下设置:
AuthorizedKeysFile  .ssh/authorized_keys 
PasswordAuthentication no
PubkeyAuthentication yes

同时,确保注释掉“Match Group Administrators”设置:

#Match Group administrators
#       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

请确保在服务器的C:\Users\username\.ssh\authorized_keys文件中包括客户端的公钥。

最后,为了帮助将用户与账号匹配,我发现在客户端的用户数据上更加具体是有益的。而不是仅使用简单的用户名,我使用了服务器上用户的域和用户名。在我的情况下,我的客户端的C:\Users\UserName\.ssh\config文件如下:

Host my_short_name
  HostName my.serveraddress.net
  User serversname\username
  IdentityFile .ssh\id_rsa

在这种情况下,我的Windows 10服务器将被称为“serversname”(设备名称下)。通过以这种方式指定用户,我可以避免密码验证。

作为额外的奖励,这对于默认的PowerShell 7 shell非常有效。即使是我的默认PowerShell配置文件也可以通过ssh工作,并且我获得了posh-git和oh-my-posh的完全支持。然而,我发现使PowerShell成为默认shell环境的默认方法(通过编辑ssh_conf以包括'Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -NoLogo')对于我来说不起作用。相反,在服务器上使用提升的PowerShell窗口中的命令:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "c:/progra~1/powershell/7/pwsh.exe" -PropertyType String -Force

这只是创建了一个注册表项。如果您想删除它,您可以随时在注册表中找到并删除它。


2
我不知道这个为什么有用,但是注释掉Match Group Administrators设置解决了我的问题。正如下面有人告诉的那样,这可能是由服务器上使用的非英语区域设置引起的。 - Peter Zaitcev
1
我将“Match Group Administrators”注释掉,启用了“PubkeyAuthentication yes”,然后重新启动了服务“ControlPanel> AdministratorTools> Services>sshd”,最终解决了问题,谢谢。 - OSezer

5

这只是我根据 @n0rds优秀答案 编写的脚本版本。

将此脚本放置在带有您的公钥/私钥对的目录中并运行!

PowerShell.exe -ExecutionPolicy Bypass -File "C:\bypass\prompt\standard.ps1" 2>&1>$null

Add-WindowsCapability -Online -Name OpenSSH.Server
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH SSH Server' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 -Program "%WINDIR%\System32\OpenSSH\sshd.exe"

#Must Enable ssh-agent before starting
Set-Service -Name ssh-agent -StartupType Automatic
Set-Service -Name sshd -StartupType Automatic
Start-Service ssh-agent; Start-Service sshd

$sshdir="$env:USERPROFILE\.ssh"
mkdir $sshdir
copy .\id_rsa $sshdir\
cat  $sshdir\id_rsa
copy .\*.pub  $sshdir\authorized_keys
cat $sshdir\authorized_keys
ssh-add $sshdir\id_rsa

$sshd_config="C:\ProgramData\ssh\sshd_config" 
(Get-Content $sshd_config) -replace '#PubkeyAuthentication', 'PubkeyAuthentication' | Out-File -encoding ASCII $sshd_config
(Get-Content $sshd_config) -replace 'AuthorizedKeysFile __PROGRAMDATA__', '#AuthorizedKeysFile __PROGRAMDATA__' | Out-File -encoding ASCII $sshd_config
(Get-Content $sshd_config) -replace 'Match Group administrators', '#Match Group administrators' | Out-File -encoding ASCII $sshd_config
cat C:\ProgramData\ssh\sshd_config

Restart-Service ssh-agent; Restart-Service sshd

Write-Host "Use this to Login/test Now"
write-host ssh $env:UserName@localhost

3
如果您正在使用mls-software.com的OpenSSH版本,这里有另一个提示。
如果您使用SSHD_SERVER帐户和特权分离进行安装,则可以使用公钥身份验证(参见http://www.mls-software.com/opensshd-pki.html)。但是,如果启用了UAC,则安装将不成功。用户将无法正确创建,服务也将无法创建。事后手动尝试使这些项正常运行非常困难。只需在安装之前禁用UAC即可使安装过程正确创建用户和服务。安装完成后,您可以重新启用UAC。
当我手动创建SSHD_SERVER帐户时,使用密码身份验证时认证成功,但客户端终止连接并显示“/bin/bash:操作不允许”。服务器关闭了公钥身份验证(Cambolie发布的原始错误)。

来自mls-software的反馈指出,这并不总是适用的。在我的情况下禁用UAC可以解决问题,但在所有情况下可能并非必要。我将进一步研究我的情况并查看是否可以发布更多细节。 - Dustin
为什么MLS OpenSSH很重要?为什么它不能作为本地系统(或其他甚至域帐户)运行? - Mikhail Orlov

1
我通过以下方式解决了这个问题:
  1. 安装 SSHD_SERVER + 特权分离模式。我还手动在配置中将特权分离设置为“是”。这在很长一段时间内对我不起作用,用户没有被创建。然后它工作了,我不知道为什么。我只是去控制面板中的用户帐户检查 UAC 是否关闭。我还为每个人提供了 /var/empty 的完全访问权限。
  2. 对于 C:\openssh\var\empty,我将“属性获取/设置”权限设置为每个人和自己,并将“完全”权限设置为 .\sshd_server。我还将其设置为所有者。

1
我遇到了一个不同的情况。
首先,按照gWay所说的,在另一个终端窗口连接服务器进行调试。
我得到了read_keyfile_line: C:\\Users\\yieatn\\.ssh/authorized_keys line 1 exceeds size limit
将authorized_keys重新编码为utf-8。
原因是我使用cat id_rsa >> authorized_keys和中文PowerShell创建文件时使用UTF-16创建了authorized_keys。

0

我无法使用我的ed25519客户端公钥(ssh-keygen -t ed215519)使其工作,但是它可以使用rsa密钥(ssh-keygen -t rsa)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接