azureterraformconnection-stringazure-synapselinked-service

Azure synapse linked service for Azure Function in Terraform


I'm writing a terraform script to create a azure synapse workspace. I've created a linked service for Azure Function but I'm unable to use it in pipeline, where it gives me an error of missing function key.

This is what i'm using now. I'm sure the problem is in the type_properties_json parameter.

resource "azurerm_synapse_linked_service" "FunctionName" {
  name                 = "FunctionName"
  synapse_workspace_id = azurerm_synapse_workspace.synapse.id
  type                 = "AzureFunction"
  type_properties_json = <<JSON
    {
      "functionAppUrl": "https://${data.azurerm_function_app.FunctionName.default_hostname}",
      "authentication": "Anonymous",
      "functionKey": "${data.azurerm_function_app_host_keys.FunctionName.default_function_key}"
    }
  JSON
  depends_on = [
    azurerm_synapse_firewall_rule.allowAll,
    data.azurerm_function_app.FunctionName,
    data.azurerm_function_app_host_keys.FunctionName
  ]
}

And this does create a linked service but when i use it in a pipeline, the run fails with the error

Azure function activity missing function key.

It appears to me after checking the output for azurerm_function_app there is no export for connectionString.


Solution

  • I tried to reproduce the scenario in my environment.

    Tried below code:

    resource "azurerm_synapse_linked_service" "example" {
      name                 = "kavya-fnapplinked"
      synapse_workspace_id = azurerm_synapse_workspace.example.id
      type                 = "AzureFunction"
      type_properties_json = <<JSON
        {
          "functionAppUrl": "https://${data.azurerm_function_app.example.default_hostname}",
          "authentication": "Anonymous",
         "functionKey": "${data.azurerm_function_app_host_keys.example.default_function_key}"
    }
    JSON
    depends_on = [
        azurerm_synapse_firewall_rule.allowAll,
        data.azurerm_function_app.example,
        data.azurerm_function_app_host_keys.example
      ]
    
    }
    

    Got errors due to the json property and function key not being generated as expected as they are not in correct format.

    enter image description here

    For this ,note two important points:

    1. Function key is only generated after the function app is created first and is a sensitive value.
    2. Json format for sensitive values must be in below format
    "secret": 
                     {
                    "type": "SecureString",
                    "value":  “{value}"
                   }
    

    Code:

    resource "azurerm_role_assignment" "role_assignment" {
      scope                = azurerm_storage_account.stfn.id
      role_definition_name = "Storage Blob Data Owner"
      principal_id         = data.azurerm_client_config.current.object_id
    }
    
    # used Sleep to wait for role assignment to take its time to propagate
    resource "time_sleep" "role_assignment_sleep" {
      create_duration = "60s"
    
      triggers = {
        role_assignment = azurerm_role_assignment.role_assignment.id
      }
    }
    
    
    resource "azurerm_storage_data_lake_gen2_filesystem" "example" {
      name               = "kavdatalakexample123"
      storage_account_id = azurerm_storage_account.stfn.id
       depends_on         = [time_sleep.role_assignment_sleep]
    }
    
    resource "azurerm_synapse_workspace" "example" {
      name                = "exmple-workspace"
      resource_group_name = data.azurerm_resource_group.example.name
      location            = data.azurerm_storage_account.example.location
      storage_data_lake_gen2_filesystem_id = azurerm_storage_data_lake_gen2_filesystem.example.id
      sql_administrator_login              = "sqladminuser"
      sql_administrator_login_password     = "H@Sh1CoR3!"
      managed_virtual_network_enabled      = true
      identity {
        type = "SystemAssigned"
      }
    
    }
    
    
    
    resource "azurerm_synapse_firewall_rule" "allowAll" {
      name                 = "allowAll"
      synapse_workspace_id = azurerm_synapse_workspace.example.id
      start_ip_address     = "0.0.0.0"
      end_ip_address       = "255.255.255.255"
    }
    
    
    resource "azurerm_storage_account" "stfn" {
      name                     = "kaexpleaccforfunct"
       resource_group_name = data.azurerm_resource_group.example.name
      location            = data.azurerm_storage_account.example.location
      account_tier             = "Standard"
      account_replication_type = "LRS"
    }
    
    
    resource "azurerm_app_service_plan" "example" {
      name                = "exm-kavya-app-service-plan"
      resource_group_name = data.azurerm_resource_group.example.name
      location            =data.azurerm_storage_account.example.location
      kind                = "FunctionApp"
      sku {
        tier = "Dynamic"
        size = "Y1"
      }
    }
    resource "azurerm_function_app" "example" {
      name                      = "exm-kavya-function-app"
      resource_group_name = data.azurerm_resource_group.example.name
      location            = data.azurerm_resource_group.example.location
     // storage_connection_string = azurerm_storage_account.stfn.primary_connection_string
      storage_account_name       = azurerm_storage_account.stfn.name
      storage_account_access_key = azurerm_storage_account.stfn.primary_access_key
      app_service_plan_id       = azurerm_app_service_plan.example.id
    }
    
    
    
    
    data "azurerm_function_app_host_keys" "example" {
     resource_group_name = data.azurerm_resource_group.example.name
     name= azurerm_function_app.example.name
      
    }
    
    output "function_key" {
      value = data.azurerm_function_app_host_keys.example.default_function_key
       sensitive = true
    }
    
    output "function_appurl" {
      value = "https://${azurerm_function_app.example.default_hostname}"
    }
    
    
    
    resource "azurerm_key_vault" "example" {
      name                        = "kavyaexamplekeyvault"
      location                    = data.azurerm_resource_group.example.location
      resource_group_name         = data.azurerm_resource_group.example.name
      enabled_for_disk_encryption = true
      tenant_id                   = data.azurerm_client_config.current.tenant_id
      soft_delete_retention_days  = 7
      purge_protection_enabled    = false
    
      sku_name = "standard"
    
      access_policy {
        tenant_id = data.azurerm_client_config.current.tenant_id
        object_id = data.azurerm_client_config.current.object_id
    
       
        key_permissions = [
          "Create",
          "Get",
        ]
    
        secret_permissions = [
          "Set",
          "Get",
          "Delete",
          "Purge",
          "Recover",
          "List"
        ]
    
        storage_permissions = [
          "Get","Set"
        ]
      }
    }
    
    resource "azurerm_key_vault_secret" "example" {
      name         = "functionkey"
      value        = data.azurerm_function_app_host_keys.example.default_function_key
      key_vault_id = azurerm_key_vault.example.id
    }
    
    resource "azurerm_synapse_linked_service" "example" {
      name                 = "kav-fnapplinked"
      synapse_workspace_id = azurerm_synapse_workspace.example.id
      type                 = "AzureFunction"
      type_properties_json = <<JSON
        {
           
      "functionAppUrl": "https://${azurerm_function_app.example.default_hostname}",
      "authentication": "Anonymous",
      "functionKey": 
                 {
                "type": "SecureString",
                "value":  "${azurerm_key_vault_secret.example.value}"
               }
          "authentication": "Anonymous",
          "functionKey": 
                     {
                    "type": "SecureString",
                    "value":  "${azurerm_key_vault_secret.example.value}"
                   }
    }
    JSON
    
    depends_on = [
        azurerm_synapse_firewall_rule.allowAll,
        azurerm_function_app.example,
        data.azurerm_function_app_host_keys.example
      ]
    
    }
    

    With abovecode I could successfully, create linked service.

    enter image description here

    Linked service for azure synapse workspace:

    enter image description here

    Reference: azure - Terraform issue creating the resource "azurerm_synapse_linked_service" specifically with the "type_properties_json" field - Stack Overflow