从 Webhook 启动 Runbook

使用 Webhook 可使外部服务在 Azure 自动化中通过单个 HTTP 请求启动特定的 Runbook。 外部服务包括 Azure DevOps Services、GitHub、Azure Monitor 日志和自定义应用程序。 此类服务可以使用 Webhook 启动 Runbook,而无需实现完整的 Azure 自动化 API。 可以将 Webhook 与在 Azure 自动化中启动 Runbook 中其他启动 Runbook 的方法进行比较。

WebhooksOverview

要了解带有 Webhook 的 TLS 1.2 或更高版本的客户端要求,请参阅用于 Azure 自动化的 TLS 1.2 或更高版本

Webhook 属性

下表介绍了必须为 webhook 配置的属性。

属性 说明
名称 Webhook 的名称。 可以提供任何名称,因为该名称不会公开给客户端。 它只用来标识 Azure 自动化中的 Runbook。 最好是为 Webhook 提供一个名称,该名称需要与使用它的客户端相关。
URL Webhook 的 URL。 这是客户端通过 HTTP POST 来调用的唯一地址,用于启动链接到 Webhook 的 Runbook。 它是在创建 Webhook 时自动生成的。 无法指定自定义 URL。

URL 包含一个允许第三方系统调用 Runbook 的安全令牌,不需要进一步进行身份验证。 因此,应该将 URL 视为密码。 出于安全原因,只能在创建 Webhook 时通过 Azure 门户查看该 URL。 请将保存在安全位置的 URL 记下来,供将来使用。
到期日期 Webhook 的到期日期,该日期之后不能再使用它。 创建 Webhook 后,只要它没有过期,就可以修改到期日期。
已启用 指示 Webhook 是否在创建后默认启用的设置。 如果将此属性设置为“禁用”,则任何客户端都无法使用 Webhook。 可以在创建 Webhook 或 Webhook 创建后的任何其他时间设置此属性。

Webhook 启动 Runbook 时使用的参数

Webhook 可以定义 Runbook 参数的值,当 Runbook 启动时会用到这些值。 Webhook 必须包含 Runbook 的任何必需参数的值,可以包含可选参数的值。 即使在创建 Webhook 后,也可以修改为 Webhook 配置的参数值。 链接到单个 Runbook 的多个 Webhook 可以使用不同的 Runbook 参数值。 客户端在使用 Webhook 启动 Runbook 时,无法重写在 Webhook 中定义的参数值。

若要从客户端接收数据,Runbook 支持一个名为 WebhookData 的参数。 此参数定义包含客户端在 POST 请求中包含的数据的对象。

WebhookData properties

WebhookData 参数具有以下属性:

属性 说明
WebhookName Webhook 的名称。
RequestHeader 包含传入 POST 请求标头的 PSCustomObject。
RequestBody 传入 POST 请求的主体。 此正文保留任何数据格式,例如字符串、JSON、XML,或表单编码格式。 编写的 Runbook 必须能够与预期的数据格式配合工作。

无需配置 Webhook 即可支持 WebhookData 参数,也不需要 Runbook 来接受它。 如果 Runbook 没有定义该参数,则会忽略从客户端发送的请求的任何详细信息。

注意

调用 Webhook 时,客户端应始终存储任何参数值,以防调用失败。 如果存在网络中断或连接问题,应用程序无法检索失败的 Webhook 调用。

如果在创建 Webhook 时为 WebhookData 指定了值,则会在 Webhook 使用客户端 POST 请求中的数据启动 Runbook 时重写该值。 即使应用程序未在请求正文中包含任何数据,也会发生这种情况。

如果启动使用 Webhook 以外的机制定义 WebhookData 的 Runbook,则可以为 Runbook 识别的 WebhookData 提供值。 此值应该是与 WebhookData 参数具有相同属性的对象,这样 Runbook 就可以使用它,如同使用 Webhook 所传递的实际 WebhookData 对象一样。

例如,如果你从 Azure 门户启动以下 Runbook,并想要传递一些示例 Webhook 数据进行测试,则必须在用户界面中传递 JSON 格式的数据。

WebhookData parameter from UI

在下一个 Runbook 示例中,让我们为 WebhookData 定义以下属性:

  • WebhookName:MyWebhook
  • RequestBody: *[{'ResourceGroup': 'myResourceGroup','Name': 'vm01'},{'ResourceGroup': 'myResourceGroup','Name': 'vm02'}]*

现在我们在 UI 中为 WebhookData 参数传递以下 JSON 对象。 下面的示例带有回车符和换行符,与从 Webhook 中传递的格式相匹配。

{"WebhookName":"mywebhook","RequestBody":"[\r\n {\r\n \"ResourceGroup\": \"vm01\",\r\n \"Name\": \"vm01\"\r\n },\r\n {\r\n \"ResourceGroup\": \"vm02\",\r\n \"Name\": \"vm02\"\r\n }\r\n]"}

Start WebhookData parameter from UI

注意

Azure 自动化通过 Runbook 作业记录所有输入参数的值。 因此,客户端在 Webhook 请求中提供的任何输入都将记录下来,并可供有权访问自动化作业的任何人使用。 因此,在 Webhook 调用中包括敏感信息时,应该特别小心。

Webhook 安全性

Webhook 的安全性取决于其 URL 的私密性,可以通过 URL 中包含的安全令牌来调用 Webhook。 只要请求是向正确的 URL 发出的,Azure 自动化就不会对此请求执行任何身份验证。 因此,客户端不应针对执行高度敏感操作的 runbook 使用 Webhook,而不使用验证请求的替代方法。

请考虑以下策略:

  • 可在 runbook 中包含逻辑,以确定它是否由 Webhook 调用。 让 Runbook 检查 WebhookData 参数的 WebhookName 属性。 Runbook 还可以执行进一步的验证,只需在 RequestHeaderRequestBody 属性中查找特定信息即可。

  • 让 Runbook 在收到 Webhook 请求时对外部条件执行某种验证。 例如,当有新的内容提交到 GitHub 存储库时,可通过 GitHub 调用 Runbook。 Runbook 在继续之前,可能会连接到 GitHub 来验证是否有新的提交内容。

  • Azure 自动化支持 Azure 虚拟网络服务标记,尤其是 GuestAndHybridManagement。 可以在网络安全组Azure 防火墙中使用服务标记来定义网络访问控制并触发 Webhook。 创建安全规则时,可以使用服务标记代替特定 IP 地址。 在规则的相应源或目标字段中指定服务标记名称(例如 GuestAndHybridManagement),可以允许或拒绝自动化服务的流量。 此服务标记不支持通过将 IP 范围限制到特定区域来实现更精细控制的方法。

创建 Webhook

注意

将 Webhook 与 PowerShell 7 runbook 一起使用时,它会将 Webhook 输入参数自动转换为无效的 JSON。 有关详细信息,请参阅已知问题 - PowerShell 7.1(预览版)。 建议将 Webhook 与 PowerShell 5 runbook 一起使用。

  1. 请使用以下代码创建 PowerShell runbook:

    param
    (
        [Parameter(Mandatory=$false)]
        [object] $WebhookData
    )
    
    write-output "start"
    write-output ("object type: {0}" -f $WebhookData.gettype())
    write-output $WebhookData
    write-output "`n`n"
    write-output $WebhookData.WebhookName
    write-output $WebhookData.RequestBody
    write-output $WebhookData.RequestHeader
    write-output "end"
    
    if ($WebhookData.RequestBody) { 
        $names = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
    
            foreach ($x in $names)
            {
                $name = $x.Name
                Write-Output "Hello $name"
            }
    }
    else {
        Write-Output "Hello World!"
    }
    
  2. 使用 Azure 门户、PowerShell 或 REST API 创建 Webhook。 Webhook 需要已发布的 runbook。 本演练使用了从创建 Azure 自动化 runbook 中创建的 runbook 的修改版本。

    1. 登录 Azure 门户

    2. 在 Azure 门户中,导航到自动化帐户。

    3. 在“流程自动化”下选择“Runbook”,打开“Runbook”页面 。

    4. 从列表中选择你的 Runbook,打开“Runbook 概述”页面。

    5. 选择“添加 Webhook”,打开“添加 Webhook”页面 。

      Runbook overview page with Add webhook highlighted.

    6. 在“添加 Webhook”页上,选择“创建新的 Webhook” 。

      Add webhook page with create highlighted.

    7. 输入 Webhook 的名称。 “到期日期”字段的到期日期默认为自当前日期起的一年后。

    8. 单击复制图标,或按 Ctrl + C 以复制 Webhook 的 URL。 然后将 URL 保存到安全位置。

      Creaye webhook page with URL highlighted.

      重要

      一旦创建 Webhook,就不能再次检索该 URL。 请务必按上面所述对其进行复制并记录。

    9. 选择“确定”,返回到“添加 Webhook”页面 。

    10. 在“添加 Webhook”页上,选择“配置参数和运行设置”,打开“参数”页面 。

      Add webhook page with parameters highlighted.

    11. 查看“参数”页面。 无需对本文中使用的示例 runbook 进行任何更改。 选择“确定”,返回到“添加 Webhook”页面 。

    12. 在“添加 Webhook”页上,选择“创建” 。 Webhook 已创建,返回到“Runbook 概述”页面。


使用 Webhook

此示例使用 PowerShell cmdlet Invoke-WebRequest 将 POST 请求发送到新的 Webhook。

  1. 准备将传递给 runbook 的值作为 Webhook 调用的主体。 对于相对简单的值,可按以下方式编写脚本中的值:

    $Names  = @(
                @{ Name="Hawaii"},
                @{ Name="Seattle"},
                @{ Name="Florida"}
            )
    
    $body = ConvertTo-Json -InputObject $Names
    
  2. 对于较大的集,建议使用文件。 创建名为 names.json 的文件,然后将以下代码粘贴到其中:

    [
        { "Name": "Hawaii" },
        { "Name": "Florida" },
        { "Name": "Seattle" }
    ]
    

    在运行以下 PowerShell 命令前,将变量 $file 的值更改为 json 文件的实际路径。

    # Revise file path with actual path
    $file = "path\names.json"
    $bodyFile = Get-Content -Path $file 
    
  3. 运行以下 PowerShell 命令,使用 REST API 调用 Webhook。

    $response = Invoke-WebRequest -Method Post -Uri $webhookURI -Body $body -UseBasicParsing
    $response
    
    $responseFile = Invoke-WebRequest -Method Post -Uri $webhookURI -Body $bodyFile -UseBasicParsing
    $responseFile
    

    为方便说明,对生成主体的两种不同方法进行了两次调用。 而对于生产,只使用一种方法。 输出应如下所示(只显示一个输出):

    Output from webhook call.

    客户端收到从 POST 请求返回的以下代码之一。

    代码 文本 说明
    202 已接受 已接受该请求,并已成功将 Runbook 排队。
    400 无效的请求 出于以下原因之一,未接受该请求:
    • Webhook 已过期。
    • Webhook 已禁用。
    • URL 中的令牌无效。
    404 未找到 出于以下原因之一,未接受该请求:
    • 找不到 Webhook。
    • 找不到 runbook。
    • 找不到帐户。
    500 内部服务器错误 URL 有效,但出现了错误。 重新提交请求。

    假设请求成功,Webhook 响应将包含 JSON 格式的作业 ID,如下所示。 它包含单个作业 ID,但 JSON 格式允许将来可能的增强功能。

    {"JobIds":["<JobId>"]}
    
  4. 使用 PowerShell cmdlet Get-AzAutomationJobOutput 获取输出。 也可使用 Azure 自动化 API 获取。

    #isolate job ID
    $jobid = (ConvertFrom-Json ($response.Content)).jobids[0]
    
    # Get output
    Get-AzAutomationJobOutput `
        -AutomationAccountName $automationAccount `
        -Id $jobid `
        -ResourceGroupName $resourceGroup `
        -Stream Output
    

    触发在上一步中创建的 runbook 时,它将创建一个作业,并且输出应如下所示:

    Output from webhook job.

更新 Webhook

创建 Webhook 后,其有效期为 10 年,此期限过后,它会自动过期。 Webhook 过期后,你无法重新激活它。 只能删除并重新创建它。 对于尚未到期的 Webhook,可将其延期。 若要延长 Webhook 的有效期,请执行以下步骤。

  1. 请导航到包含 Webhook 的 Runbook。
  2. 在“资源”下,选择“Webhook”,然后选择需要延期的 Webhook 。
  3. 在“Webhook”页中,选择新的过期日期和时间,然后选择“保存” 。

查看 API 调用 Webhook - 更新和 PowerShell cmdlet Set-AzAutomationWebhook,了解其他可能的修改。

清理资源

以下是一些从自动化 runbook 中删除 Webhook 的示例。

  • 使用 PowerShell,可按如下所示的方式使用 Remove-AzAutomationWebhook cmdlet。 不返回任何输出。

    Remove-AzAutomationWebhook `
        -ResourceGroup $resourceGroup `
        -AutomationAccountName $automationAccount `
        -Name $psWebhook
    
  • 使用 REST,可按如下所示的方式使用 REST Webhook - 删除 API。

    Invoke-WebRequest -Method Delete -Uri $restURI -Headers $authHeader
    

    输出为 StatusCode : 200 表明删除成功。

使用 ARM 模板创建 runbook 和 Webhook

也可使用 Azure 资源管理器模板创建自动化 Webhook。 此示例模板会创建一个自动化帐户、四个 runbook 和一个用于指定 runbook 的 Webhook。

  1. 创建名为 webhook_deploy.json 的文件,然后将以下代码粘贴到其中:

    {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "automationAccountName": {
                "type": "String",
                "metadata": {
                    "description": "Automation account name"
                }
            },
            "webhookName": {
                "type": "String",
                "metadata": {
                    "description": "Webhook Name"
                }
            },
            "runbookName": {
                "type": "String",
                "metadata": {
                    "description": "Runbook Name for which webhook will be created"
                }
            },
            "WebhookExpiryTime": {
                "type": "String",
                "metadata": {
                    "description": "Webhook Expiry time"
                }
            },
            "_artifactsLocation": {
                "defaultValue": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/",
                "type": "String",
                "metadata": {
                    "description": "URI to artifacts location"
                }
            }
        },
        "resources": [
            {
                "type": "Microsoft.Automation/automationAccounts",
                "apiVersion": "2020-01-13-preview",
                "name": "[parameters('automationAccountName')]",
                "location": "[resourceGroup().location]",
                "properties": {
                    "sku": {
                        "name": "Free"
                    }
                },
                "resources": [
                    {
                        "type": "runbooks",
                        "apiVersion": "2018-06-30",
                        "name": "[parameters('runbookName')]",
                        "location": "[resourceGroup().location]",
                        "dependsOn": [
                            "[parameters('automationAccountName')]"
                        ],
                        "properties": {
                            "runbookType": "Python2",
                            "logProgress": "false",
                            "logVerbose": "false",
                            "description": "Sample Runbook",
                            "publishContentLink": {
                                "uri": "[uri(parameters('_artifactsLocation'), 'scripts/AzureAutomationTutorialPython2.py')]",
                                "version": "1.0.0.0"
                            }
                        }
                    },
                    {
                        "type": "webhooks",
                        "apiVersion": "2018-06-30",
                        "name": "[parameters('webhookName')]",
                        "dependsOn": [
                            "[parameters('automationAccountName')]",
                            "[parameters('runbookName')]"
                        ],
                        "properties": {
                            "isEnabled": true,
                            "expiryTime": "[parameters('WebhookExpiryTime')]",
                            "runbook": {
                                "name": "[parameters('runbookName')]"
                            }
                        }
                    }
                ]
            }
        ],
        "outputs": {
            "webhookUri": {
                "type": "String",
                "value": "[reference(parameters('webhookName')).uri]"
            }
        }
    }
    
  2. 以下 PowerShell 代码示例从计算机部署模板。 为变量提供适当的值,然后执行脚本。

    $resourceGroup = "resourceGroup"
    $templateFile = "path\webhook_deploy.json"
    $armAutomationAccount = "automationAccount"
    $armRunbook = "ARMrunbookName"
    $armWebhook = "webhookName"
    $webhookExpiryTime = "12-31-2022"
    
    New-AzResourceGroupDeployment `
        -Name "testDeployment" `
        -ResourceGroupName $resourceGroup `
        -TemplateFile $templateFile `
        -automationAccountName $armAutomationAccount `
        -runbookName $armRunbook `
        -webhookName $armWebhook `
        -WebhookExpiryTime $webhookExpiryTime
    

    注意

    出于安全原因,仅在首次部署模板时才返回 URI。

后续步骤