Windows 远程管理
与默认使用 SSH 的 Linux/Unix 主机不同,Windows 主机配置使用 WinRM。本主题介绍如何配置和使用 WinRM 与 Ansible。
什么是 WinRM?
WinRM 是 Windows 用于与另一台服务器远程通信的管理协议。它是一个基于 SOAP 的协议,通过 HTTP/HTTPS 通信,包含在所有最新的 Windows 操作系统中。从 Windows Server 2012 开始,WinRM 默认启用,但在某些情况下,需要额外配置才能将 WinRM 与 Ansible 一起使用。
Ansible 可以通过 psrp 或 winrm 连接插件使用 WinRM。这些插件有其自身的 Python 依赖项,这些依赖项不包含在 Ansible 软件包中,必须单独安装。
如果您选择 pipx
安装说明,您可以通过运行以下命令安装这些依赖项:
pipx inject "pypsrp<=1.0.0" # for psrp
pipx inject "pywinrm>=0.4.0" # for winrm
或者,如果您选择 pip
安装说明:
pip3 install "pypsrp<=1.0.0" # for psrp
pip3 install "pywinrm>=0.4.0" # for winrm
警告
在最新版本的 MacOS 上的 Ansible 中使用 winrm
或 psrp
连接插件通常会失败。这是一个已知问题,它发生在 Python 堆栈深处,Ansible 无法更改。目前唯一的解决方法是设置环境变量 OBJC_DISABLE_INITIALIZE_FORK_SAFETY=yes
、no_proxy=*
并避免使用 Kerberos 身份验证。
WinRM 设置
在 Ansible 可以使用 WinRM 连接之前,Windows 主机必须配置 WinRM 侦听器。此侦听器将在配置的端口上侦听并接受传入的 WinRM 请求。
虽然本指南更详细地介绍了如何枚举、添加和删除侦听器,但您可以运行以下 PowerShell 代码片段来设置具有默认值的 HTTP 侦听器:
# Enables the WinRM service and sets up the HTTP listener
Enable-PSRemoting -Force
# Opens port 5985 for all profiles
$firewallParams = @{
Action = 'Allow'
Description = 'Inbound rule for Windows Remote Management via WS-Management. [TCP 5985]'
Direction = 'Inbound'
DisplayName = 'Windows Remote Management (HTTP-In)'
LocalPort = 5985
Profile = 'Any'
Protocol = 'TCP'
}
New-NetFirewallRule @firewallParams
# Allows local user accounts to be used with WinRM
# This can be ignored if using domain accounts
$tokenFilterParams = @{
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
Name = 'LocalAccountTokenFilterPolicy'
Value = 1
PropertyType = 'DWORD'
Force = $true
}
New-ItemProperty @tokenFilterParams
要添加使用自签名证书的 HTTPS 侦听器,我们可以运行以下命令:
# Create self signed certificate
$certParams = @{
CertStoreLocation = 'Cert:\LocalMachine\My'
DnsName = $env:COMPUTERNAME
NotAfter = (Get-Date).AddYears(1)
Provider = 'Microsoft Software Key Storage Provider'
Subject = "CN=$env:COMPUTERNAME"
}
$cert = New-SelfSignedCertificate @certParams
# Create HTTPS listener
$httpsParams = @{
ResourceURI = 'winrm/config/listener'
SelectorSet = @{
Transport = "HTTPS"
Address = "*"
}
ValueSet = @{
CertificateThumbprint = $cert.Thumbprint
Enabled = $true
}
}
New-WSManInstance @httpsParams
# Opens port 5986 for all profiles
$firewallParams = @{
Action = 'Allow'
Description = 'Inbound rule for Windows Remote Management via WS-Management. [TCP 5986]'
Direction = 'Inbound'
DisplayName = 'Windows Remote Management (HTTPS-In)'
LocalPort = 5986
Profile = 'Any'
Protocol = 'TCP'
}
New-NetFirewallRule @firewallParams
警告
以上脚本仅用于演示目的,在生产环境中运行之前应进行审查。某些更改(例如,为所有传入连接打开防火墙端口,允许使用 WinRM 的本地帐户,自签名证书)可能不适用于所有环境。
枚举侦听器
要查看 WinRM 服务上正在运行的当前侦听器:
winrm enumerate winrm/config/Listener
这将输出类似以下内容:
Listener
Address = *
Transport = HTTP
Port = 5985
Hostname
Enabled = true
URLPrefix = wsman
CertificateThumbprint
ListeningOn = 10.0.2.15, 127.0.0.1, 192.168.56.155, ::1, fe80::5efe:10.0.2.15%6, fe80::5efe:192.168.56.155%8, fe80::
ffff:ffff:fffe%2, fe80::203d:7d97:c2ed:ec78%3, fe80::e8ea:d765:2c69:7756%7
Listener
Address = *
Transport = HTTPS
Port = 5986
Hostname = SERVER2016
Enabled = true
URLPrefix = wsman
CertificateThumbprint = E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE
ListeningOn = 10.0.2.15, 127.0.0.1, 192.168.56.155, ::1, fe80::5efe:10.0.2.15%6, fe80::5efe:192.168.56.155%8, fe80::
ffff:ffff:fffe%2, fe80::203d:7d97:c2ed:ec78%3, fe80::e8ea:d765:2c69:7756%7
在上面的示例中,配置了两个 WinRM 侦听器。一个通过 HTTP 在端口 5985 上侦听,另一个通过 HTTPS 在端口 5986 上侦听。一些有用的关键选项包括:
Transport
:侦听器是通过 HTTP 还是 HTTPS 运行。Port
:侦听的端口,HTTP 的默认值为5985
,HTTPS 的默认值为5986
。CertificateThumbprint
:对于 HTTPS,这是用于 TLS 连接的证书的指纹。
要查看 CertificateThumbprint
指定的证书详细信息,您可以运行以下 PowerShell 命令:
$thumbprint = "E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE"
Get-Item -Path "Cert:\LocalMachine\My\$thumbprint" | Select-Object *
创建侦听器
可以通过 Enable-PSRemoting
cmdlet 创建 HTTP 侦听器,但您也可以使用以下 PowerShell 代码手动创建 HTTP 侦听器。
$listenerParams = @{
ResourceURI = 'winrm/config/listener'
SelectorSet = @{
Transport = "HTTP"
Address = "*"
}
ValueSet = @{
Enabled = $true
Port = 5985
}
}
New-WSManInstance @listenerParams
创建 HTTPS 侦听器类似,但 Port
现在是 5985
,并且必须设置 CertificateThumbprint
值。证书可以是自签名证书或来自证书颁发机构的证书。如何生成证书不在本节的讨论范围之内。
$listenerParams = @{
ResourceURI = 'winrm/config/listener'
SelectorSet = @{
Transport = "HTTP"
Address = "*"
}
ValueSet = @{
CertificateThumbprint = 'E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE'
Enabled = $true
Port = 5985
}
}
New-WSManInstance @listenerParams
CertificateThumbprint
值必须设置为安装在 LocalMachine\My
证书存储中的证书的指纹。
Address
选择器值可以设置为以下三个值之一:
*
- 绑定到所有地址IP:...
- 绑定到由...
指定的 IPv4 或 IPv6 地址MAC:32-a3-58-90-be-cc
- 绑定到具有指定 MAC 地址的适配器
删除侦听器
以下代码可以删除所有侦听器或特定侦听器:
# Removes all listeners
Remove-Item -Path WSMan:\localhost\Listener\* -Recurse -Force
# Removes only HTTP listeners
Get-ChildItem -Path WSMan:\localhost\Listener |
Where-Object Keys -contains "Transport=HTTP" |
Remove-Item -Recurse -Force
# Removes only HTTPS listeners
Get-ChildItem -Path WSMan:\localhost\Listener |
Where-Object Keys -contains "Transport=HTTPS" |
Remove-Item -Recurse -Force
WinRM 身份验证
WinRM 有几种不同的身份验证选项可用于对具有 Windows 主机的用户进行身份验证。每个选项都有其自身的优点和缺点,因此了解何时使用每个选项以及何时不使用每个选项非常重要。
下表是选项的高级概述:
选项 |
本地帐户 |
活动目录帐户 |
凭据委派 |
HTTP 加密 |
---|---|---|---|---|
基本 |
是 |
否 |
否 |
否 |
证书 |
是 |
否 |
否 |
否 |
Kerberos |
否 |
是 |
是 |
是 |
NTLM |
是 |
是 |
否 |
是 |
CredSSP |
是 |
是 |
是 |
是 |
不应通过 HTTP 侦听器使用 Basic
和 NTLM
身份验证选项,因为它们要么不提供加密,要么提供非常弱的加密。psrp
连接插件还提供 Negotiate
身份验证选项,它将在回退到 NTLM
之前尝试使用 Kerberos
。winrm
连接插件必须指定 kerberos
或 ntlm
。
要指定身份验证协议,您可以使用以下变量:
# For psrp
ansible_psrp_auth: basic|certificate|negotiate|kerberos|ntlm|credssp
# For winrm
ansible_winrm_transport: basic|certificate|kerberos|ntlm|credssp
对于 WinRM,建议在域环境中通过 HTTP 使用 Kerberos 身份验证,或者对于本地帐户通过 HTTPS 使用 Basic/NTLM。CredSSP 应仅在绝对必要时使用,因为它由于使用不受约束的委派而可能构成安全风险。
基本认证
基本认证是最简单的身份验证选项之一,但也是最不安全的。这是因为用户名和密码只是简单的base64编码,如果未使用安全通道(例如HTTPS),则任何人都可以对其进行解码。基本认证只能用于本地帐户(不能用于域帐户)。
以下示例显示为基本身份验证配置的主机变量
ansible_user: LocalUsername
ansible_password: Password
# psrp
ansible_connection: psrp
ansible_psrp_auth: basic
# winrm
ansible_connection: winrm
ansible_winrm_transport: basic
Windows主机上默认情况下未启用基本身份验证,但可以通过在PowerShell中运行以下命令来启用
Set-Item -Path WSMan:\localhost\Service\Auth\Basic -Value $true
证书认证
有关如何配置和使用证书身份验证的更多信息,请参见WinRM证书身份验证。
NTLM认证
NTLM是Microsoft使用的一种较旧的身份验证机制,它可以支持本地帐户和域帐户。WinRM服务默认启用NTLM,因此使用前无需任何设置。
NTLM是最容易使用的身份验证协议,并且比Basic
身份验证更安全。如果在域环境中运行,则应使用Kerberos
而不是NTLM。
Kerberos比使用NTLM具有多个优势
NTLM是一种较旧的协议,不支持较新的加密协议。
NTLM身份验证速度较慢,因为它在身份验证阶段需要与主机进行更多轮次往返。
与Kerberos不同,NTLM不允许凭据委派。
此示例显示配置为使用NTLM身份验证的主机变量
ansible_user: LocalUsername
ansible_password: Password
# psrp
ansible_connection: psrp
ansible_psrp_auth: negotiate # or ntlm to only use NTLM
# winrm
ansible_connection: winrm
ansible_winrm_transport: ntlm
Kerberos和Negotiate
在域环境中运行时,Kerberos是推荐使用的身份验证选项。Kerberos支持诸如凭据委派和HTTP上的消息加密等功能,并且是WinRM提供的更安全的选项之一。
Kerberos确实需要在Ansible主机上进行一些额外的设置工作才能正确使用。有关如何配置、使用和排除Kerberos身份验证问题的更多信息,请参见Kerberos身份验证。
以下示例显示为Kerberos身份验证配置的主机变量
ansible_user: [email protected]
ansible_password: Password
# psrp
ansible_connection: psrp
ansible_psrp_auth: negotiate # or kerberos to disable ntlm fallback
# winrm
ansible_connection: winrm
ansible_winrm_transport: kerberos
CredSSP
CredSSP身份验证是一种较新的身份验证协议,允许凭据委派。这是通过在身份验证成功后加密用户名和密码,并使用CredSSP协议将其发送到服务器来实现的。
由于用户名和密码被发送到服务器用于双跳身份验证,请确保Windows主机与之通信的主机没有被破坏并且是受信任的。
CredSSP可用于本地帐户和域帐户,并支持HTTP上的消息加密。
要使用CredSSP身份验证,主机变量配置如下
ansible_user: Username
ansible_password: Password
# psrp
ansible_connection: psrp
ansible_psrp_auth: credssp
# winrm
ansible_connection: winrm
ansible_winrm_transport: credssp
Windows主机上默认情况下未启用CredSSP身份验证,但可以通过在PowerShell中运行以下命令来启用
Enable-WSManCredSSP -Role Server -Force
CredSSP需要安装可选的Python库,可以使用pipx完成
pipx inject "pypsrp[credssp]<=1.0.0" # for psrp
pipx inject "pywinrm[credssp]>=0.4.0" # for winrm
或者,如果您选择 pip
安装说明:
pip3 install "pypsrp[credssp]<=1.0.0" # for psrp
pip3 install "pywinrm[credssp]>=0.4.0" # for winrm
CredSSP通过使用TLS连接来包装身份验证令牌和随后通过连接发送的消息来工作。默认情况下,它将使用Windows自动生成的自签名证书。虽然通过HTTPS连接使用CredSSP仍然需要验证WinRM侦听器使用的HTTPS证书,但对CredSSP证书没有进行验证。可以通过设置WinRM服务配置下的CertificateThumbprint
选项来配置CredSSP以使用不同的证书。
# Note the value $thumprint will be different in each situation, this needs
# to be set based on the cert that is used.
$thumbprint = "7C8DCBD5427AFEE6560F4AF524E325915F51172C"
# Set the thumbprint value
Set-Item -Path WSMan:\localhost\Service\CertificateThumbprint -Value $thumbprint
非管理员帐户
默认情况下,WinRM配置为仅允许来自本地Administrators
组中帐户的连接。可以通过运行以下命令来更改此设置
winrm configSDDL default
这将显示一个ACL编辑器,可以在其中添加新的用户或组。要通过WinRM运行命令,用户和组必须至少具有Read
和Execute
权限。
虽然可以使用非管理员帐户使用WinRM,但大多数典型的服务器管理任务都需要某种级别的管理员访问权限,因此其效用通常有限。
WinRM加密
默认情况下,WinRM在未加密的通道上运行时将无法工作。如果使用HTTP上的TLS(HTTPS)或使用消息级加密,则WinRM协议认为通道已加密。建议使用具有TLS的WinRM,因为它适用于所有身份验证选项,但需要创建证书并在WinRM侦听器上使用。
如果在域环境中,ADCS可以为由域本身颁发的宿主创建证书。
如果HTTPS不可用,则当身份验证选项为NTLM
、Kerberos
或CredSSP
时,可以使用HTTP。这些协议将在将其发送到服务器之前使用其自身的加密方法加密WinRM有效负载。在通过HTTPS运行时不使用消息级加密,因为加密使用更安全的TLS协议。如果需要传输和消息加密,则可以设置以下主机变量
# psrp
ansible_psrp_message_encryption: always
# winrm
ansible_winrm_message_encryption: always
注意
HTTP上的消息加密需要pywinrm>=0.3.0。
最后一种方法是在Windows主机上禁用加密要求。这仅应用于开发和调试目的,因为从Ansible发送的任何内容都可以被查看或操作,并且远程会话可以被同一网络上的任何人完全接管。要禁用加密要求
Set-Item -Path WSMan:\localhost\Service\AllowUnencrypted -Value $true
注意
除非绝对需要,否则不要禁用加密检查。这样做可能会允许其他人拦截网络上的敏感信息,例如凭据和文件。
HTTPS证书验证
作为TLS协议的一部分,证书验证以确保主机与主体匹配,并且客户端信任服务器证书的发行者。如果使用自签名证书,则客户端将不信任该证书,并且连接将失败。要绕过此问题,请根据使用的连接插件设置以下主机变量
ansible_psrp_cert_validation: ignore
ansible_winrm_server_cert_validation: ignore
在域环境中设置HTTPS侦听器的更常见方法之一是使用Active Directory证书服务(AD CS)。AD CS用于根据证书签名请求(CSR)生成签名证书。如果WinRM HTTPS侦听器使用由另一个机构(如AD CS)签名的证书,则可以将Ansible设置为在TLS握手过程中信任该发行者。
要使Ansible信任像AD CS这样的证书颁发机构(CA),可以将CA的发行者证书导出为PEM编码的证书。然后可以将此证书本地复制到Ansible控制节点,并用作证书验证的来源,也称为CA链。
CA链可以包含一个或多个发行者证书,并且每个条目都包含在新的一行中。然后,要将自定义CA链用作验证过程的一部分,请根据使用的连接插件将以下主机变量设置为CA PEM格式文件的路径
ansible_psrp_ca_cert
ansible_winrm_ca_trust_path
如果未设置此变量,则改为使用默认CA链,该链位于Python包certifi的安装路径中。某些Linux发行版可能已将psrp
和winrm
连接插件使用的底层Python requests
库配置为使用系统的证书存储区而不是certifi
。如果是这种情况,则CA链将与系统的证书存储区相同。
WinRM限制
由于WinRM协议的设计,在使用WinRM时存在一些限制,这些限制在为Ansible创建剧本时可能会导致问题。这些包括
对于大多数身份验证类型,凭据不会被委派,这会在访问网络资源或安装某些程序时导致身份验证错误。
通过WinRM运行时,对Windows Update API的许多调用都会被阻止。
由于没有凭据委派,或者因为它们访问禁止的Windows API(如通过WinRM的WUA),某些程序无法通过WinRM安装。
WinRM下的命令在非交互式会话中执行,这可能会阻止某些命令或可执行文件运行。
无法运行与
DPAPI
交互的进程,某些安装程序(如Microsoft SQL Server)使用此进程。
可以通过执行以下操作来减轻其中一些限制
将身份验证方法设置为使用
credssp
或kerberos
并启用凭据委派使用
become
绕过所有WinRM限制,并像在本地一样运行命令。与使用credssp
之类的身份验证传输不同,这还将删除非交互式限制和API限制,例如WUA和DPAPI使用计划任务运行命令,该命令可以使用
win_scheduled_task
模块创建。与become
类似,这绕过了所有 WinRM 限制,但只能运行命令,不能运行模块。
WinRM 故障排除
WinRM 具有广泛的配置选项,这使得其配置复杂。因此,Ansible 显示的错误实际上可能是主机设置问题。
要识别主机问题,请从另一台 Windows 主机运行以下命令以测试与目标 Windows 主机的连接。
测试 HTTP
# winrm
winrs -r:http://server:5985/wsman -u:Username -p:Password ipconfig
# psrp
Invoke-Command -ComputerName server { ipconfig } -Credential username
测试 HTTPS
# winrm
winrs -r:https://server:5986/wsman -u:Username -p:Password -ssl ipconfig
# psrp
Invoke-Command -UseSSL -ComputerName server { ipconfig } -Credential username
# psrp ignoring certs
$sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
Invoke-Command -UseSSL -ComputerName server { ipconfig } -Credential username -SessionOption $sessionOption
要验证目标主机名是否可以在 Ansible 控制节点上解析,请运行以下命令之一
dig +search server
# May fail if the Windows firewall is set to block ICMP pings
# but will show the hostname if resolvable.
ping server
要验证 WinRM 服务是否正在监听并且防火墙没有阻止连接,可以使用 nc
测试 WinRM 端口上的连接
# HTTP port
> nc -zv server 5985
Connection to server port 5985 [tcp/wsman] succeeded!
# HTTPS port
> nc -zv server 5986
Connection to server port 5986 [tcp/wsmans] succeeded!
要验证 WinRM 是否具有 HTTPS 侦听器并正在工作,可以使用 openssl s_client
测试连接并查看证书详细信息
echo '' | openssl s_client -connect server:5986
注意
openssl s_client
命令将使用系统信任库来验证证书,这可能与 Ansible 中使用的信任库不一致。有关更多信息,请参阅 HTTPS 证书验证。
另请参阅
- Ansible 剧本
剧本入门
- Ansible 提示和技巧
剧本技巧
- Windows 模块列表
Windows 特定模块列表,所有模块均在 PowerShell 中实现
- 沟通
有问题?需要帮助?想分享您的想法?请访问 Ansible 沟通指南