Windows SSH

在较新的 Windows 版本上,您可以使用 SSH 连接到 Windows 主机。这是 WinRM 的另一种连接选项。

注意

虽然 Ansible 可以自 Ansible 2.8 版本以来将 SSH 连接插件用于 Windows 节点,但官方支持仅在 2.18 版本中添加。

SSH 设置

微软自 Windows Server 2019 以来在 Windows 中提供了一个 OpenSSH 实现,作为 Windows 功能。它也可以通过 Win32-OpenSSH 下的 upstream 软件包进行安装。Ansible 官方只支持 Windows 附带的 OpenSSH 实现,不支持 upstream 软件包。OpenSSH 版本必须至少为 7.9.0.0。这实际上意味着官方支持从 Windows Server 2022 开始,因为 Server 2019 附带的是 7.7.2.1 版本。使用较旧的 Windows 版本或 upstream 软件包可能有效,但不被支持。

要在 Windows Server 2022 及更高版本上安装 OpenSSH 功能,请使用以下 PowerShell 命令

Get-WindowsCapability -Name OpenSSH.Server* -Online |
    Add-WindowsCapability -Online
Set-Service -Name sshd -StartupType Automatic -Status Running

$firewallParams = @{
    Name        = 'sshd-Server-In-TCP'
    DisplayName = 'Inbound rule for OpenSSH Server (sshd) on TCP port 22'
    Action      = 'Allow'
    Direction   = 'Inbound'
    Enabled     = 'True'  # This is not a boolean but an enum
    Profile     = 'Any'
    Protocol    = 'TCP'
    LocalPort   = 22
}
New-NetFirewallRule @firewallParams

$shellParams = @{
    Path         = 'HKLM:\SOFTWARE\OpenSSH'
    Name         = 'DefaultShell'
    Value        = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'
    PropertyType = 'String'
    Force        = $true
}
New-ItemProperty @shellParams

默认 Shell 配置

默认情况下,Windows 上的 OpenSSH 使用 cmd.exe 作为默认 shell。虽然 Ansible 可以使用此默认 shell,但建议将其更改为 powershell.exe,因为它经过更好的测试,并且应该比使用 cmd.exe 作为默认值更快。要更改默认 shell,您可以使用以下 PowerShell 脚本

# Set default to powershell.exe
$shellParams = @{
    Path         = 'HKLM:\SOFTWARE\OpenSSH'
    Name         = 'DefaultShell'
    Value        = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'
    PropertyType = 'String'
    Force        = $true
}
New-ItemProperty @shellParams

# Set default back to cmd.exe
Remove-ItemProperty -Path HKLM:\SOFTWARE\OpenSSH -Name DefaultShell

新的默认 shell 设置将应用于下一个 SSH 连接,无需重新启动 sshd 服务。您也可以使用 Ansible 来配置默认 shell

- name: set the default shell to PowerShell
  ansible.windows.win_regedit:
    path: HKLM:\SOFTWARE\OpenSSH
    name: DefaultShell
    data: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    type: string
    state: present

- name: reset SSH connection after shell change
  ansible.builtin.meta: reset_connection

- name: set the default shell to cmd
  ansible.windows.win_regedit:
    path: HKLM:\SOFTWARE\OpenSSH
    name: DefaultShell
    state: absent

- name: reset SSH connection after shell change
  ansible.builtin.meta: reset_connection

meta: reset_connection 非常重要,以确保后续任务将使用新的默认 shell。

Ansible 配置

要将 Ansible 配置为对 Windows 主机使用 SSH,您必须设置两个连接变量

  • ansible_connection 设置为 ssh

  • ansible_shell_type 设置为 powershellcmd

ansible_shell_type 变量应反映在 Windows 主机上配置的 DefaultShell。在 ssh 下记录的其他 SSH 选项也可以为 Windows 主机设置。

SSH 身份验证

Windows 上的 Win32-OpenSSH 身份验证类似于 Unix/Linux 主机上的 SSH 身份验证。虽然可以使用许多身份验证方法,但通常在 Windows 上使用三种方法

选项

本地帐户

Active Directory 帐户

凭据委派

密钥

GSSAPI

密码

在大多数情况下,建议使用密钥或 GSSAPI 身份验证而不是密码身份验证。

密钥身份验证

Windows 上的 SSH 密钥身份验证与 POSIX 节点的 SSH 密钥身份验证工作方式相同。您可以使用 ssh-keygen 命令生成密钥对,并将公钥添加到用户配置文件目录中的 authorized_keys 文件中。私钥应保密,不要共享。

一个区别是,管理员用户的 authorized_keys 文件不位于用户配置文件目录的 .ssh 文件夹中,而是在 C:\ProgramData\ssh\administrators_authorized_keys 中。可以通过删除或注释 C:\ProgramData\ssh\sshd_config 中的行并重新启动 sshd 服务,将管理员用户的 authorized_keys 文件的位置更改回用户配置文件目录。

Match Group administrators
    AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

SSH 密钥适用于本地帐户和域帐户,但存在双跳问题。这意味着,当使用 SSH 密钥身份验证与 Ansible 时,远程会话将无法访问用户凭据,并在尝试访问网络资源时失败。要解决此问题,您可以在需要访问远程资源的用户凭据的该任务上使用 become

GSSAPI 身份验证

GSSAPI 身份验证将使用 Kerberos 来验证用户对 Windows 主机的身份。要在 Ansible 中使用 GSSAPI 身份验证,Windows 服务器必须配置为通过编辑 C:\ProgramData\ssh\sshd_config 文件来允许 GSSAPI 身份验证。添加以下行或编辑现有行

GSSAPIAuthentication yes

编辑完成后,使用 Restart-Service -Name sshd 重新启动 sshd 服务。

在 Ansible 控制节点上,您需要安装并配置 Kerberos,该 Kerberos 与 Windows 主机所在的域关联。如何设置和配置超出了本文档的范围。配置完 Kerberos 域后,您可以使用 kinit 命令获取您正在连接的用户票证,并使用 klist 验证哪些票证可用

> kinit [email protected]
Password for [email protected]

> klist
Ticket cache: KCM:1000
Default principal: [email protected]

Valid starting     Expires            Service principal
29/08/24 13:54:51  29/08/24 23:54:51  krbtgt/[email protected]
        renew until 05/09/24 13:54:48

获得有效票证后,您可以使用 ansible_user 主机变量指定 UPN 用户名,Ansible 将在使用 SSH 时自动为该用户使用 Kerberos 票证。

也可以通过 GSSAPI 身份验证启用不受约束的委派,让 Windows 节点访问网络资源。为了让 GSSAPI 委派工作,由 kinit 获取的票证必须是可转发的,并且 ssh 必须使用 -o GSSAPIDelegateCredentials=yes 选项调用。要检索可转发票证,请使用 kinit-f 标志,或者在 /etc/krb5.conf 文件的 [libdefaults] 下添加 forwardable = true

> kinit -f [email protected]
Password for [email protected]

# -f will show the ticket flags, we want to see F
> klist -f
Ticket cache: KCM:1000
Default principal: [email protected]

Valid starting     Expires            Service principal
29/08/24 13:54:51  29/08/24 23:54:51  krbtgt/[email protected]
        renew until 05/09/24 13:54:48, Flags: FRIA

GSSAPIDelegateCredentials=yes 选项可以设置在 ~/.ssh/config 文件中,也可以作为清单中的主机变量设置

ansible_ssh_common_args: -o GSSAPIDelegateCredentials=yes

psrpwinrm 连接插件不同,SSH 连接插件无法在提供显式用户名和密码时获取 Kerberos TGT 票证。这意味着用户必须在运行 playbook 之前拥有有效的 Kerberos 票证。

有关如何配置、使用和排除 Kerberos 身份验证故障的更多信息,请参阅 Kerberos 身份验证

密码身份验证

密码身份验证是最不安全的身份验证方法,不建议使用。但是,可以使用密码身份验证与 Windows SSH。要使用 Ansible 的密码身份验证,请在清单文件或 playbook 中设置 ansible_password 变量。使用密码身份验证需要在 Ansible 控制节点上安装 sshpass 包。

密码身份验证的工作原理类似于 WinRM CredSSP 身份验证,其中用户名和密码被提供给 Windows 主机,它将执行不受约束的委派以访问网络资源。