Recently while building a synapse based data platform with Terraform one of the automation challenges was how to approve the managed private endpoints that are created via Synapse.

When I create private endpoints myself in Terraform there is an option to set a flag so they are auto approved. When you are doing a synapse managed private endpoint, you use the azurerm_synapse_managed_private_endpoint resource and there is no option to approve the private endpoint automatically. I dont think you can approve them automatically so it looks like Terraform is constrained by Azure in this case. I know if you create them in the Portal you need to manually approve them too.

I know a few people have been talking about this on various forums, below I discuss two of the options I looked at for working around this limitation in my automation.

Option 1 – Powershell / Azure CLI

The first option I looked at was using a Powershell script which ran the Azure CLI and will have a function which looks for any pending connections for a given resource and then approves them.

I call the function passing in the name of the resource and its type.

Below is the script I used:


function ApprovePrivateEndPointConnectionsForResource([string] $resourceGroupName, [string] $resourceName, [string] $resourceType)
{
    #Use Azure CLI to query the private endpoints for this resource
    $text = $(az network private-endpoint-connection list -g $resourceGroupName -n $resourceName --type $resourceType)    
    $json = $text | ConvertFrom-Json

    #Loop over the private endpoint connections and approve any which are pending
    foreach($connection in $json)
    {   
        $privateEndpointConnectionId = $connection.id    
        $privateEndpointId = $connection.properties.privateEndpoint.id    
        $status = $connection.properties.privateLinkServiceConnectionState.status    
        
        if($status -eq "Pending"){
        
            Write-Host ''
            Write-Host 'About to Approve:'
            Write-Host $privateEndpointConnectionId
            Write-Host $status

            az network private-endpoint-connection approve --id $privateEndpointConnectionId --description "Approved"
        }
    }
}

$environmentName = $env:CommonSetting_EnvironmentName_LowerCase
$fullResourceGroupName = 'RG-IT-EDMS-' + $environmentName

#Approve Storage Private Endpoints
$fullResourceName = 'mystorage' + $environmentName.ToLower()
ApprovePrivateEndPointConnectionsForResource -resourceName $fullResourceName -resourceType 'Microsoft.Storage/storageAccounts' -resourceGroupName $fullResourceGroupName

#Approve Keyvault Private Endpoints
$fullResourceName = 'my-kv-' + $environmentName.ToLower()
ApprovePrivateEndPointConnectionsForResource -resourceName $fullResourceName -resourceType 'Microsoft.Keyvault/vaults' -resourceGroupName $fullResourceGroupName


#Approve Azure SQL Private Endpoints
$fullResourceName = 'my-az-sql-db-' + $environmentName.ToLower()
ApprovePrivateEndPointConnectionsForResource -resourceName $fullResourceName -resourceType 'Microsoft.Sql/servers' -resourceGroupName $fullResourceGroupName

Option 2 – Terraform Null Resource

Option 2 to achieve this involves using the null resource in Terraform. The null resource allows me to have a script using the local-exec provisioner where I can run some powershell inside of terraform and then in this terraform resource the script can reference the other resources I have created such as the sql db in the instance below.

It will then use a similar script to the above and approve any pending private endpoint connections that are waiting to be approved for that resource.

resource "null_resource" "approve_synapse_sqldb_private_endpoint" {
      
    triggers = {
        always_run = timestamp()
    }
        
    provisioner "local-exec" {
        interpreter = ["PowerShell", "-Command"]

        command = <<-EOT

        $resourceName = '${azurerm_mssql_server.edms_sql_server.name}'
        $resourceGroupName = '${data.azurerm_resource_group.edms_resource_group.name}'        
        $resourceType = 'Microsoft.Sql/servers'

        $text = $(az network private-endpoint-connection list -g $resourceGroupName -n $resourceName --type $resourceType)
        $json = $text | ConvertFrom-Json

        foreach($connection in $json)
        {
            $id = $connection.id
            $status = $connection.properties.privateLinkServiceConnectionState.status

            if($status -eq "Pending"){
        
                Write-Host $id ' is in a pending state'
                Write-Host $status

                az network private-endpoint-connection approve --id $id
            }
        }

        EOT
        }

    depends_on = [
        azurerm_synapse_managed_private_endpoint.edms_synapse_workspace_private_endpoint_edms_keyvault
    ]
}

Comparison

The benefit of the terraform null resource provider is it can be part of your terraform process and can reference other resources in your solution such as pointing to the sql database and then approve all connections for it.

The downside of terraform is that the null resource needs to trigger all of the time because you cant guarantee the connection has been approved or not so your null resource will show as a destroy and recreate in your terraform plan.

The downside of option 1 is you need to run it at the end separately when your terraform is finished.

In my case it felt a little less complicated to do option 1 and just put a step in my azure devops pipeline to run the script when Terraform was finished to approve any connections which need approving.

 

Buy Me A Coffee