Creating budget alerts through Azure Blueprints

Have a reusable Azure ARM asset to set cost alerts on all your subscriptions.

I have highlighted the importance of a good Azure cloud governance plan and implementation before, and this week I received some slightly panicky messages from a colleague who’s customer was seeing extremely high cost. I was in another conference call that I couldn’t drop, but immediately gave some actions to limit further spend spiraling out of control.

In the end everything got solved, but this incident triggered some people and made them aware that they didn’t have cost alerts in place on the majority of their subscriptions. And even though these budget alerts typically come with a delay of 8-24 hours as Microsoft needs to collect and aggregate metrics first, it is still much better than let things run for weeks and end up with an even higher invoice.

While it’s very easy to create a new budget alert in the portal, having to do this on a 100 subscriptions is error-prone and will certainly take some time. So I suggested to quickly create these alerts in PowerShell across the whole tenant. However, the documentation stated following note:

Customers with a Microsoft Customer Agreement should use the Budgets REST API to create budgets programmatically because PowerShell and CLI aren’t yet supported.

And yes, the tenant wasn’t on an Enterprise Agreement but a Microsoft Customer Agreement. I had a look at the Budgets REST API and came to the conclusion that this wasn’t the path I wanted to take to provide IT with a reusable and easy-to-use script for current and future budget alerts. There was one more option available: using an ARM template.

Azure Blueprints

Azure Blueprints (currently still in preview) are a declarative way to orchestrate the deployment of various resource templates and other artifacts such as:

  • Role Assignments
  • Policy Assignments
  • ARM templates
  • Resource Groups

You create a blueprint definition and save it to a management group or subscription. Afterwards a published version can be assigned to a subscription or resource group. Since we want to assign to all subscription in a tenant, we’ll define the blueprint on a management group (possibly the tenant root group).

Cost alert blueprint

You can set multiple budget levels in a budget alert, but the main task here was to have at least one budget alert in place so for simplicity I went for a single level. Of course since we want some flexibility in budget value, contact email, … we will need some parameters:

  • Budget name (unique) within resource group
  • Budget amount
  • Start and end date
  • Budget level threshold(s)
  • Contact emails once alert triggers

Blueprint definition

This results in following template:

{
  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "budgetName": {
      "type": "string",
      "defaultValue": "DefaultBudget",
      "metadata": {
        "description": "Name of the Budget. It should be unique within a resource group."
      }
    },
    "amount": {
      "type": "string",
      "defaultValue": "500",
      "metadata": {
        "description": "The total amount of cost or usage to track with the budget"
      }
    },
    "timeGrain": {
      "type": "string",
      "defaultValue": "Monthly",
      "allowedValues": [
        "Monthly",
        "Quarterly",
        "Annually"
      ],
      "metadata": {
        "description": "The time covered by a budget. Tracking of the amount will be reset based on the time grain."
      }
    },
    "startDate": {
      "type": "string",
      "defaultValue": "[utcNow('YYYY-MM-dd')]",
      "metadata": {
        "description": "The start date must be first of the month in YYYY-MM-DD format. Future start date should not be more than three months. Past start date should be selected within the timegrain period."
      }
    },
    "endDate": {
      "type": "string",
      "defaultValue": "2040-12-31",
      "metadata": {
        "description": "The end date for the budget in YYYY-MM-DD format. If not provided, we default this to 10 years from the start date."
      }
    },
    "threshold": {
      "type": "string",
      "defaultValue": "100",
      "metadata": {
        "description": "Threshold value associated with a notification. Notification is sent when the cost exceeded the threshold. It is always percent and has to be between 0.01 and 1000."
      }
    },
    "contactEmails": {
      "type": "array",
      "defaultValue": [
        "azure-support@yourcompany.com"
      ],
      "metadata": {
        "description": "The list of email addresses to send the budget notification to when the threshold is exceeded."
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Consumption/budgets",
      "apiVersion": "2021-10-01",
      "name": "[parameters('budgetName')]",
      "properties": {
        "timePeriod": {
          "startDate": "[parameters('startDate')]",
          "endDate": "[parameters('endDate')]"
        },
        "timeGrain": "[parameters('timeGrain')]",
        "amount": "[parameters('amount')]",
        "category": "Cost",
        "notifications": {
          "NotificationForExceededBudget1": {
            "enabled": true,
            "operator": "GreaterThan",
            "threshold": "[parameters('threshold')]",
            "contactEmails": "[parameters('contactEmails')]"
          }
        }
      }
    }
  ]
}

For more extensive budget alerts with multiple budget levels or meter types, have a look at this gist from fRanK45jPm.

Now simply navigate to Blueprints in the Azure portal, create a new Blank Blueprint and give it a name. In our case we set the definition location to the tenant root group. With these parameters filled in, switch to the Artifacts tab. Click on ‘Add artifact’ and choose the Azure Resource Manager template (Subscription) option. Give it a name (e.g. BudgetAlert) and paste the ARM template from above.

If you switch to the Parameters tab in this Add artifact blade then you can choose which parameters are already pre-filled. Finally click add and save the draft. Once you’re ready, don’t forget to publish the definition.

Blueprint assignment

Once the definition is published, it is available for assignment. Pick the subscriptions that you want to assign to, fill in the required parameters and hit assign.

Important to notice is the Lock Assignment option. This is part of your Azure Governance story: do you want to assign a single blueprint everywhere and let subscription owners/contributors modify the values or even delete the budget alert? Or do you maybe go for a handful of deployments (each for a different budget on different subscription groups), locking the budget alert from any manual changes? While this second option is certainly safer from an Azure Governance perspective, you will need to re-assign on a specific subscription in case you want to change a value.

Blueprint assignment

Licensed under CC BY-NC-SA 4.0; code samples licensed under MIT.
comments powered by Disqus
Built with Hugo - Based on Theme Stack designed by Jimmy