CentOS 7停服后,很多团队把跳板机或Ansible控制节点迁移到了Rocky Linux或Ubuntu上。迁移本身不复杂,但真正的麻烦在于,原本通过PowerShell远程管理的Windows补丁流程,现在需要无缝接入新的Ansible环境。直接解决问题的方法就是:在Linux控制节点上配置Kerberos认证,通过WinRM协议打通Ansible与Windows Server的连接,然后编写Playbook实现补丁扫描、下载、安装和重启的全自动化编排。

环境现状与认证准备

迁移后的控制节点通常是Rocky Linux 8/9或Ubuntu 22.04/24.04。Windows服务器端需要启用WinRM服务,并且配置为支持CredSSP或Kerberos认证。如果你的环境有Active Directory域,强烈建议使用Kerberos,因为这种认证方式支持双跳,在补丁安装过程中如果需要从文件服务器获取更新包,不会出现权限问题。

先在Windows服务器上确认WinRM状态。在PowerShell中执行以下命令快速配置:

Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true
Set-Item WSMan:\localhost\Service\Auth\CredSSP -Value $true

生产环境不建议使用Basic认证,这里只是为了快速验证。实际部署时,应当配置HTTPS监听器,并使用AD域账号进行Kerberos认证。

Linux控制节点的Kerberos配置

在Rocky Linux上安装必要的包:

dnf install -y python3 python3-pip krb5-workstation krb5-devel
pip3 install pywinrm[kerberos]
pip3 install ansible

配置/etc/krb5.conf文件,指向你的域控制器:

[libdefaults]
    default_realm = YOURDOMAIN.COM
    dns_lookup_realm = true
    dns_lookup_kdc = true
    ticket_lifetime = 24h
    renew_lifetime = 7d
    forwardable = true

[realms]
    YOURDOMAIN.COM = {
        kdc = dc01.yourdomain.com
        admin_server = dc01.yourdomain.com
    }

[domain_realm]
    .yourdomain.com = YOURDOMAIN.COM
    yourdomain.com = YOURDOMAIN.COM

验证Kerberos是否正常工作,使用kinit获取票据:

kinit administrator@YOURDOMAIN.COM
klist

看到票据信息就说明认证通道已经建立。这一步是整个方案的基础,很多人在迁移后遇到“401 Unauthorized”错误,根本原因就是Kerberos配置不完整,或者时间不同步导致票据验证失败。务必确保所有服务器的时间差不超过5分钟,建议统一使用NTP服务。

Ansible Inventory与WinRM连接配置

在Ansible的hosts文件中定义Windows服务器组:

[windows_servers]
win-srv-01 ansible_host=192.168.1.101
win-srv-02 ansible_host=192.168.1.102

[windows_servers:vars]
ansible_user = administrator@YOURDOMAIN.COM
ansible_connection = winrm
ansible_winrm_transport = kerberos
ansible_winrm_server_cert_validation = ignore
ansible_port = 5986
ansible_winrm_scheme = https

这里有一个关键点:ansible_winrm_transport设置为kerberos后,Ansible会使用之前kinit获取的票据进行认证,不再需要明文密码。如果控制节点重启或票据过期,需要重新执行kinit。可以通过crontab定时执行kinit -R来续期票据,或者使用keytab文件实现无人工干预的自动认证。

补丁管理Playbook设计思路

Windows补丁管理不像Linux那样简单地yum update就能解决。需要考虑几个维度:补丁分类(安全更新、关键更新、功能更新)、安装时间窗口、重启策略、以及失败回滚机制。Ansible提供了win_updates模块,但这个模块在早期版本中存在超时和卡死的问题,目前Ansible 2.14以上版本已经比较稳定。

一个生产级别的补丁更新Playbook应该包含以下阶段:

- name: Windows补丁自动化管理
  hosts: windows_servers
  gather_facts: yes
  strategy: free
  serial: 1

  tasks:
    - name: 检查可用更新
      ansible.windows.win_updates:
        category_names:
          - SecurityUpdates
          - CriticalUpdates
        state: searched
      register: available_updates

    - name: 显示可用更新数量
      ansible.builtin.debug:
        msg: "发现 {{ available_updates.updates | length }} 个可用更新"

    - name: 下载并安装更新
      ansible.windows.win_updates:
        category_names:
          - SecurityUpdates
          - CriticalUpdates
        state: installed
        reboot: false
        log_path: C:\ansible_wu_log.txt
      register: update_result
      when: available_updates.updates | length > 0

    - name: 检查是否需要重启
      ansible.windows.win_reboot:
        reboot_timeout: 1800
        post_reboot_delay: 120
      when: update_result.reboot_required

使用serial: 1确保一次只操作一台服务器,避免批量重启导致服务中断。strategy: free让每台服务器独立执行任务,不会因为某台服务器卡住而阻塞整个流程。

处理补丁安装的常见坑

win_updates模块底层调用Windows Update API,这个API本身就很慢,而且容易卡在下载阶段。如果服务器长时间没有更新,第一次扫描可能需要30分钟以上。解决方案是在任务上设置合理的超时时间,并且使用async异步执行:

- name: 异步安装更新
  ansible.windows.win_updates:
    category_names: "{{ update_categories }}"
    state: installed
    reboot: false
  async: 7200
  poll: 30
  register: async_update

另一个常见问题是某些更新需要前置依赖,单独安装会失败。win_updates模块会自动处理依赖关系,但如果遇到反复失败的更新,建议先在测试环境手动排查,确认是否是微软已知问题。可以在Playbook中添加白名单或黑名单机制,跳过特定KB编号的更新:

- name: 安装更新但排除特定KB
  ansible.windows.win_updates:
    category_names:
      - SecurityUpdates
    reject_list:
      - KB5009557
    state: installed
补丁合规性报告与审计

运维团队需要知道哪些服务器安装了哪些补丁,哪些存在风险敞口。可以编写一个专门的扫描Playbook,定期生成补丁合规报告:

- name: 补丁合规性扫描
  hosts: windows_servers
  gather_facts: yes
  tasks:
    - name: 获取已安装更新列表
      ansible.windows.win_shell: |
        Get-HotFix | Select-Object HotFixID,InstalledOn,InstalledBy | ConvertTo-Json
      register: installed_hotfixes

    - name: 获取缺失的安全更新
      ansible.windows.win_updates:
        category_names:
          - SecurityUpdates
          - CriticalUpdates
        state: searched
      register: missing_updates

    - name: 生成报告
      ansible.builtin.copy:
        content: |
          服务器: {{ inventory_hostname }}
          已安装补丁数: {{ (installed_hotfixes.stdout | from_json) | length }}
          缺失安全更新数: {{ missing_updates.updates | length }}
          缺失更新列表:
          {% for update in missing_updates.updates %}
          - {{ update.title }} ({{ update.kb | join(', ') }})
          {% endfor %}
        dest: /var/reports/{{ inventory_hostname }}_patch_report.txt
      delegate_to: localhost

这份报告可以接入现有的监控系统或发送到企业微信、钉钉等通知渠道。关键是形成闭环:扫描、安装、验证、报告,四个环节缺一不可。

多台Windows服务器的分组策略

生产环境中不可能一次性把所有服务器都更新,需要按照业务角色分组,分批次执行。可以在Inventory中定义不同的组和变量:

[web_servers]
web-01 ansible_host=10.0.1.11
web-02 ansible_host=10.0.1.12

[db_servers]
db-01 ansible_host=10.0.2.21
db-02 ansible_host=10.0.2.22

[all_windows:children]
web_servers
db_servers

[web_servers:vars]
maintenance_window = "03:00-05:00"
reboot_allowed = true

[db_servers:vars]
maintenance_window = "01:00-03:00"
reboot_allowed = false

结合Ansible的when条件判断,可以在Playbook中实现只在维护窗口内执行更新,或者对数据库服务器只下载不安装,等人工确认后再执行重启。这种灵活性是传统WSUS或SCCM难以快速实现的。

利用Ansible Roles组织代码

当Playbook越来越复杂,建议使用Roles来组织代码结构。创建一个名为windows_patch_management的Role:

roles/windows_patch_management/
├── defaults
│   └── main.yml
├── tasks
│   ├── main.yml
│   ├── scan.yml
│   ├── install.yml
│   └── report.yml
├── handlers
│   └── main.yml
├── templates
│   └── report.j2
└── vars
    └── main.yml

defaults/main.yml定义默认变量,比如更新类别、重启超时时间、日志路径等。vars/main.yml存放具体环境的值。tasks按功能拆分成scan、install、report三个文件,main.yml中通过include_tasks按需调用。这样结构清晰,新同事接手也能快速理解。

补丁回滚与异常处理

不是每次更新都一帆风顺。Windows补丁偶尔会导致应用异常,这时候需要快速回滚。Ansible可以调用win_shell执行卸载命令:

- name: 卸载指定补丁
  ansible.windows.win_shell: |
    $patch = Get-HotFix -Id "{{ kb_number }}"
    if ($patch) {
        wusa /uninstall /kb:{{ kb_number }} /quiet /norestart
    }
  args:
    executable: powershell.exe
  register: uninstall_result
  ignore_errors: yes

更稳妥的做法是在安装补丁前创建系统还原点,或者在虚拟化环境中提前打快照。Ansible可以调用VMware或Hyper-V的模块在更新前自动创建快照,更新验证通过后再删除。这套组合拳下来,补丁管理的风险就降到了最低。

持续优化与自动化调度

把所有Playbook接入AWX或Ansible Tower,设置定时任务,比如每月第二个周三凌晨执行安全更新。利用AWX的Survey功能,让运维人员在执行前选择更新类别、目标服务器组、是否允许重启,既保证了标准化,又保留了灵活性。

监控方面,可以把补丁安装结果通过回调插件发送到Prometheus或ELK,建立仪表盘展示各服务器的补丁状态。当发现某台服务器连续多次更新失败,自动创建工单通知对应负责人。从CentOS迁移到新平台后,这套基于Ansible的Windows补丁管理体系不仅没有中断,反而因为统一了Linux和Windows的自动化工具,运维效率有了明显提升。

整个方案的核心在于:Kerberos认证是基础,WinRM是通道,win_updates模块是执行器,Roles是组织方式,AWX是调度中枢。把这五个环节理顺,Windows服务器的补丁管理就能真正实现无人值守。