executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
implementing-patch-management-workflow补丁管理(Patch Management)是识别、测试、部署和验证软件更新以修复组织 IT 基础设施漏洞的系统化流程。有效的补丁管理工作流通过结构化测试、审批门禁和分阶段发布,在降低攻击面的同时将运营中断降至最低。
Independent GitHub snapshot · Automated classification · Original documentation governs
补丁管理(Patch Management)是识别、测试、部署和验证软件更新以修复组织 IT 基础设施漏洞的系统化流程。有效的补丁管理工作流通过结构化测试、审批门禁和分阶段发布,在降低攻击面的同时将运营中断降至最低。
| 环 | 环境 | 机器比例 | 驻留时间 | 目的 |
|---|---|---|---|---|
| 环 0 | 实验室/测试 | N/A | 24-48 小时 | 功能验证 |
| 环 1 | IT 早期采用者 | 5% | 48-72 小时 | 真实环境试点 |
| 环 2 | 业务试点 | 15% | 5-7 天 | 更广泛的兼容性 |
| 环 3 | 通用部署 | 50% | 7-14 天 | 主要发布 |
| 环 4 | 关键任务 | 30% | 环 3 之后 | 最终部署 |
# WSUS(Windows Server Update Services)
# 配置 WSUS 服务器与 Microsoft Update 同步
# 在 WSUS 服务器上通过 PowerShell 执行:
Install-WindowsFeature -Name UpdateServices -IncludeManagementTools
& "C:\Program Files\Update Services\Tools\WsusUtil.exe" postinstall CONTENT_DIR=D:\WSUS
# 为 WSUS 客户端配置 GPO
# 计算机配置 > 管理模板 > Windows 组件 > Windows Update
# 指定 Intranet Microsoft 更新服务位置:http://wsus-server:8530
# Ansible:为 Linux 配置补丁仓库
# roles/patch-management/tasks/configure_repos.yml
---
- name: 配置 RHEL 补丁仓库
yum_repository:
name: rhel-patches
description: RHEL Security Patches
baseurl: https://satellite.corp.local/pulp/repos/patches
gpgcheck: yes
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
enabled: yes
- name: 配置 Ubuntu 补丁源
apt_repository:
repo: "deb https://apt-mirror.corp.local/ubuntu {{ ansible_distribution_release }}-security main"
state: present
when: ansible_os_family == "Debian"
# patch_assessment.py - 将漏洞扫描与可用补丁关联
import subprocess
import platform
import json
def get_windows_pending_patches():
"""通过 PowerShell 查询 Windows Update 的待安装补丁。"""
ps_cmd = """
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$Results = $Searcher.Search("IsInstalled=0 AND Type='Software'")
$Results.Updates | ForEach-Object {
[PSCustomObject]@{
Title = $_.Title
KB = ($_.KBArticleIDs -join ',')
Severity = $_.MsrcSeverity
Size = [math]::Round($_.MaxDownloadSize / 1MB, 2)
Published = $_.LastDeploymentChangeTime.ToString('yyyy-MM-dd')
CVE = ($_.CveIDs -join ',')
}
} | ConvertTo-Json
"""
result = subprocess.run(
["powershell", "-Command", ps_cmd],
capture_output=True, text=True, timeout=120
)
return json.loads(result.stdout) if result.stdout.strip() else []
def get_linux_pending_patches():
"""查询包管理器获取可用安全更新。"""
if platform.system() != "Linux":
return []
# 尝试 apt(Debian/Ubuntu)
try:
result = subprocess.run(
["apt", "list", "--upgradable"],
capture_output=True, text=True, timeout=60
)
packages = []
for line in result.stdout.strip().split("\n")[1:]:
if line:
parts = line.split("/")
packages.append({
"package": parts[0],
"available_version": parts[1].split()[0] if len(parts) > 1 else "",
"source": "apt"
})
return packages
except FileNotFoundError:
pass
# 尝试 yum/dnf(RHEL/CentOS)
try:
result = subprocess.run(
["dnf", "updateinfo", "list", "security", "--available"],
capture_output=True, text=True, timeout=60
)
packages = []
for line in result.stdout.strip().split("\n"):
parts = line.split()
if len(parts) >= 3:
packages.append({
"advisory": parts[0],
"severity": parts[1],
"package": parts[2],
"source": "dnf"
})
return packages
except FileNotFoundError:
return []
# Ansible playbook:test_patches.yml
---
- name: 在实验室环境测试补丁
hosts: test_servers
become: yes
vars:
rollback_snapshot: "pre-patch-{{ ansible_date_time.date }}"
tasks:
- name: 打补丁前创建 VM 快照
community.vmware.vmware_guest_snapshot:
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
datacenter: "{{ datacenter }}"
name: "{{ inventory_hostname }}"
snapshot_name: "{{ rollback_snapshot }}"
state: present
delegate_to: localhost
- name: 应用安全补丁(RHEL/CentOS)
dnf:
name: "*"
state: latest
security: yes
update_cache: yes
when: ansible_os_family == "RedHat"
register: patch_result
- name: 应用安全补丁(Ubuntu/Debian)
apt:
upgrade: dist
update_cache: yes
only_upgrade: yes
when: ansible_os_family == "Debian"
register: patch_result
- name: 如需则重启
reboot:
reboot_timeout: 600
msg: "正在重启以安装补丁"
when: patch_result.changed
- name: 执行补丁后验证
include_tasks: validate_services.yml
- name: 报告补丁结果
debug:
msg: "{{ inventory_hostname }} 打补丁{{ '成功' if patch_result.changed else '无更新' }}"
# deploy_patches.yml - 分阶段生产发布
---
- name: 环 1 - IT 早期采用者
hosts: ring1_hosts
serial: "25%"
max_fail_percentage: 10
become: yes
tasks:
- import_tasks: apply_patches.yml
- import_tasks: validate_services.yml
- name: 等待驻留期
pause:
hours: 48
run_once: true
- name: 环 2 - 业务试点
hosts: ring2_hosts
serial: "20%"
max_fail_percentage: 5
become: yes
tasks:
- import_tasks: apply_patches.yml
- import_tasks: validate_services.yml
- name: 环 3 - 通用部署
hosts: ring3_hosts
serial: "10%"
max_fail_percentage: 3
become: yes
tasks:
- import_tasks: apply_patches.yml
- import_tasks: validate_services.yml
打补丁后运行漏洞扫描以确认补丁安装情况:
# 触发补丁后验证扫描
curl -k -X POST "https://nessus:8834/scans/$VERIFY_SCAN_ID/launch" \
-H "X-Cookie: token=$TOKEN"
# 对比补丁前后结果
# 期望与已部署补丁匹配的漏洞数量减少
| 严重程度 | SLA(互联网可达) | SLA(内部) | SLA(气隙) |
|---|---|---|---|
| 严重(CVSS 9+) | 48 小时 | 7 天 | 14 天 |
| 高(CVSS 7-8.9) | 7 天 | 14 天 | 30 天 |
| 中(CVSS 4-6.9) | 30 天 | 30 天 | 60 天 |
| 低(CVSS 0.1-3.9) | 90 天 | 90 天 | 90 天 |