Azure CDN returns "InvalidUri" when using Terraform

In hindsight, I could have probably solved this issue a lot quicker, but the error was so vague and the fact that CDN changes take some time to propagate, it took me more effort than I wanted. So, here we are, I'm writing this blog post in the hopes of saving you some time. I ran into some connectivity errors when connecting an Azure CDN to an Azure blob storage. But this might also apply to your web apps.

TL;DR: Go to solution

The setup

Our infrastructure setup is straightforward, centred around using Azure Blob Storage to host files like software installers, which are then distributed via Azure CDN to ensure global accessibility with low latency. A custom DNS was integrated with Azure CDN (and an Azure-managed SSL) to provide a branded and easy-to-remember access point for these files. The entire setup, from storage accounts to CDN configurations and custom DNS mapping, was provisioned and managed using Terraform. As a first setup, this is quite straightforward, and the terraform is relatively easy. It validates, plans and applies correctly, and even tfsec didn't warn me about any errors. So we deployed the terraform with success.

resource "azurerm_resource_group" "downloads" {
  name     = local.resource_group_name_with_location
  location = var.location
}

resource "azurerm_storage_account" "downloads" {
  name                     = local.escaped_random_name_24
  resource_group_name      = azurerm_resource_group.downloads.name
  location                 = var.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  min_tls_version          = "TLS1_2"
}

resource "azurerm_cdn_profile" "resources" {
  name                = "${local.name}-cdn"
  location            = var.location
  resource_group_name = azurerm_resource_group.downloads.name
  sku                 = "Standard_Verizon"
}

resource "azurerm_cdn_endpoint" "resources" {
  name                   = "${local.name_with_suffix}-cdne"
  profile_name           = azurerm_cdn_profile.resources.name
  location               = var.location
  resource_group_name    = azurerm_resource_group.downloads.name
  is_http_allowed        = false
  is_compression_enabled = true

  content_types_to_compress = [
    "application/x-msdownload" # For .exe files
  ]

  origin {
    name      = "blob"
    host_name = azurerm_storage_account.downloads.primary_blob_host
  }
}

The problem

After it was provisioned we had to wait a couple of minutes, and sometimes a couple of hours while CDN got its configuration propagated. First, you will see HTTP 404 response and after a while, it should work. However, this was not the case. The error we were presented with was the following "InvalidUri" message.

<Error>
	<Code>InvalidUri</Code>
	<Message>The request URI is invalid. RequestId:bc46aeba-601e-0065-54b2-76b9e0000000 Time:2024-03-15T08:25:55.7419100Z
	</Message>
</Error>

Diagnosis

So, first things first, we checked if the blob storage was working and if we could download the files using the storage account URL ***.blob.core.windows.net/downloads/installer.exe and these were working just fine. So we can establish that the link between the CDN and the storage account is not correct. Thus I assumed a configuration error from my side.

Different Options

Another thing that didn't help to wrap my head around the problem is that there are multiple CDN options in Azure. Furthermore, everything has been consolidated in "Azure Front Door and CDN profiles", so whenever you create one manually. The options are:

  • Microsoft CDN (classic)
  • Microsoft Standard Edgio
  • Microsoft Premium Edgio
  • Microsoft Azure Front Door (more expansive and feature richt)

So I tried all of these options, as you can manually create them from your blob storage. And obviously, these were working out of the box. 😅

Create a CDN from your azure blob storage

Having identified that 1; there is a configuration error, and 2; it is most likely caused by the way we create the Azure CDN profiles, we can narrow down our search. My previous searches (and assistance of ChatGPT) didn't get a hit, but having identified Terraform as a potential configuration problem, I was able to narrow down the search.

The solution

The problem is that the terraform template is missing the property origin_host_header. My next step would have been to manually compare the different endpoint configurations between the one created by Terraform and the one manually created, but I was able to find a Github issue with the same problem. It was one single property that I unfortunately overlooked. As you can see in the picture below, it is explained by inspecting this property in the Azure Portal that the Blob Storage and Web Apps require the origin host header to be specified. This is done for you when you manually create the CDN.
Thus, the correct terraform template should be like this for your CDN:

resource "azurerm_cdn_endpoint" "resources" {
  name                   = "${local.name_with_suffix}-cdne"
  profile_name           = azurerm_cdn_profile.resources.name
  location               = var.location
  resource_group_name    = azurerm_resource_group.downloads.name
  is_http_allowed        = false
  is_compression_enabled = true

  content_types_to_compress = [
    "application/x-msdownload" # For .exe files
  ]

  # ORIGIN_HOST_HEADER is required for connecting with Web Apps, Blob Storage and Cloud Services
  origin_host_header = azurerm_storage_account.downloads.primary_blob_host
  origin {
    name      = "blob"
    host_name = azurerm_storage_account.downloads.primary_blob_host
  }
}

Origin host header empty and thus cannot connect to your blob storage account.

Conclusion

It felt a bit counterintuitive to link two properties to the primary blob host, but it is necessary for it to work.  
I hope this post has helped you identify your problem working with Azure CDN and blob storage, provisioned by Terraform. However, I must give credit to Félix Prado as he was the one who was able to resolve this in his own Github issue.

Credit/Resources

Félix Prado
CDN endpoint is not working when configured using Terraform · Issue #3084 · hashicorp/terraform-provider-azurerm
Community Note Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request Please do not leave ”+1″ or “me too” comments, th…