This modules is used to create and manage a Maintenance Configuration which is a supporting service of Azure Update Manager.
For information on how to consume this module, consult the examples directory.
The maintenance configuration already used AzAPI in v0.1.0. This upgrade renames its Terraform address and migrates the AzureRM lock and role assignments to AzAPI at the same module and collection boundaries. Existing consumer module keys and role assignment map keys must stay unchanged.
Use Terraform >= 1.9, < 2.0 and AzAPI ~> 2.12. Replace the module's
resource_group_name argument with the existing resource group's fully-qualified
parent_id, for example:
parent_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example"Remove the optional subscription_id argument if configured; the subscription is
now derived from parent_id.
The name and resource_id outputs retain their existing meanings and types.
The new timeouts object has flat create, read, update, and delete fields
and defaults to provider timeouts. Non-empty ignore_body_changes lists require
Terraform 1.11 or later; the default empty lists do not.
The module owns these declarative moves. Do not copy them into the consumer or
run terraform state mv for the standard upgrade:
| Released address (relative to the consumer module) | New address | Mechanism |
|---|---|---|
azapi_resource.maintenance_configuration |
azapi_resource.this |
Same-provider move |
azurerm_management_lock.this[0] |
azapi_resource.lock[0] |
Provider state conversion |
azurerm_role_assignment.this["key"] |
azapi_resource.role_assignments["key"] |
Provider state conversion, preserving each key and existing assignment GUID |
modtm_telemetry.telemetry and random_uuid.telemetry |
No replacement state binding | Managed telemetry removed blocks with destroy = false |
There are no inline ARM children to import and no avm_managed_migration_enabled
flag for the standard upgrade. Leave unrelated configuration unchanged during
the migration.
-
Back up state securely outside version control and record the existing ARM resource IDs, role assignment GUIDs, lock name and notes. Keep the original AzureRM provider configuration (including
features {}) available through the upgrade apply. Retain the old modtm and random providers for initialization while state still refers to the old telemetry resources. -
Remove any
ReadOnlylock before upgrading: it blocks the reconciliation PUT. Setlock = nulland apply using the previous module version first, then upgrade with the lock still disabled. Restore it in a separate apply after the upgrade. ACanNotDeletelock may remain configured. -
Change the module source/version and
parent_id, retaining the same resource group, name, location, scope, role assignment keys and other settings. -
Initialize and save a plan:
terraform init -upgrade terraform plan -out=migration.tfplan terraform show -json migration.tfplan > migration.plan.json
-
Inspect all moves, output changes and actions before applying. Do not apply a plan that deletes or replaces the maintenance configuration, lock or role assignments. In-place reconciliation is possible. New random UUID state inside the interface utility does not replace existing assignment GUIDs. A lock-removal timer is created only when a lock is configured.
-
Apply the inspected saved plan with
terraform apply migration.tfplan. Check that the resource IDs, assignment GUIDs and lock details are unchanged, then run another plan to establish convergence. Remove obsolete provider configurations only after their state references are gone.
Current managed telemetry creates empty subscription-scoped Azure deployments
when enabled, including in the interface utility. The deployment identity needs
Microsoft.Resources/deployments/read, write, and delete at the active
subscription scope. Telemetry intentionally updates only its
body.properties.template.outputs.apply_id.value timestamp on each normal plan.
With enable_telemetry = false, require a completely empty follow-up plan; with
telemetry enabled, require no infrastructure drift beyond those exact deployment
timestamps. The opt-out is forwarded to the utility.
This exception applies only to assignments with a composite ID in AzureRM state. Ordinary assignment IDs use the automatic moves above and do not need state removal or consumer-root imports.
AzureRM can store a cross-tenant assignment ID as <ARM-ID>|<tenant-ID>.
AzAPI's provider move does not strip that suffix, so this case is not covered
by the automatic move. Before planning the candidate, back up state, obtain the
existing assignment's ARM ID and GUID, and remove only its old binding:
terraform state rm 'module.maintenance.azurerm_role_assignment.this["delegated"]'In the consumer root, add an import targeting the corresponding new address:
import {
to = module.maintenance.azapi_resource.role_assignments["delegated"]
id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example/providers/Microsoft.Maintenance/maintenanceConfigurations/example/providers/Microsoft.Authorization/roleAssignments/11111111-1111-1111-1111-111111111111"
}Use the actual consumer module path, including any module instance keys, and the actual existing ARM ID without the tenant suffix. Preserve the original assignment inputs and provider tenant context. Inspect and apply the saved import plan, verify the GUID and delegated identity, then remove the root import block. Never remove a binding without its matching import. This exceptional procedure requires separate state-backed verification in the consumer's tenant context.
Lock names and default notes are preserved. Lock deletion waits 30 seconds before
deleting covered resources, including role assignments, when the lock is being
removed. This teardown ordering does not automatically remove an unchanged lock
for a role-assignment-only replacement. Role definition names are
resolved case-insensitively at the existing resource group; tenant-level definition
IDs are subscription-qualified. skip_service_principal_aad_check = true supplies
principalType = "ServicePrincipal" unless an explicit principal type overrides it.
Changing immutable assignment inputs still requires replacement; perform such
changes separately from the upgrade. The name input controls new assignments;
an adopted assignment retains its GUID, and a later explicit name change triggers
replacement.
Do not combine the state migration with intentional assignment replacement. After completing the upgrade, use separate applies for changes to immutable assignment inputs when a module-owned lock is configured:
- Keep the assignment inputs unchanged, set
lock = null, and apply a reviewed plan that removes only the lock and its associated timer. Confirm the lock is absent before continuing. - Change the assignment inputs, inspect the planned replacement and its permission impact, then apply that separately reviewed plan.
- Restore the original lock input and apply a final reviewed plan.
This is a staged operational procedure, not automatic lock orchestration.
The combined lock-removal, assignment-replacement and lock-restoration sequence
has not been state-backed verified for this migration candidate. Neither has the
ReadOnly remove-and-restore upgrade exception. Verify these exceptional paths
in an isolated consumer environment before using them in production; successful
unchanged-input migration and full teardown do not prove either sequence.
Do not assume reverting the module version rolls back converted provider state. After an apply, recovery requires reconciling both state and Azure, using the protected backup and verified live identities. A saved state alone does not undo Azure mutations.
The following requirements are needed by this module:
The following resources are used by this module:
- azapi_resource.lock (resource)
- azapi_resource.role_assignments (resource)
- azapi_resource.telemetry (resource)
- azapi_resource.this (resource)
- terraform_data.telemetry (resource)
- time_sleep.wait_for_resource_destroy (resource)
- azapi_client_config.telemetry (data source)
- azapi_resource_list.role_definitions (data source)
The following input variables are required:
Description: (Required) Azure region where the resource should be deployed.
Type: string
Description: (Required) The name of the this resource.
Type: string
Description: The Azure resource ID of the parent resource group, in the form /subscriptions/{subscription_id}/resourceGroups/{resource_group_name}.
Type: string
Description: (Required) The scope of the Maintenance Configuration. Possible values are Extension, Host, InGuestPatch, OSImage, SQLDB or SQLManagedInstance.
Type: string
The following input variables are optional (have default values):
Description: This variable controls whether or not telemetry is enabled for the module.
For more information see https://aka.ms/avm/telemetryinfo.
If it is set to false, then no telemetry will be collected.
Type: bool
Default: true
Description: (Optional) The extension properties of the Maintenance Configuration. Must be specified when scope is Extension.
Type: map(string)
Default: {}
Description: Body-relative paths to ignore for each AzAPI resource, using dot notation. Ignored configuration is not sent to Azure until the path is removed. Changes take effect only after apply. Non-empty lists require Terraform 1.11 or later.
authorization_locks- Paths ignored on management locks.authorization_role_assignments- Paths ignored on role assignments.maintenance_maintenance_configurations- Paths ignored on the maintenance configuration.
Type:
object({
authorization_locks = optional(list(string), [])
authorization_role_assignments = optional(list(string), [])
maintenance_maintenance_configurations = optional(list(string), [])
})Default: {}
Description: (Optional) The install patches of the Maintenance Configuration. Must be specified when scope is InGuestPatch.
linux- (Optional) The Linux parameters of the Maintenance Configuration. This property only applies when scope is set to InGuestPatch.classifications_to_include- (Optional) The classifications to include. Defaults to Critical & Securitypackage_name_masks_to_exclude- (Optional) The package name masks to exclude.package_name_masks_to_include- (Optional) The package name masks to include.
reboot_setting- (Optional) Possible reboot preference as defined by the user based on which it would be decided to reboot the machine or not after the patch operation is completed. Possible values are Always, IfRequired and Never. This property only applies when scope is set to InGuestPatch.windows- (Optional) The Windows parameters of the Maintenance Configuration. This property only applies when scope is set to InGuestPatch.classifications_to_include- (Optional) List of Classification category of patches to be patched. Possible values are Critical, Security, UpdateRollup, FeaturePack, ServicePack, Definition, Tools and Updates. Defaults to Critical & Securityexclude_kbs_requiring_reboot- (Optional) The exclude Kbs requiring reboot.kb_numbers_to_exclude- (Optional) The KB numbers to exclude.kb_numbers_to_include- (Optional) The KB numbers to include.
Type:
object({
linux = optional(object({
classifications_to_include = optional(list(string), ["Critical", "Security"])
package_name_masks_to_exclude = optional(list(string), [])
package_name_masks_to_include = optional(list(string), [])
}))
reboot_setting = optional(string)
windows = optional(object({
classifications_to_include = optional(list(string), ["Critical", "Security"])
exclude_kbs_requiring_reboot = optional(bool)
kb_numbers_to_exclude = optional(list(string), [])
kb_numbers_to_include = optional(list(string), [])
}))
})Default: {}
Description: Controls the Resource Lock configuration for this resource. The following properties can be specified:
kind- (Required) The type of lock. Possible values are\"CanNotDelete\"and\"ReadOnly\".name- (Optional) The name of the lock. If not specified, a name will be generated based on thekindvalue. Changing this forces the creation of a new resource.notes- (Optional) Notes about the lock. This value maps toMicrosoft.Authorization/locks.properties.notes.
Type:
object({
kind = string
name = optional(string, null)
notes = optional(string, null)
})Default: null
Description: AzAPI resource types and API versions used by this module.
authorization_locks- Resource type and API version for management locks.authorization_role_assignments- Resource type and API version for role assignments.maintenance_maintenance_configurations- Resource type and API version for the maintenance configuration.
Type:
object({
authorization_locks = optional(string, "Microsoft.Authorization/locks@2020-05-01")
authorization_role_assignments = optional(string, "Microsoft.Authorization/roleAssignments@2022-04-01")
maintenance_maintenance_configurations = optional(string, "Microsoft.Maintenance/maintenanceConfigurations@2023-04-01")
})Default: {}
Description: Retry configuration applied to every supported AzAPI resource declared by the module.
error_message_regex- Error patterns triggering a retry. Defaults toReferencedResourceNotProvisioned.interval_seconds- Initial interval in seconds. Defaults to 10.max_interval_seconds- Maximum interval in seconds. Defaults to 180.
Type:
object({
error_message_regex = optional(list(string), ["ReferencedResourceNotProvisioned"])
interval_seconds = optional(number, 10)
max_interval_seconds = optional(number, 180)
})Default: {}
Description: A map of role assignments to create on the maintenance configuration. The map key is deliberately arbitrary to avoid issues where map keys maybe unknown at plan time.
name- (Optional) The name of the role assignment. If not set, a random UUID will be generated. Changing this forces the creation of a new resource.role_definition_id_or_name- The ID or name of the role definition to assign to the principal.principal_id- The ID of the principal to assign the role to.description- (Optional) The description of the role assignment.skip_service_principal_aad_check- (Optional) If set to true, skips the Azure Active Directory check for the service principal in the tenant. Defaults to false.condition- (Optional) The condition which will be used to scope the role assignment.condition_version- (Optional) The version of the condition syntax. Leave asnullif you are not using a condition, if you are then valid values are '2.0'.delegated_managed_identity_resource_id- (Optional) The delegated Azure Resource Id which contains a Managed Identity. Changing this forces a new resource to be created. This field is only used in cross-tenant scenario.principal_type- (Optional) The type of theprincipal_id. Possible values areUser,GroupandServicePrincipal. It is necessary to explicitly set this attribute when creating role assignments if the principal creating the assignment is constrained by ABAC rules that filters on the PrincipalType attribute.
Note: only set
skip_service_principal_aad_checkto true if you are assigning a role to a service principal.
Type:
map(object({
name = optional(string, null)
role_definition_id_or_name = string
principal_id = string
description = optional(string, null)
skip_service_principal_aad_check = optional(bool, false)
condition = optional(string, null)
condition_version = optional(string, null)
delegated_managed_identity_resource_id = optional(string, null)
principal_type = optional(string, null)
}))Default: {}
Description: (Optional) Tags of the resource.
Type: map(string)
Default: null
Description: Per-operation timeouts applied to every supported AzAPI resource declared by the module. Defaults to null (provider defaults). Each value is a Go duration string, for example 30m.
create- Timeout for create operations.read- Timeout for read operations.update- Timeout for update operations.delete- Timeout for delete operations.
Type:
object({
create = optional(string)
read = optional(string)
update = optional(string)
delete = optional(string)
})Default: null
Description: (Optional) The visibility of the Maintenance Configuration. The only allowable value is Custom. Defaults to Custom.
Type: string
Default: "Custom"
Description: (Optional) The maintenance window of the Maintenance Configuration.
duration- (Optional) The duration of the maintenance window in HH:mm format. Defaults to 01:30expiration_date_time- (Optional) Effective expiration date of the maintenance window in YYYY-MM-DD hh:mm format.recur_every- (Required) The rate at which a maintenance window is expected to recur. The rate can be expressed as daily, weekly, or monthly schedules.start_date_time- (Required) Effective start date of the maintenance window in YYYY-MM-DD hh:mm format.time_zone- (Required) The time zone for the maintenance window. A list of timezones can be obtained by executing [System.TimeZoneInfo]::GetSystemTimeZones() in PowerShell.
Type:
object({
duration = optional(string, "01:30")
expiration_date_time = optional(string)
recur_every = string
start_date_time = string
time_zone = string
})Default: null
The following outputs are exported:
Description: The name of the Maintenance Configuration resource.
Description: The ID of the Maintenance Configuration resource.
The following Modules are called:
Source: Azure/avm-utl-interfaces/azure
Version: 0.9.0
The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.