Finding deployment credentials of your Web App in Azure

When a Web App is published to Azure for the first time, publish profile is being generated containing basic information regarding what, where and how should be deployed. After you've automated your CI/CD pipeline, those informations are somehow lost. But what if I need to incorporate them in my build or release process? Fortunately there's an easy way to download all the data and use it for our purpose.

Azure CLI for the rescue!

To be honest, there's a few Powershell commands, which could help us here at least like:

  • Get-AzureWebsite
  • Get-AzureRMWebApp
  • Get-AzureRMWebAppPublishProfile

The first one is designed for Azure Classic and won't work e.g. when a connection type in VSTS is set to Azure Resource Manager. However it allows you to get credentials really easily:

$website = Get-AzureWebsite -Name $functionAppName

$username = $website.PublishingUsername
$password = $website.PublishingPassword

It will work perfectly if only you're not restricted to using ARM.

Get-AzureRMWebApp is a command, which is designed for working with Resource Manager. It's very similar to Get-AzureRMWebAppPublishProfile, the difference comes from the amount of information it returns. Since in this post we're focusing on getting deployment credentials, we'll skip the former and consider the latter only. When Get-AzureRMWebAppPublishProfile is called, it returns XML content, similar to .PublishSettings file which can be downloaded from Azure Portal. To fetch both a username and a password, you can use following script:

$xml = [xml](Get-AzureRMWebAppPublishingProfile -ResourceGroupName $resourceGroup -Name $functionAppName -OutputFile "__deploymentProfile.xml" -Format WebDeploy) 
$publishProfile =  $xml.FirstChild.ChildNodes[1]

$username = $publishProfile.userName.split('\')
$password = $publishProfile.userPWD

With those credentials, you can automate your CI/CD pipeline even more(e.g. they are needed when accessing Kudu for a master key for Azure Function). The only thing you have to remember, is to select the right version of the command, depending on the deployment model.

Working with Azure Functions and VSTS - retrieving secrets

This post is an extension to the post written by Marek Grabarz here. If you haven't got a chance to read, I strongly recommend you to do so - it presents a bit more general approach to automate Azure Functions and can act as baseline when it comes to build your custom solution.

The problem

You have an ARM template and full CI/CD pipeline prepared. All works smoothly and with easy. You're just about to grab a beer and celebrate success when suddenly you realizes, that you haven't put functions' keys to the output. After searching multiple pages you finally finds Marek's post, which explains in detail what is needed to obtain a secret from a function. 

Unfortunately using Azure Active Directory Authentication Library (aka ADAL) with VSTS results with the following error:

2017-04-24T08:16:40.9453294Z GAC    Version        Location                                                                                         
2017-04-24T08:16:40.9463285Z ---    -------        --------                                                                                         
2017-04-24T08:16:40.9523277Z False  v4.0.30319     C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\Az...
2017-04-24T08:16:40.9683275Z False  v4.0.30319     C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\Az...
2017-04-24T08:16:42.5695169Z ##[error]Exception calling "AcquireToken" with "4" argument(s): "user_interaction_required: One of two conditions was encountered: 1. The PromptBehavior.Never flag was passed, but the constraint could not be honored, because user interaction was required. 2. An error occurred during a silent web authentication that prevented the http authentication flow from completing in a short enough time frame"
2017-04-24T08:16:42.6375138Z ##[section]Finishing: Azure PowerShell script: FilePath

All right - maybe using PrompBehaviour.Auto is going to help:

2017-04-24T08:42:56.7459955Z GAC    Version        Location                                                                                         
2017-04-24T08:42:56.7459955Z ---    -------        --------                                                                                         
2017-04-24T08:42:56.7519937Z False  v4.0.30319     C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\Az...
2017-04-24T08:42:56.7679946Z False  v4.0.30319     C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\Az...
2017-04-24T08:42:57.9119830Z ##[error]Exception calling "AcquireToken" with "4" argument(s): "Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application."
2017-04-24T08:42:58.0019817Z ##[section]Finishing: Azure PowerShell script: FilePath

Apparently the way how VSTS authenticates itself is different than doing it locally(when you check logs, you'll see, that it doesn't call Login-AzureRMAccount - instead Add-AzureRMAccount -ServicePrincipal, what could be the reason, why ADAL is problematic in this particular scenario). We have to find another way to get the token for authentication. 

The solution

It seems, that the best way to obtain a token is to call a REST API under{tenantId}/oauth2/token. To do so you need a couple of things:

  • client_id for the service principal VSTS uses
  • client_secret(a key which is connected to the service principal)

The best way to find them is to do following:

1. Go to the Services panel

2. You should see the endpoint defined for VSTS. From here you can click on Manage Service Principal

You'll be forwarded to the old portal. Now go to the Configure tab - from here you can copy client_id needed for the API. You can also find the Keys section which is the last thing we need here - just add another key and copy its value(remember that once you leave this page, you won't be able to retrieve it). Once we're armed with additional data, we can use it to get our token:

$tokenEndpoint = "{tenantId}/oauth2/token"
$body = @{
        'resource'= ""
        'client_id' = "client_id"
        'grant_type' = 'client_credentials'
        'client_secret' = "client_secret"

$params = @{
    ContentType = 'application/x-www-form-urlencoded'
    Headers = @{'accept'='application/json'}
    Body = $body
    Method = 'Post'
    URI = $TokenEndpoint

$token = Invoke-RestMethod @params
$token | select access_token, @{L='Expires';E={[timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($_.expires_on))}} | fl *

This token can be further used to get a function key like this(assuming you have a master key):

$hostKeyRequest = Invoke-RestMethod -Method GET -Uri "https://$$masterKey" -Headers @{ Authorization = $token }


Integrating multiple resources in Azure and VSTS can be a little tricky sometimes, but as you can see it still doesn't require much work to get it working. With a simple Powershell script and one call to the API you can authenticate requests from your VSTS instance and make it work with most components available in Azure.