> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Setup Alerts for Power Off Virtual Machine Events

### More Info:

Ensure that a Microsoft Azure activity log alert is fired whenever a 'Power Off Virtual Machine' event is triggered within your cloud account. An Azure activity log alert fires each time the action event that matches the condition defined in the alert configuration is triggered. The alert condition that this conformity rule checks for is `Whenever the Administrative Activity Log 'Power Off Virtual Machine (Microsoft.Compute/virtualMachines)' has 'any' level, with 'any' status and event is initiated by 'any'`

### Risk Level

High

### Address

Security

### Compliance Standards

CBP, CIS Microsoft Azure Foundations

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        Below are step‑by‑step instructions to set up alerts for VM power‑off events in Azure using the portal. This uses Activity Log alerts, which are the most reliable way to capture “Power off” operations.

        ***

        ## 1. Identify the Event You Want to Alert On

        Azure records VM power operations in the Activity log with operations like:

        * `Power off virtual machine`
        * `Deallocate virtual machine`
        * (and their “Succeeded” status)

        You’ll create an **Activity log alert** on these operations.

        ***

        ## 2. Go to Azure Monitor

        1. Sign in to the [Azure portal](https://portal.azure.com).
        2. In the left-hand menu (or search bar), go to **Monitor**.
        3. In Monitor, select **Alerts** from the left pane.
        4. Click **+ Create** → **Alert rule**.

        ***

        ## 3. Select the Scope (Which VMs / Subscription / RG)

        1. Under **Scope**, click **Select resource**.
        2. Decide the level:
           * To monitor *all* VMs in a subscription: choose the **Subscription**.
           * To monitor *all* VMs in a resource group: choose the **Resource group**.
           * To monitor a *single VM*: change filter to **Resource type = Virtual machines**, then select the VM.
        3. Click **Done**.

        ***

        ## 4. Choose the Signal Type (Activity Log)

        1. Under **Condition**, click **Add condition**.
        2. In the “Select a signal” pane:
           * Make sure **Signal type** is set to **Activity log** (not Metrics).
           * Look for **Administrative** category events such as:
             * `Power off virtual machine`
             * `Deallocate virtual machine`
        3. If you see multiple relevant operations (depends on your environment), you may need multiple rules:
           * One for `Power off virtual machine`
           * One for `Deallocate virtual machine`
        4. Click the `Power off virtual machine` (or the operation you want) signal.

        ***

        ## 5. Configure the Condition

        After selecting `Power off virtual machine`:

        1. You’ll see **Configure signal logic**.
        2. Under **Filter**, ensure:
           * **Operation name** is `Power off virtual machine`.
           * **Status** (if available) is `Succeeded` so you only alert on completed power-offs.
        3. Leave other filters as default unless you need to further narrow by caller, IP, etc.
        4. Click **Done** (or **Apply**) to confirm the condition.

        Repeat to create another alert rule for `Deallocate virtual machine` if you also want alerts when VMs are deallocated.

        ***

        ## 6. Create or Select an Action Group (Who Gets Notified)

        1. Under **Actions**, click **Add action groups**.
        2. Either:
           * Select an existing **Action group**, or
           * Click **Create action group**:
             1. Define:
                * **Subscription**
                * **Resource group**
                * **Action group name**
                * **Display name**
             2. On the **Notifications** tab:
                * Click **+ Add notification**.
                * Choose **Email/SMS/Push/Voice** (or other methods such as Webhook, Logic App).
                * Enter email addresses or phone numbers as needed.
             3. Review and **Create** the action group.
        3. Ensure the action group is selected and click **Apply**.

        ***

        ## 7. Define Alert Rule Details

        1. Under **Alert rule details**:
           * **Alert rule name**: e.g., `Alert - VM Power Off - <scope description>`.
           * **Description**: e.g., `Alert when any VM in this subscription is powered off (Activity log).`
           * **Severity**: choose (e.g., **Sev 2** or **Sev 3**) based on your policy.
        2. Ensure **Enable rule upon creation** is checked.

        ***

        ## 8. Review and Create

        1. Click **Review + create**.
        2. Validate settings, then click **Create**.

        Repeat the same process for `Deallocate virtual machine` if you want to catch both power-off behaviors.

        ***

        ## 9. (Optional) Test the Alert

        1. Go to one of the target VMs.
        2. In the VM blade, click **Stop** (this will typically deallocate it; depending on how it’s done you may see `Power off` or `Deallocate` in the Activity log).
        3. Wait a few minutes; verify:
           * The event appears under **Monitor → Activity log** with `Power off virtual machine` or `Deallocate virtual machine` and status `Succeeded`.
           * The configured action (email/SMS/etc.) is received.

        This fully remediates the “no alerts on power off VM events” misconfiguration for Azure Compute using the Azure portal.
      </Accordion>

      <Accordion title="Using CLI">
        Below is a minimal, end‑to‑end Azure CLI remediation to alert whenever a VM is powered off or deallocated.

        ### 1. Set variables

        ```bash theme={null}
        # Set these to your values
        SUBSCRIPTION_ID="<your-subscription-id>"
        RESOURCE_GROUP="<rg-of-your-vm-or-alert>"
        VM_NAME="<your-vm-name>"
        LOCATION="<region-of-alert-eg-westeurope>"
        ALERT_NAME="vm-poweroff-alert"
        ACTION_GROUP_NAME="vm-poweroff-ag"
        ACTION_GROUP_SHORT_NAME="vmoffag"
        ALERT_EMAIL="<your-email@example.com>"

        az account set --subscription "$SUBSCRIPTION_ID"
        ```

        Get the VM resource ID (optional, for scoping):

        ```bash theme={null}
        VM_ID=$(az vm show \
          --resource-group "$RESOURCE_GROUP" \
          --name "$VM_NAME" \
          --query id -o tsv)
        ```

        > You can scope the alert to the whole subscription, a resource group, or a single VM. Below I show subscription‑scope (recommended) and note how to change it.

        ***

        ### 2. Create an Action Group (where alerts are sent)

        ```bash theme={null}
        az monitor action-group create \
          --resource-group "$RESOURCE_GROUP" \
          --name "$ACTION_GROUP_NAME" \
          --short-name "$ACTION_GROUP_SHORT_NAME" \
          --location "$LOCATION" \
          --action email myEmail "$ALERT_EMAIL"
        ```

        Capture the Action Group ID:

        ```bash theme={null}
        AG_ID=$(az monitor action-group show \
          --resource-group "$RESOURCE_GROUP" \
          --name "$ACTION_GROUP_NAME" \
          --query id -o tsv)
        ```

        ***

        ### 3. Create Activity Log Alert for VM Power Off / Deallocate

        These operations appear in the Activity Log as:

        * `Microsoft.Compute/virtualMachines/deallocate/action`
        * `Microsoft.Compute/virtualMachines/powerOff/action`

        Create an Activity Log alert for both, scoped to the **subscription**:

        ```bash theme={null}
        az monitor activity-log alert create \
          --name "$ALERT_NAME" \
          --resource-group "$RESOURCE_GROUP" \
          --scope "/subscriptions/$SUBSCRIPTION_ID" \
          --condition category=Administrative \
          --condition "operationName=Microsoft.Compute/virtualMachines/deallocate/action" \
          --condition "operationName=Microsoft.Compute/virtualMachines/powerOff/action" \
          --action-group "$AG_ID" \
          --location "$LOCATION"
        ```

        If you want to scope it to a **single VM** instead:

        ```bash theme={null}
        az monitor activity-log alert create \
          --name "$ALERT_NAME" \
          --resource-group "$RESOURCE_GROUP" \
          --scope "$VM_ID" \
          --condition category=Administrative \
          --condition "operationName=Microsoft.Compute/virtualMachines/deallocate/action" \
          --condition "operationName=Microsoft.Compute/virtualMachines/powerOff/action" \
          --action-group "$AG_ID" \
          --location "$LOCATION"
        ```

        ***

        ### 4. Verify

        List the activity log alerts:

        ```bash theme={null}
        az monitor activity-log alert list \
          --resource-group "$RESOURCE_GROUP" \
          -o table
        ```

        Once in place, whenever a VM is powered off or deallocated under the defined scope, you’ll receive an email from the Action Group.
      </Accordion>

      <Accordion title="Using Python">
        Below is a concise, step‑by‑step way to set up **Azure alerts when a VM is powered off** (deallocated/stopped) using **Python** and the Azure SDK.

        We’ll create an **Activity Log Alert** that fires when a VM receives a PowerOff or Deallocate operation.

        ***

        ## 1. Prerequisites

        1. **Python packages**

        ```bash theme={null}
        pip install azure-identity azure-mgmt-monitor
        ```

        2. **Authentication**

        Use one of:

        * `az login` (for local dev with `DefaultAzureCredential`)
        * Managed Identity (if running in Azure)

        3. Collect:

        * `subscription_id`
        * `resource_group_name` (for the alert resource)
        * (Optional) `vm_name` or target resource if you want the alert limited to a specific VM.

        ***

        ## 2. Understand the operations to monitor

        For VM power‑off events, the common Activity Log operations are:

        * `Microsoft.Compute/virtualMachines/powerOff/action`
        * `Microsoft.Compute/virtualMachines/deallocate/action`

        We’ll create an Activity Log Alert that triggers when either of these appears.

        ***

        ## 3. Python code – Create Activity Log Alert

        This example:

        * Creates an Activity Log Alert at the subscription level.
        * Filters on the two operations above.
        * Sends an email via an action group (if you already have one), or you can just create the alert without actions.

        Replace placeholders with your values.

        ```python theme={null}
        from azure.identity import DefaultAzureCredential
        from azure.mgmt.monitor import MonitorManagementClient
        from azure.mgmt.monitor.models import (
            ActivityLogAlertResource,
            ActivityLogAlertAllOfCondition,
            ActivityLogAlertLeafCondition,
            ActivityLogAlertActionGroup,
        )

        # -------------------------------------------------------------------
        # CONFIG – UPDATE THESE
        # -------------------------------------------------------------------
        subscription_id = "<YOUR_SUBSCRIPTION_ID>"
        resource_group_name = "<ALERT_RESOURCE_GROUP_NAME>"
        alert_name = "vm-poweroff-deallocate-alert"

        # Optional: if you want to target a specific VM, set this:
        # Full VM resource ID (example)
        # /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Compute/virtualMachines/<vmname>
        target_vm_resource_id = "<OPTIONAL_VM_RESOURCE_ID_OR_LEAVE_EMPTY>"

        # Optional: existing Action Group resource ID for notifications
        # /subscriptions/<sub>/resourceGroups/<rg>/providers/microsoft.insights/actionGroups/<actionGroupName>
        action_group_id = "<OPTIONAL_ACTION_GROUP_RESOURCE_ID_OR_LEAVE_EMPTY>"


        # -------------------------------------------------------------------
        # AUTH & CLIENT
        # -------------------------------------------------------------------
        credential = DefaultAzureCredential()
        monitor_client = MonitorManagementClient(credential, subscription_id)

        # -------------------------------------------------------------------
        # CONDITIONS – WHAT TO MATCH IN THE ACTIVITY LOG
        # -------------------------------------------------------------------
        # We use an "allOf" consisting of:
        #   - category = Administrative
        #   - (operationName = PowerOff OR operationName = Deallocate)
        #   - (optional) resourceId = specific VM

        conditions = []

        # Category: Administrative
        conditions.append(
            ActivityLogAlertLeafCondition(
                field="category",
                equals="Administrative"
            )
        )

        # Operations: powerOff or deallocate
        # Note: "anyOf" is implemented as multiple leaf conditions with "OR" behavior
        operation_conditions = [
            ActivityLogAlertLeafCondition(
                field="operationName",
                equals="Microsoft.Compute/virtualMachines/powerOff/action"
            ),
            ActivityLogAlertLeafCondition(
                field="operationName",
                equals="Microsoft.Compute/virtualMachines/deallocate/action"
            )
        ]

        # If you want a specific VM only:
        if target_vm_resource_id and target_vm_resource_id.strip():
            conditions.append(
                ActivityLogAlertLeafCondition(
                    field="resourceId",
                    equals=target_vm_resource_id
                )
            )

        # Build the final allOf condition:
        # SDK expects ActivityLogAlertAllOfCondition with "all_of" (list of leaf conditions or nested).
        # For OR between operations, you place them in 'any_of' sub-condition or rely on separate alerts.
        # Many customers instead create two alerts (one per operation).
        # For simplicity, create ONE alert per operation below.

        # -------------------------------------------------------------------
        # HELPER – CREATE ONE ALERT FOR A SINGLE OPERATION
        # -------------------------------------------------------------------
        def create_alert_for_operation(operation_name: str, alert_suffix: str):
            leaf_conditions = [
                ActivityLogAlertLeafCondition(field="category", equals="Administrative"),
                ActivityLogAlertLeafCondition(field="operationName", equals=operation_name)
            ]

            if target_vm_resource_id and target_vm_resource_id.strip():
                leaf_conditions.append(
                    ActivityLogAlertLeafCondition(
                        field="resourceId",
                        equals=target_vm_resource_id
                    )
                )

            all_of_condition = ActivityLogAlertAllOfCondition(
                all_of=leaf_conditions
            )

            actions = []
            if action_group_id and action_group_id.strip():
                actions.append(
                    ActivityLogAlertActionGroup(
                        action_group_id=action_group_id,
                        webhook_properties={}
                    )
                )

            alert = ActivityLogAlertResource(
                location="global",
                enabled=True,
                scopes=[f"/subscriptions/{subscription_id}"],
                condition=all_of_condition,
                actions=actions,
                description=f"Alert when VM receives {operation_name} operation"
            )

            result = monitor_client.activity_log_alerts.create_or_update(
                resource_group_name=resource_group_name,
                activity_log_alert_name=f"{alert_name}-{alert_suffix}",
                activity_log_alert=alert
            )
            print(f"Created alert: {result.name}")

        # Create two alerts: one for PowerOff, one for Deallocate
        create_alert_for_operation(
            "Microsoft.Compute/virtualMachines/powerOff/action",
            "poweroff"
        )

        create_alert_for_operation(
            "Microsoft.Compute/virtualMachines/deallocate/action",
            "deallocate"
        )
        ```

        ***

        ## 4. What this remediation achieves

        * Any time a VM is **powered off** or **deallocated**:
          * Azure emits an Activity Log event.
          * The Activity Log Alert(s) above match that event.
          * Actions are triggered (e.g., notifications via Action Group), enabling you to detect and investigate unexpected VM shutdowns.

        If you tell me whether you want:

        * Subscription‑wide vs single‑VM monitoring, and
        * Email/SMS/Teams/webhook actions,

        I can adjust the code to your exact setup.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        resource "azurerm_monitor_action_group" "vm_poweroff_ag" {
          name                = "VM_POWEROFF_ACTION_GROUP"
          resource_group_name = "RESOURCE_GROUP_NAME"        # replace with the resource group for the action group
          short_name          = "vm-pwoff"

          email_receiver {
            name          = "oncall-email"
            email_address = "ONCALL_EMAIL_ADDRESS"           # replace with email to receive alerts
          }

          # add other receivers as needed (sms_receiver, webhook_receiver, etc.)
        }

        resource "azurerm_monitor_activity_log_alert" "vm_poweroff_alert" {
          name                = "VM_POWEROFF_ALERT"
          resource_group_name = "RESOURCE_GROUP_NAME"        # replace with the resource group where you want the alert rule
          scopes              = [AZURE_VM_RESOURCE_ID]       # replace with the full resource ID of the VM or its resource group/subscription
          description         = "Alert on VM power off or deallocate events"

          criteria {
            category       = "Administrative"
            operation_name = "Microsoft.Compute/virtualMachines/deallocate/action"
          }

          criteria {
            category       = "Administrative"
            operation_name = "Microsoft.Compute/virtualMachines/powerOff/action"
          }

          action {
            action_group_id = azurerm_monitor_action_group.vm_poweroff_ag.id
          }

          enabled = true
        }
        ```

        This adds an Activity Log Alert that fires whenever a VM is powered off or deallocated and sends notifications through the specified action group. No existing resources are forced to be replaced by this change; it only creates new monitoring resources.

        To verify, `terraform plan` should show creation of `azurerm_monitor_action_group.vm_poweroff_ag` and `azurerm_monitor_activity_log_alert.vm_poweroff_alert` with the specified criteria and no changes to your existing `azurerm_windows_virtual_machine`/`azurerm_linux_virtual_machine` resources.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-activity-log](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-activity-log)
* [https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-log](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-log)
