Windows SSH

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

注意

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

SSH 设置

自 Windows Server 2019 起,Microsoft 通过 Windows 功能提供 OpenSSH 实现。它也可以通过 Win32-OpenSSH 下的上游软件包安装。Ansible 官方仅支持 Windows 随附的 OpenSSH 实现,不支持上游软件包。OpenSSH 版本必须至少为 7.9.0.0。这实际上意味着官方支持从 Windows Server 2022 开始,因为 Server 2019 随附的版本为 7.7.2.1。使用较旧的 Windows 版本或上游软件包可能有效,但不受支持。

要在 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。也可以为 Windows 主机设置 ssh 下记录的其他 SSH 选项。

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 主机的身份。要将 GSSAPI 身份验证与 Ansible 一起使用,必须通过编辑 C:\ProgramData\ssh\sshd_config 文件来配置 Windows 服务器以允许 GSSAPI 身份验证。添加以下行或编辑现有行

GSSAPIAuthentication yes

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

在 Ansible 控制节点上,需要安装 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 hostvar 指定 UPN 用户名,并且 Ansible 在使用 SSH 时将自动使用该用户的 Kerberos 票证。

还可以通过 GSSAPI 身份验证启用无约束委派,以使 Windows 节点能够访问网络资源。要使 GSSAPI 委派工作,kinit 检索的票证必须是可转发的,并且必须使用 -o GSSAPIDelegateCredentials=yes 选项调用 ssh。要检索可转发的票证,请使用 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

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

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 主机,然后它会执行无约束委派以访问网络资源。