Use Azure Policy to enforce job execution on Hybrid Runbook Worker

Important

Azure Automation Agent-based User Hybrid Runbook Worker (Windows and Linux) has retired on 31 August 2024 and is no longer supported. Follow the guidelines on how to migrate from an existing Agent-based User Hybrid Runbook Workers to Extension-based Hybrid Workers.

Starting a runbook on a Hybrid Runbook Worker uses a Run on option that allows you to specify the name of a Hybrid Runbook Worker group when initiating from the Azure portal, with the Azure PowerShell, or REST API. When a group is specified, one of the workers in that group retrieves and runs the runbook. If your runbook does not specify this option, Azure Automation runs the runbook in the Azure sandbox.

Anyone in your organization who is a member of the Automation Job Operator or higher can create runbook jobs. To manage runbook execution targeting a Hybrid Runbook Worker group in your Automation account, you can use Azure Policy. This helps to enforce organizational standards and ensure your automation jobs are controlled and managed by those designated, and anyone cannot execute a runbook on an Azure sandbox, only on Hybrid Runbook workers.

A custom Azure Policy definition is included in this article to help you control these activities using the following Automation REST API operations. Specifically:

This policy is based on the runOn property. The policy validates the value of the property, which should contain the name of an existing Hybrid Runbook Worker group. If the value is null, it is interpreted as the create request for the job, job schedule, or webhook is intended for the Azure sandbox, and the request is denied.

Permissions required

You need to be a member of the Owner role at the subscription-level for permission to Azure Policy resources.

Create and assign the policy definition

Here we compose the policy rule and then assign it to either a management group or subscription, and optionally specify a resource group in the subscription. If you aren't yet familiar with the policy language, reference policy definition structure for how to structure the policy definition.

  1. Use the following JSON snippet to create a JSON file with the name AuditAutomationHRWJobExecution.json.

     {
       "properties": {
         "displayName": "Enforce job execution on Automation Hybrid Runbook Worker",
         "description": "Enforce job execution on Hybrid Runbook Workers in your Automation account.",
         "mode": "all",
         "parameters": {
           "effectType": {
             "type": "string",
             "defaultValue": "Deny",
             "allowedValues": [
                "Deny",
                "Disabled"
             ],
             "metadata": {
               "displayName": "Effect",
               "description": "Enable or disable execution of the policy"
             }
           }
         },
         "policyRule": {
           "if": {
             "anyOf": [
               {
                 "allOf": [
                   {
                     "field": "type",
                     "equals": "Microsoft.Automation/automationAccounts/jobs"
                   },
                   {
                     "value": "[length(field('Microsoft.Automation/automationAccounts/jobs/runOn'))]",
                     "less": 1
                   }
                 ]
               },
               {
                 "allOf": [
                   {
                     "field": "type",
                     "equals": "Microsoft.Automation/automationAccounts/webhooks"
                   },
                   {
                     "value": "[length(field('Microsoft.Automation/automationAccounts/webhooks/runOn'))]",
                     "less": 1
                   }
                 ]
               },
               {
                 "allOf": [
                   {
                     "field": "type",
                     "equals": "Microsoft.Automation/automationAccounts/jobSchedules"
                   },
                   {
                     "value": "[length(field('Microsoft.Automation/automationAccounts/jobSchedules/runOn'))]",
                     "less": 1
                   }
                 ]
               }
             ]
           },
           "then": {
             "effect": "[parameters('effectType')]"
           }
         }
       }
     }
    
  2. Run the following Azure PowerShell or Azure CLI command to create a policy definition using the AuditAutomationHRWJobExecution.json file.

     az policy definition create --name 'audit-enforce-jobs-on-automation-hybrid-runbook-workers' --display-name 'Audit Enforce Jobs on Automation Hybrid Runbook Workers' --description 'This policy enforces job execution on Automation account user Hybrid Runbook Workers.' --rules 'AuditAutomationHRWJobExecution.json' --mode All
    

    The command creates a policy definition named Audit Enforce Jobs on Automation Hybrid Runbook Workers. For more information about other parameters that you can use, see az policy definition create.

    When called without location parameters, az policy definition create defaults to saving the policy definition in the selected subscription of the sessions context. To save the definition to a different location, use the following parameters:

    • subscription - Save to a different subscription. Requires a GUID value for the subscription ID or a string value for the subscription name.
    • management-group - Save to a management group. Requires a string value.

  1. After you create your policy definition, you can create a policy assignment by running the following commands:

    az policy assignment create --name '<name>' --scope '<scope>' --policy '<policy definition ID>'
    

    The scope parameter on az policy assignment create works with management group, subscription, resource group, or a single resource. The parameter uses a full resource path. The pattern for scope for each container is as follows. Replace {rName}, {rgName}, {subId}, and {mgName} with your resource name, resource group name, subscription ID, and management group name, respectively. {rType} would be replaced with the resource type of the resource, such as Microsoft.Compute/virtualMachines for a VM.

    • Resource - /subscriptions/{subID}/resourceGroups/{rgName}/providers/{rType}/{rName}
    • Resource group - /subscriptions/{subID}/resourceGroups/{rgName}
    • Subscription - /subscriptions/{subID}
    • Management group - /providers/Microsoft.Management/managementGroups/{mgName}

    You can get the Azure Policy Definition ID by using PowerShell with the following command:

    az policy definition show --name 'Audit Enforce Jobs on Automation Hybrid Runbook Workers'
    

    The policy definition ID for the policy definition that you created should resemble the following example:

    "/subscription/<subscriptionId>/providers/Microsoft.Authorization/policyDefinitions/Audit Enforce Jobs on Automation Hybrid Runbook Workers"
    

  1. Sign in to the Azure portal.

  2. Launch the Azure Policy service in the Azure portal by selecting All services, then searching for and selecting Policy.

  3. Select Compliance in the left side of the page. Then locate the policy assignment you created.

    Screenshot of Azure Policy dashboard.

When one of the Automation REST operations are executed without reference to a Hybrid Runbook Worker in the request body, a 403 response code is returned with an error similar to the following example indicating the operation attempted execution on an Azure sandbox:

{
  "error": {
    "code": "RequestDisallowedByPolicy",
    "target": "Start_VMS",
    "message": "Resource 'Start_VMS' was disallowed by policy. Policy identifiers: '[{\"policyAssignment\":{\"name\":\"Enforce Jobs on Automation Hybrid Runbook Workers\",\"id\":\"/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/MAIC-RG/providers/Microsoft.Authorization/policyAssignments/fd5e2cb3842d4eefbc857917\"},\"policyDefinition\":{\"name\":\"Enforce Jobs on Automation Hybrid Runbook Workers\",\"id\":\"/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/providers/Microsoft.Authorization/policyDefinitions/bbbb1b1b-cc2c-dd3d-ee4e-ffffff5f5f5f\"}}]'.",
    "additionalInfo": [
      {
        "type": "PolicyViolation",
        "info": {
          "policyDefinitionDisplayName": "Enforce Jobs on Automation Hybrid Runbook Workers",
          "evaluationDetails": {
            "evaluatedExpressions": [
              {
                "result": "True",
                "expressionKind": "Field",
                "expression": "type",
                "path": "type",
                "expressionValue": "Microsoft.Automation/automationAccounts/jobs",
                "targetValue": "Microsoft.Automation/automationAccounts/jobs",
                "operator": "Equals"
              },
              {
                "result": "True",
                "expressionKind": "Value",
                "expression": "[length(field('Microsoft.Automation/automationAccounts/jobs/runOn'))]",
                "expressionValue": 0,
                "targetValue": 1,
                "operator": "Less"
              }
            ]
          },
          "policyDefinitionId": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/providers/Microsoft.Authorization/policyDefinitions/bbbb1b1b-cc2c-dd3d-ee4e-ffffff5f5f5f",
          "policyDefinitionName": "bbbb1b1b-cc2c-dd3d-ee4e-ffffff5f5f5f",
          "policyDefinitionEffect": "Deny",
          "policyAssignmentId": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/MAIC-RG/providers/Microsoft.Authorization/policyAssignments/fd5e2cb3842d4eefbc857917",
          "policyAssignmentName": "fd5e2cb3842d4eefbc857917",
          "policyAssignmentDisplayName": "Enforce Jobs on Automation Hybrid Runbook Workers",
          "policyAssignmentScope": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/MAIC-RG",
          "policyAssignmentParameters": {}
        }
      }
    ]
  }
}

The attempted operation is also logged in the Automation account's Activity Log, similar to the following example.

Example of Activity log for failed job execution.

Next steps

To work with runbooks, see Manage runbooks in Azure Automation.