Skip to main content

Command Palette

Search for a command to run...

How to Deploy Grafana on Azure Using Terraform

Published
6 min read
How to Deploy Grafana on Azure Using Terraform

Grafana is one of the most popular open-source visualisation tools for monitoring systems, applications, and infrastructure. If you're running on Azure and want to automate the deployment of Grafana using Infrastructure as Code (IaC), Terraform is the tool for the job. This guide will walk through deploying Grafana on Azure using Terraform.

What do you need

All you need to follow this post is:

  • Terraform installed

  • Azure CLI installed

  • VS Code (or follow this article using your IDE of choice)

  • An Azure Subscription to deploy to

As we are deploying Grafana and not utilising any Cloud-hosted option, you do not need to sign up for any other services.

Terraform Configuration

First, create a directory for this project and open it within your chosen IDE. Then, create a file and call it main.tf. This is where we will configure the code we need.

We will start by configuring the provider. For this article, we are going to use AzureRM to do this:

provider "azurerm" {
  features {}
}

And now we move onto the resource block for Grafana. Microsoft offers an Azure-hosted Grafana service, which we will utilise as part of the deployment in this post:

resource "azurerm_resource_group" "grafana_rg" {
  name     = "grafana-rg"
  location = "West Europe"
}

resource "azurerm_dashboard_grafana" "grafana" {
  name                              = "grafana-instance-weu"
  resource_group_name               = azurerm_resource_group.grafana_rg.name
  location                          = "West Europe"
  grafana_major_version             = 11
  api_key_enabled                   = true
  deterministic_outbound_ip_enabled = true
  public_network_access_enabled     = true

  identity {
    type = "SystemAssigned"
  }

  tags = {
    key = "value"
  }
}

Now we have the resource block defined, let's break down what has been configured:

  • Name - The name we want to give the Grafana instance

  • Resource_group_name - The resource group the instance will sit within

  • Location - The Azure region to deploy into. In this example, we are using West Europe

  • Grafana_major_version - The major version of Grafana to deploy. At the time of writing, version 11 is the latest supported by the Azure resource

  • Api_key_enabled - Enables API keys for programmatic access to Grafana. Useful if you plan to integrate with other tooling

  • Deterministic_outbound_ip_enabled - When enabled, the instance uses a fixed set of outbound IPs. This is helpful when you need to allow-list the Grafana instance against data sources behind a firewall

  • Public_network_access_enabled - Controls whether the Grafana endpoint is reachable from the public internet. In a production setup, you would likely want this set to false and use Private Link instead

  • Identity - We are assigning a system-assigned managed identity, which we will use later to grant Grafana access to data sources such as Azure Monitor

  • Tags - Standard tagging block. Replace the placeholder key/value with your own tagging standard

Granting Access to Azure Monitor

On its own, the Grafana instance will deploy and be accessible, but it will not be able to read any data from Azure. To make this useful, we need to grant the managed identity permission to read metrics and logs from your subscription.

The most common role to assign is Monitoring Reader at the subscription scope. We can do this directly in Terraform using the azurerm_role_assignment resource:

data "azurerm_subscription" "current" {}

resource "azurerm_role_assignment" "grafana_monitoring_reader" {
  scope                = data.azurerm_subscription.current.id
  role_definition_name = "Monitoring Reader"
  principal_id         = azurerm_dashboard_grafana.grafana.identity[0].principal_id
}

What we are doing here:

  • Data block - Pulling the current subscription ID so we do not need to hardcode it

  • Scope - Assigning the role at the subscription level. You can narrow this down to a resource group or resource if you want tighter control

  • Role_definition_name - The built-in role we want to assign. Monitoring Reader is enough for most dashboarding scenarios

  • Principal_id - This is the system-assigned identity we created as part of the Grafana resource

If you also want Grafana to read from Log Analytics, you may want to assign the Log Analytics Reader role as well.

Granting Yourself Access

One thing that often catches people out the first time they deploy Azure Managed Grafana is that deployment alone does not give your user account access to sign in. You need to assign yourself the Grafana Admin (or Grafana Editor/Viewer) role on the instance itself.

We can handle this in Terraform too:

data "azurerm_client_config" "current" {}

resource "azurerm_role_assignment" "grafana_admin" {
  scope                = azurerm_dashboard_grafana.grafana.id
  role_definition_name = "Grafana Admin"
  principal_id         = data.azurerm_client_config.current.object_id
}

This grabs the object ID of whoever is running the Terraform apply and assigns them Grafana Admin rights on the new instance. If you are deploying this via a pipeline using a service principal, you will want to swap the principal_id out for the object ID of the user or group that should actually be managing the instance.

Deploying the Configuration

With everything in place, we can deploy. Open a terminal in your project directory and run the following:

az login
terraform init
terraform plan
terraform apply

The terraform plan step is a good habit to get into before any apply. It shows exactly what Terraform intends to create, modify, or destroy. Once you are happy with the plan output, confirm the apply and Terraform will provision your resource group, Grafana instance, and role assignments.

Deployment typically takes a few minutes. Once complete, head over to the Azure Portal, find your Grafana resource, and click the endpoint URL listed on the overview page. This will take you to the Grafana UI, where you can now start building dashboards.

You can commit the code to a repository and build a pipeline to deploy this also, but for this post, we executed it locally.

Wrapping Up

In a handful of lines of Terraform, we have a fully managed Grafana instance on Azure, wired up with a managed identity and the right permissions to start pulling data from Azure Monitor. No VMs to patch, no containers to maintain, and updates are handled by Microsoft.

In future posts, I will cover locking the instance down behind Private Link, integrating Grafana with Azure Managed Prometheus, and deploying dashboards as code so the whole stack can live alongside your infrastructure in source control.

%buymeacoffe-butyellow