用 Ansible 从 Linux 管理 Windows 服务器:WinRM 机制与认证取舍

用 Ansible 从 Linux 管理 Windows 服务器:WinRM 机制与认证取舍
乔阳管理多台 Windows 服务器时,通过远程桌面逐台登录执行重复配置,低效到让人难以忍受。Linux 那边有 SSH 配合脚本就能批量操作,Windows 长期以来缺少顺手的方案。Ansible 的 Windows 支持通过 WinRM 协议打通了这条路,控制机留在 Linux,被管机器不需要装 agent。
WinRM 是什么,为什么不用 SSH
Windows 没有 SSH(直到 Server 2019 才原生支持 OpenSSH),但自带了一套远程管理协议 WinRM(Windows Remote Management)。它是 WS-Management 标准的微软实现,基于 SOAP over HTTP,默认监听 5985(HTTP)和 5986(HTTPS)两个端口。Ansible 对 Windows 的支持就建立在 WinRM 之上。
和 Linux 那边 Ansible 通过 SSH 调 Python 模块不同,Windows 被管节点上不需要装 Ansible 客户端,也不需要 Python。Ansible 把模块代码通过 WinRM 推过去执行,依赖的是 Windows 内置的 PowerShell 远程能力。这是这套方案最大的好处:被管机器零侵入,WinRM 服务在 Vista / Server 2008 之后默认随系统存在,只需启用。
代价是协议层面比 SSH 重。WinRM 是 SOAP,每条消息都是 XML,传输效率和 SSH 比有明显差距,大批量文件传输或高频模块调用时会感觉出来。日常配置变更这种低频场景完全够用。
认证方式与传输层的选择
WinRM 的安全由两个独立维度决定:认证方式和传输层。两者可以组合,但有约束。
认证方式有几种,各有取舍:
- Basic:用户名密码,凭据以明文形式走 HTTP(需要服务端开启
AllowUnencrypted)。最简单,也最不安全,只适合内网测试。 - NTLM:Windows 原生挑战响应,不需要域,比 Basic 安全一些,但跨网段和某些受限场景下表现不稳定。
- Kerberos:域环境下的首选,需要控制机装
python-kerberos并配置krb5.conf,拿到票据后能单点登录多台机器。配置成本最高,体验也最好。 - CredSSP:凭据委派,用于需要二次跳转(从被管机再连第三台机器)的场景,配置较繁琐。
- Certificate:用客户端证书替代密码,适合做无密码化自动化,但证书签发和管理本身有成本。
传输层是 HTTP(5985,明文)或 HTTPS(5986,加密)。Basic 走 HTTP 必须显式开 AllowUnencrypted,否则服务端拒绝;走 HTTPS 则不需要。NTLM、Kerberos 自带加密协商,可以走 HTTP,但仍然建议外面套一层 HTTPS。
本文用 Basic + HTTP,是最简组合,也是最不安全的一个。选它的原因很简单:内网测试环境,机器少,先把链路打通。生产环境应该走 5986 + Kerberos 或 Certificate,不要在公网或半可信网络上跑 Basic。
控制节点配置(Linux 侧)
安装 Ansible
Ubuntu 上直接装:
1 | sudo apt-get update && sudo apt-get install ansible |
Ubuntu 仓库里的版本可能偏旧,需要新版本用 pip:
1 | pip3 install ansible |
主机清单
创建并编辑 /etc/ansible/hosts:
1 | sudo touch /etc/ansible/hosts |
1 | [windows_servers] |
几个关键参数:
ansible_connection=winrm:指定用 WinRM 而不是 SSH。ansible_winrm_transport=basic:认证方式选 Basic。ansible_winrm_server_cert_validation=ignore:忽略服务端证书校验。Basic over HTTP 本来就没证书,这个参数在切到 HTTPS 时才真正有意义,这里留着是为了将来切换时不踩坑。ansible_port=5985:WinRM 的 HTTP 端口。走 HTTPS 改成 5986。
凭据文件
把密码单独放 host_vars,避免明文写在清单里:
1 | sudo touch /etc/ansible/host_vars/win-host1.yml |
1 | ansible_user: test |
密码里有特殊字符(比如这里的 .)时,务必用引号包裹,否则 YAML 解析可能出问题。生产环境应该用 Ansible Vault 加密这个文件,明文只是演示。
配置完目录长这样:
1 | /etc/ansible |
被管节点配置(Windows 侧)
网络类型必须是”专用”
WinRM 服务对网络配置文件有要求,网络类型必须是”专用”或”域”,不能是”公用”。公用网络配置下 Windows 会拒绝接受 WinRM 连接,这是最常见的连不上的原因之一。
路径:设置 -> 网络和 Internet -> 以太网 -> 当前连接 -> 改为”专用网络”。
创建专用用户组
给 Ansible 单独建个组,方便后续按组授权,不要直接拿管理员账号跑:
- 计算机管理 -> 本地用户和组 -> 组
- 新建组
ansible - 把要远程管理的用户加进去
启用 WinRM
Ansible 官方在 GitHub 提供了一个 ConfigureRemotingForAnsible.ps1 脚本可以一键配好。但它会改不少东西,我倾向于手动执行关键命令,至少知道自己改了什么。
以管理员权限打开 PowerShell,依次执行:
1 | # 启用 WinRM 服务并做基础配置 |
AllowUnencrypted="true" 这一项很多人会漏。Basic 认证默认要求加密通道(HTTPS),走 HTTP 明文就必须显式打开这个开关,否则 Ansible 连接时会报 401 或加密相关错误。
命令执行结果参考:
看到监听器跑在 5985 端口,WinRM 就绪了。
连接测试
回到 Linux 控制节点:
1 | ansible windows_servers -m win_ping |
成功的话返回:
1 | win-host1 | SUCCESS => { |
win_ping 不是 ICMP ping,它走的是完整的 WinRM 认证和传输链路,返回 pong 说明整条路径都通。
加更多机器
首台通了之后,扩容就是重复劳动。
主机清单加几行:
1 | [windows_servers] |
每台机器在 host_vars/ 下建一个凭据文件:
1 | sudo touch /etc/ansible/host_vars/win-host2.yml |
1 | # win-host2.yml |
每台 Windows 机器上把”网络类型改专用、建 ansible 组、跑那段 PowerShell”重复一遍。批量验证:
1 | ansible windows_servers -m win_ping |
1 | win-host1 | SUCCESS => { "changed": false, "ping": "pong" } |
到这步就能用 Ansible 统一管理所有 Windows 服务器了。
踩过的坑
Windows LTSC / Home 版本不可用。 LTSC 功能精简过度,部分 Ansible 模块跑不起来;Home 版本干脆没有 WinRM 服务。要用 Server 版,或者专业版 / 企业版。这是选机器时就得确认的前提,不是配置能解决的。
win_ping 连接超时。 优先排查三件事:Linux 能不能 ping 通 Windows;5985 端口防火墙有没有放行(本地防火墙和网络设备都要看);WinRM 服务和监听器是否正常,在 Windows 上跑 winrm e winrm/config/listener 确认。
认证失败 401。 多半是用户没加进 Remote Management Users 组,或者 Basic 认证没开。验证方式:winrm get winrm/config/service/auth,看 Basic = true。密码里有特殊字符一定要加引号。
网络类型不匹配。 公用网络下 WinRM 直接拒绝连接,改回专用或域。
关于安全的实话
这套配置是 Basic + HTTP + 明文,凭据在网络上是可以被抓到的。我用在完全隔离的内网测试环境,机器之间可信。环境如果不是这样,不要照搬:
- 公网或半可信网络,必须走 5986(HTTPS),用正式证书或者自签证书配合
ansible_winrm_server_cert_validation=ignore。 - 域环境优先上 Kerberos,一次票据拿到多台机器,体验比 Basic 好太多,也不用在每台机器上单独配密码。
- 凭据文件用 Ansible Vault 加密,别明文躺着。
- 定期轮换密码,哪怕在内网。
把链路打通是第一步,把链路做安全是第二步,两步不能省第二步。















