Azure Service Endpoint Architecture

In one of my last onside appointments, I had to design an architecture for an application which should communicate over “service endpoint”.

The final architecture looks like the following:

At the moment it’s not possible to implement the whole environment with Azure powershell modules because there are some preview features included, but I’ve found a solution and will share that information with you. I will show you the implementation by code step by step.

At the bottom you can find a link to my GitHub repository, where you can find a detail documentation and the whole script.

Okay, deploy the resources.

Let’s start with the Azure Virtual Network.

$delegation = New-AzDelegation -Name "myDelegation" -ServiceName "Microsoft.Web/serverFarms"
$subnetpse = New-AzVirtualNetworkSubnetConfig -AddressPrefix "10.0.1.0/24" -Name "Sub-PSE" `
                                              -ServiceEndpoint Microsoft.Web,Microsoft.Sql,Microsoft.KeyVault `
                                              -Delegation $delegation                                        
$vnet = New-AzVirtualNetwork -Name $vnetname -ResourceGroupName $rg.ResourceGroupName -Location $location `
                             -AddressPrefix "10.0.0.0/16" -Subnet $subnetpse
$subnetid = ($vnet.Subnets | Where-Object Name -EQ $subnetpse.Name).Id

Next, deploy the SQL server, the SQL Database and activate the private service endpoint connection.

$sqlserver = New-AzSqlServer -Location $location -ServerName $sqlservername -SqlAdministratorCredentials $sqlservercredential `
                         -AssignIdentity -ResourceGroupName $resourcegroup        
$sqldatabase = New-AzSqlDatabase -DatabaseName $sqldatabasename -ResourceGroupName $resourcegroup -ServerName $sqlserver.ServerName `
                                -Edition GeneralPurpose -VCore 2 -ComputeGeneration Gen5 -ComputeModel Serverless 
Write-Host "Enable PSE for SQL servere"
$sqlvnet = New-AzSqlServerVirtualNetworkRule -ResourceGroupName $sqlserver.ResourceGroupName -ServerName $sqlserver.ServerName `
                                -VirtualNetworkRuleName "DemoPSERule" `
                                -VirtualNetworkSubnetId ($vnet.Subnets | Where-Object Name -eq $subnetpse.Name).Id

Now deploy the AppService plan and the AppService. Here we use a simple trick, because at the moment the private service endpoint integration with PowerShell isn’t possible, because that feature is in preview and not implemented at the moment. Here is the code to create the AppServicePlan and the AppService.

$appsvcplan = New-AzAppServicePlan -ResourceGroupName $resourcegroup -Location $location -Name $appsvcplanname `
                               -Tier Standard -NumberofWorkers 1 -WorkerSize Small
$webapp = New-AzWebApp -Name $webappname -Location $location -ResourceGroupName $resourcegroup -AppServicePlan $appsvcplan.Name
$webappidentity = Set-AzWebApp -Name $webapp.Name -ResourceGroupName $webapp.ResourceGroup -AssignIdentity $true

Further here is the private service integration code. In that section I call the API directly with an Invoke-RestMethod command.

$resourceId = "$($webapp.Id)/config/virtualNetwork"
$url = "https://management.azure.com$resourceId" + "?api-version=2018-02-01"
$payload = @{ id=$resourceId; location=$location;  properties=@{subnetResourceId=$subnetid; swiftSupported="true"} } | ConvertTo-Json
$enableappsvcpseresponse = Invoke-RestMethod -Method Put -Uri $url -Headers @{ Authorization="Bearer $accesstoken"; "Content-Type"="application/json" } -Body $payload -Verbose -Debug

At the end we create an Azure KeyVault, define a seperate access policy for the AppService managed identity and create a secret who includes the SQL connection string.

Write-Host "Create Azure KeyVault"
$keyvault = New-AzKeyVault -Name $keyvaultname -ResourceGroupName $resourcegroup -Location $location 
Write-Host "Add KeyVault Policy"
Set-AzKeyVaultAccessPolicy -VaultName $keyvault.VaultName -ResourceGroupName $resourcegroup -ObjectId $webappidentity.Identity.PrincipalId -PermissionsToSecrets get,list
$sqlpw= [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sqlservercredential.Password)
$sqlpw = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($sqlpw)
$connectionstring = "Server=tcp:sqldemopse.database.windows.net,1433;Initial Catalog=demopsedb;Persist Security Info=False;User `
                    ID=$($sqlservercredential.UserName);Password=$($sqlpw);MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" `
                    | ConvertTo-SecureString -AsPlainText -Force
Write-Host "Add KeyVault Secret"
$keyvaultsectret = Set-AzKeyVaultSecret -Name $keyvaultsecretname -VaultName $keyvault.VaultName -SecretValue $connectionstring
Write-Host "Enable PSE for KeyVault"
Add-AzKeyVaultNetworkRule -VaultName $keyvault.VaultName -VirtualNetworkResourceId $subnetid
Update-AzKeyVaultNetworkRuleSet -VaultName $keyvault.VaultName -DefaultAction Deny -Bypass None 

At the end I will add SQL tables and deploy the AppService source code.

This section is a planed feature!

Now everything is in place and you can use a private service endpoint architecture including Azure KeyVault which securely stored the SQL connection string.

If you want the whole script, you can download it from my GitHub repository. You also find a detailed description about the script at the Readme.md file. Please feel free and give me a feedback and I would be happy for rating and sharing.