Windows SSH

在较新的 Windows 版本中,您可以使用 SSH 连接到 Windows 主机。这是 WinRM 的替代连接选项。

注意

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

SSH 设置

Microsoft 从 Windows Server 2019 开始在 Windows 中提供 OpenSSH 实现作为 Windows 功能。它也可以通过 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 上使用三种方法

选项

本地帐户

活动目录帐户

凭据委派

密钥

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 主机变量指定 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

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

ansible_ssh_common_args: -o GSSAPIDelegateCredentials=yes

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

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

密码认证

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

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