0

I'm new to Azure Bicep (which in itself i pretty new) but have some experience with ARM templates.

I'm trying to learn how to create an Azure Event Grid subscription to an Azure Blog storage container.

This is not production code I've been following this tutorial and am now trying to work with an EventGrid which is not covered.

When I go to deploy my template created with bicep I get the error:

{
    "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."
    }
}

My event grid subscription looks like this:

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'
    }
}

When I add an endpointUrl property to the event subscription, I get a different error:

{
    "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)."
            }
        ]
    }
}

The section of code is changed to look like this:

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'

Unfortunately I can't find any documentation on this particular issue.

My entire bicep file looks like this:

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
TrevorBrooks
  • 3,590
  • 3
  • 31
  • 53

1 Answers1

2

I generated the ARM JSON based on BICEP document. I changed the Url to public webhook and it's working:

"endpointUrl": "https://eval-mm.azurewebsites.net/api/Function1"

https://i.stack.imgur.com/Ofpi4.jpg

The EventGrid Subscription WebHook has to be public and does not support URL parameters or headers. This is annoying for me.

Enjoy BICEP, it's great stuff :-)

    {
      "$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')]"
        }
      }
    }
Markus Meyer
  • 3,327
  • 10
  • 22
  • 35