Search code examples
terraformssl-certificateazure-keyvaultazure-rm

Azurerm: KeyVault Nested Item should contain 2 or 3 segments, got 10


I get the error message below:

Error: parsing "/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/Microsoft.Network/applicationGateways/<app_gateway_name>/sslCertificates/<cert_name>": KeyVault Nested Item should contain 2 or 3 segments, got 10 from "subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/Microsoft.Network/applicationGateways/<app_gateway_name>/sslCertificates/<cert_name>"

I suppose the key error is "KeyVault Nested Item should contain 2 or 3 segments, got 10" but I have no idea what this means.

What I'm trying to do:

Via Terraform (azurerm), create an application gateway resource with a HTTPS(443) listener. I uploaded the certificate to the Azure Key (with Vault access policy) and created a managed identity to access that cert. In the portal, I can setup the listener with HTTPS using the managed identity and cert - no issues. Everything works as expected.

However, when I try to do the same in Terraform, I'm getting the error above.

Here's what I have:

data "azurerm_key_vault" "cert_store" {
  name                = "certstore"
  resource_group_name = local.resource_group.name
}

data "azurerm_key_vault_certificate" "tls_cert" {
  name         = "tls_cert"
  key_vault_id = data.azurerm_key_vault.cert_store.id
}

resource "azurerm_application_gateway" "app_gateway" {
  name                = "app_gateway1"
  resource_group_name = local.resource_group.name
  location            = local.resource_group.location
  sku {
    name     = var.gateway_vars.sku.name
    tier     = var.gateway_vars.sku.tier
    capacity = 2
  }

  gateway_ip_configuration {
    name      = "${var.gateway_vars.name}-ip-configuration"
    subnet_id = data.azurerm_subnet.gateway_subnet.id
  }

  frontend_port {
    name = "port_80"
    port = 80
  }

  frontend_port {
    name = "port_443"
    port = 443
  }

  identity {
    type = "UserAssigned"
    identity_ids = [
      azurerm_user_assigned_identity.app_gateway_managed_identity.id
    ]
  }

  ssl_certificate {
    key_vault_secret_id = data.azurerm_key_vault_certificate.cert_store.id
    name                = "tls_cert"
  }

  frontend_ip_configuration {
    name                 = "frontendIp"
    public_ip_address_id = azurerm_public_ip.app_gateway.id
  }

  backend_address_pool {
    name  = "frontend-pool"
    fqdns = ["fqdn.com"]
  }

  # https settings - used to connect to backend services via https
  backend_http_settings {
    name                                = "https"
    cookie_based_affinity               = "Disabled"
    port                                = 443
    protocol                            = "Https"
    request_timeout                     = 60
    path                                = "/"
    pick_host_name_from_backend_address = true
  }

  http_listener {
    name                           = "http80-listener"
    frontend_ip_configuration_name = "frontendIp"
    frontend_port_name             = "port_80"
    protocol                       = "Http"
  }

  http_listener {
    name                           = "https443-listener"
    frontend_ip_configuration_name = "frontendIp"
    frontend_port_name             = "port_443"
    protocol                       = "Https"
    ssl_certificate_name           = "tls_cert"
    require_sni                    = false
  }


  url_path_map {
    name                               = "path-map"
    default_backend_address_pool_name  = "frontend-pool"
    default_backend_http_settings_name = "https"
    path_rule {
      name                       = "xx"
      paths                      = ["/path"]
      backend_address_pool_name  = "frontend-pool"
      backend_http_settings_name = "https"
    }

  }

  request_routing_rule {
    name               = "tdr-routing-rule-443"
    rule_type          = "PathBasedRouting"
    http_listener_name = "https443-listener"
    url_path_map_name  = "path-map"
  }

}

Solution

  • So as I was making this post and about the publish it, a coworker reached out and figured he saw something similar a while back. Found it here:

    https://github.com/hashicorp/terraform-provider-azurerm/issues/6188

    The problem was the version of the cert being referenced. I think it didn't know which version of the cert to use, so I had to tell it which one. Within the app gateway resource block, in the ssl_certificate block, I used the trimsuffix function:

      ssl_certificate {
        name                = "tls_cert"
        key_vault_secret_id = trimsuffix(data.azurerm_key_vault_secret.certificate_secret.id, "${data.azurerm_key_vault_secret.certificate_secret.version}")
      }
    

    Second, I had to use azurerm_key_vault_secret instead of azurerm_key_vault_certificate, like below:

    data "azurerm_key_vault_secret" "certificate_secret" {
      name         = "name_of_cert"
      key_vault_id = data.azurerm_key_vault.cert_store.id
    }
    

    After that, it seems to be working. I still don't fully understand why using a keyvault secret works over keyvault certificate when trying to get a certificate but :shrug:.