Design goals
- Every server patched within an agreed time after release (e.g. critical within 14 days, others within 30).
- No outage for highly available applications; known, approved windows for single-instance ones.
- Evidence for auditors without manual spreadsheets.
1. Rings
| Ring | Members | Timing (example, after Patch Tuesday) |
|---|---|---|
| Ring 0 | IT test servers, volunteers | Day 1–2 |
| Ring 1 | Dev/test environments | Day 3–5 |
| Ring 2 | Production, first half of each HA pair/cluster | Day 7–10 |
| Ring 3 | Production, second half | Day 10–14 |
| Exception | Systems with vendor restrictions | Scheduled per vendor |
Splitting HA pairs across rings is what avoids outages. Both nodes of a cluster must never be in the same window.
2. Tag to drive scope
patchRing = 0 | 1 | 2 | 3 | exception
patchWindow = sat-0200 | sun-0200 | wed-2200
rebootAllowed = true | false
Enforce tags with Azure Policy (also for Arc servers).
3. Maintenance configurations with dynamic scopes
- One maintenance configuration per ring/window combination (schedule, classifications, reboot setting).
- Dynamic scopes select machines by subscription, resource group, location, OS and tags, so new servers join automatically.
- Set patch orchestration on Azure VMs to Customer Managed Schedules so only your schedules patch them.
az maintenance configuration create -g rg-patch -n mc-ring2-sat0200 --location centralindia \
--maintenance-scope InGuestPatch --maintenance-window-duration "03:00" \
--maintenance-window-recur-every "Week Saturday" --maintenance-window-start-date-time "2026-11-07 02:00" \
--maintenance-window-time-zone "India Standard Time" \
--install-patches-windows-parameters classifications-to-include="Critical" "Security" "UpdateRollup" \
--install-patches-linux-parameters classifications-to-include="Critical" "Security" \
--reboot-setting IfRequired --extension-properties InGuestPatchMode="User"
Parameter names evolve between CLI versions. Check az maintenance configuration create --help.
4. Pre and post tasks
Use pre/post events (Event Grid → Automation runbook / Function) for:
- Draining a node from a load balancer or cluster role before patching; re-adding after.
- Stopping/starting application services in order.
- Taking a snapshot for high-risk systems.
- Health checks after reboot; alert if a service didn't come back.
5. Periodic assessment
Enable periodic assessment (every 24 h) by policy so compliance data stays current between windows. Report from Azure Resource Graph:
patchassessmentresources
| where type =~ "microsoft.compute/virtualmachines/patchassessmentresults"
or type =~ "microsoft.hybridcompute/machines/patchassessmentresults"
| extend critical = toint(properties.availablePatchCountByClassification.critical),
security = toint(properties.availablePatchCountByClassification.security),
lastAssessed = todatetime(properties.lastModifiedDateTime)
| project machine = tostring(split(id, "/")[8]), critical, security, lastAssessed
| where critical > 0 or security > 0
| order by critical desc
Publish per owner (join with tags), not one global percentage.
6. Exceptions
- Documented per server: reason, owner, compensating controls, expiry date.
- Typical: vendor-certified patch levels, legacy apps awaiting replacement.
- Review monthly; expired exceptions return to normal rings.
7. Emergency patching
For out-of-band critical vulnerabilities: a one-time update deployment to targeted machines, skipping rings with explicit approval, plus a faster reporting cycle until closed.
Warning
Patching without health checks only tells you the patch installed, not that the application works. The post-task health check is what turns a patch window into a safe change.
Checklist
- SLA per classification agreed
- Rings split HA pairs; tags enforced
- Maintenance configurations with dynamic scopes
- Pre/post tasks for clusters and services
- Periodic assessment and per-owner reporting
- Exception process with expiry; emergency path defined