用于 Azure Bicep 的 Azure EventGrid 订阅的 Webhook Url 失败

Webhook Url for Azure EventGrid Subscription with Azure Bicep Fails

我是 Azure Bicep 的新手(它本身很新),但对 ARM 模板有一些经验。

我正在尝试了解如何创建对 Azure 博客存储容器的 Azure 事件网格订阅。

这不是生产代码我一直在关注这个tutorial,现在我正在尝试使用未涵盖的 EventGrid。

当我部署使用二头肌创建的模板时出现错误:

{
    "error": {
        "code": "InvalidRequest",
        "message": "Invalid event subscription request: Supplied URL is invalid. It cannot be null or empty and should be a proper HTTPS URL like https://www.example.com."
    }
}

我的事件网格订阅如下所示:

resource sub1 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2020-04-01-preview' = {
    name: '${eventgrid.name}${subscriptionName}'
    properties: {
        destination: {
            properties: {
                maxEventsPerBatch: 1
                preferredBatchSizeInKilobytes: 64
            }
            endpointType: 'WebHook'
        }
        filter: {
            subjectBeginsWith: '/blobServices/default/containers/mycontainer'
            includedEventTypes: [
                'Microsoft.Storage.BlobCreated'
            ]
        }
        labels: []
        eventDeliverySchema: 'EventGridSchema'
        retryPolicy: {
            maxDeliveryAttempts: 30
            eventTimeToLiveInMinutes: 1440
        }
        topicType: 'Microsoft.Storage.StorageAccounts'
    }
}

当我将 endpointUrl 属性 添加到事件订阅时,我得到了一个不同的错误:

{
    "status": "Failed",
    "error": {
        "code": "ResourceDeploymentFailure",
        "message": "The resource operation completed with terminal provisioning state 'Failed'.",
        "details": [
            {
                "code": "Url validation",
                "message": "Webhook validation handshake failed for https://foobarblee.blob.core.windows.net/results-nlp. Http POST request failed with response code Unknown. For troublehooting, visit https://aka.ms/esvalidation. Activity id:, timestamp: 9/22/2020 11:21:07 PM (UTC)."
            }
        ]
    }
}

代码部分更改为如下所示:

resource sub1 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2020-04-01-preview' = {
    name: '${eventgrid.name}${subscriptionName}'
    properties: {
        destination: {
            properties: {
                maxEventsPerBatch: 1
                preferredBatchSizeInKilobytes: 64
                endpointUrl: 'https://${storageAccount.name}.blob.core.windows.net/mycontainer'
            }
            endpointType: 'WebHook'

很遗憾,我找不到关于这个特定问题的任何文档。

我的整个二头肌文件如下所示:

param location string = resourceGroup().location
param evgNamePrefix string = 'evg'
param subNamePrefix string = 'sub'
param stgNamePrefix string = 'stg'
param subOneName string = '/foo-local-debug'
param containerOneName string = '/mycontainer'
// param storageAccountName string = 'blee'

param globalRedundancy bool = true // defaults to true, but can be overridden

var storageAccountName = '${stgNamePrefix}${uniqueString(resourceGroup().id)}'
var eventGridName = '${evgNamePrefix}${uniqueString(resourceGroup().id)}'
var eventGridSubscriptionName = '${evgNamePrefix}${subNamePrefix}${uniqueString(resourceGroup().id)}${subOneName}'

resource evg 'Microsoft.EventGrid/systemTopics@2020-04-01-preview' = {
    name: eventGridName
    location: location
    properties: {
        source: stg.id
        topicType: 'Microsoft.Storage.StorageAccounts'
    }
}
resource sub1 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2020-04-01-preview' = {
    name: '${evg.name}${subOneName}'
    properties: {
        destination: {
            properties: {
                maxEventsPerBatch: 1
                preferredBatchSizeInKilobytes: 64
                endpointUrl: 'https://${stg.name}.blob.core.windows.net/mycontainer'
            }
            endpointType: 'WebHook'
        }
        filter: {
            subjectBeginsWith: '/blobServices/default/containers/mycontainer'
            includedEventTypes: [
                'Microsoft.Storage.BlobCreated'
            ]
        }
        labels: []
        eventDeliverySchema: 'EventGridSchema'
        retryPolicy: {
            maxDeliveryAttempts: 30
            eventTimeToLiveInMinutes: 1440
        }
        topicType: 'Microsoft.Storage.StorageAccounts'
    }
}

resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' = {
    name: storageAccountName
    location: location
    kind: 'StorageV2'
    sku: {
        name: globalRedundancy ? 'Standard_GRS' : 'Standard_LRS' // if true --> GRS, else --> LRS
    }
    properties: {
        azureFilesIdentityBasedAuthentication: {
            directoryServiceOptions: 'None'
        }
        largeFileSharesState: 'Disabled'
        networkAcls: {
            bypass: 'AzureServices'
            virtualNetworkRules: []
            ipRules: []
            defaultAction: 'Allow'
        }
        supportsHttpsTrafficOnly: true
        encryption: {
            services: {
                file: {
                    keyType: 'Account'
                    enabled: true
                }
                blob: {
                    keyType: 'Account'
                    enabled: true
                }
            }
            keySource: 'Microsoft.Storage'
        }
        accessTier:'Hot'
    }
}

resource bs 'Microsoft.Storage/storageAccounts/blobServices@2019-06-01' = {
    name: '${stg.name}/default'
    properties: { 
        cors: {
            corsRules: []
        }
        deleteRetentionPolicy: {
            enabled: true
            days: 7
        }
    }
    sku: {
        name: globalRedundancy ? 'Standard_GRS' : 'Standard_LRS' // if true --> GRS, else --> LRS
        tier: 'Standard'
    }   
} 

resource c1 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-06-01' = {
  name: '${stg.name}/default${containerOneName}'
  properties: {
    defaultEncryptionScope:'$account-encryption-key'
    denyEncryptionScopeOverride: false
    publicAccess: 'None'
  }
}

output storageId string = stg.id
output computedStorageName string = stg.name
output eventGridId string = evg.id
output eventGridsName string = evg.name

我根据 BICEP 文档生成了 ARM JSON。 我将 Url 更改为 public webhook,它正在工作:

"端点Url": "https://eval-mm.azurewebsites.net/api/Function1"

https://imgur.com/a/aQcXCoq

EventGrid 订阅 WebHook 必须是 public,并且不支持 URL 参数或 headers。这让我很烦。

享受 BICEP,这是很棒的东西:-)

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "location": {
          "type": "string",
          "defaultValue": "[resourceGroup().location]"
        },
        "evgNamePrefix": {
          "type": "string",
          "defaultValue": "evg"
        },
        "subNamePrefix": {
          "type": "string",
          "defaultValue": "sub"
        },
        "stgNamePrefix": {
          "type": "string",
          "defaultValue": "stg"
        },
        "subOneName": {
          "type": "string",
          "defaultValue": "/foo-local-debug"
        },
        "containerOneName": {
          "type": "string",
          "defaultValue": "/mycontainer"
        },
        "globalRedundancy": {
          "type": "bool",
          "defaultValue": true
        }
      },
      "functions": [],
      "variables": {
        "storageAccountName": "[format('{0}{1}', parameters('stgNamePrefix'), uniqueString(resourceGroup().id))]",
        "eventGridName": "[format('{0}{1}', parameters('evgNamePrefix'), uniqueString(resourceGroup().id))]",
        "eventGridSubscriptionName": "[format('{0}{1}{2}{3}', parameters('evgNamePrefix'), parameters('subNamePrefix'), uniqueString(resourceGroup().id), parameters('subOneName'))]"
      },
      "resources": [
        {
          "type": "Microsoft.EventGrid/systemTopics",
          "apiVersion": "2020-04-01-preview",
          "name": "[variables('eventGridName')]",
          "location": "[parameters('location')]",
          "properties": {
            "source": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
            "topicType": "Microsoft.Storage.StorageAccounts"
          },
          "dependsOn": [
            "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
          ]
        },
        {
          "type": "Microsoft.EventGrid/systemTopics/eventSubscriptions",
          "apiVersion": "2020-04-01-preview",
          "name": "[format('{0}{1}', variables('eventGridName'), parameters('subOneName'))]",
          "properties": {
            "destination": {
              "properties": {
                "maxEventsPerBatch": 1,
                "preferredBatchSizeInKilobytes": 64,
                "endpointUrl": "https://eval-mm.azurewebsites.net/api/Function1"
              },
              "endpointType": "WebHook"
            },
            "filter": {
              "subjectBeginsWith": "/blobServices/default/containers/mycontainer",
              "includedEventTypes": [
                "Microsoft.Storage.BlobCreated"
              ]
            },
            "labels": [],
            "eventDeliverySchema": "EventGridSchema",
            "retryPolicy": {
              "maxDeliveryAttempts": 30,
              "eventTimeToLiveInMinutes": 1440
            },
            "topicType": "Microsoft.Storage.StorageAccounts"
          },
          "dependsOn": [
            "[resourceId('Microsoft.EventGrid/systemTopics', variables('eventGridName'))]",
            "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
          ]
        },
        {
          "type": "Microsoft.Storage/storageAccounts",
          "apiVersion": "2019-06-01",
          "name": "[variables('storageAccountName')]",
          "location": "[parameters('location')]",
          "kind": "StorageV2",
          "sku": {
            "name": "[if(parameters('globalRedundancy'), 'Standard_GRS', 'Standard_LRS')]"
          },
          "properties": {
            "azureFilesIdentityBasedAuthentication": {
              "directoryServiceOptions": "None"
            },
            "largeFileSharesState": "Disabled",
            "networkAcls": {
              "bypass": "AzureServices",
              "virtualNetworkRules": [],
              "ipRules": [],
              "defaultAction": "Allow"
            },
            "supportsHttpsTrafficOnly": true,
            "encryption": {
              "services": {
                "file": {
                  "keyType": "Account",
                  "enabled": true
                },
                "blob": {
                  "keyType": "Account",
                  "enabled": true
                }
              },
              "keySource": "Microsoft.Storage"
            },
            "accessTier": "Hot"
          }
        },
        {
          "type": "Microsoft.Storage/storageAccounts/blobServices",
          "apiVersion": "2019-06-01",
          "name": "[format('{0}/default', variables('storageAccountName'))]",
          "properties": {
            "cors": {
              "corsRules": []
            },
            "deleteRetentionPolicy": {
              "enabled": true,
              "days": 7
            }
          },
          "sku": {
            "name": "[if(parameters('globalRedundancy'), 'Standard_GRS', 'Standard_LRS')]",
            "tier": "Standard"
          },
          "dependsOn": [
            "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
          ]
        },
        {
          "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
          "apiVersion": "2019-06-01",
          "name": "[format('{0}/default{1}', variables('storageAccountName'), parameters('containerOneName'))]",
          "properties": {
            "defaultEncryptionScope": "$account-encryption-key",
            "denyEncryptionScopeOverride": false,
            "publicAccess": "None"
          },
          "dependsOn": [
            "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
          ]
        }
      ],
      "outputs": {
        "storageId": {
          "type": "string",
          "value": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
        },
        "computedStorageName": {
          "type": "string",
          "value": "[variables('storageAccountName')]"
        },
        "eventGridId": {
          "type": "string",
          "value": "[resourceId('Microsoft.EventGrid/systemTopics', variables('eventGridName'))]"
        },
        "eventGridsName": {
          "type": "string",
          "value": "[variables('eventGridName')]"
        }
      }
    }