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 https://login.windows.net/{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 = "https://login.windows.net/{tenantId}/oauth2/token"
$body = @{
        'resource'= "https://management.core.windows.net/"
        '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://$functionAppName.azurewebsites.net/admin/HOST/KEYS?CODE=$masterKey" -Headers @{ Authorization = $token }

Summary

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.

 

Help your imagination - visualizing ARM templates with ARMVIZ

ARM templates are a great tool when you want to automate provisioning of your environment. They're customizable, somehow flexible, easy to store and modify. What they lack - as many text tools - is a touch of abstraction. Most people are sightseers - that's why it's always a good thing to see what you're doing.

I'll paint this!

ARMVIZ is a free and OSS tool, which will visualize and help to validate your ARM template on a very high level. By saying "high level" I mean, that it helps to understand the structure of a template and basic dependencies rather than underlying relations when it comes to provision resources.

The very first visualization you'll see in ARMVIZ

Working with ARMVIZ

Currently there're two possibilities to work with ARMVIZ - either you open a template stored on your disk or write a new one inside the editor. The former helps to validate whether you have all components inside a template and all dependencies work well, the latter is actually a slightly better option when it comes to write JSON than Visual Studio(especially when VS goes mad while validating a JSON schema).

ARMVIZ suggests possible values but it won't limit them to the ones available for a field

When dependencies are removed from a VM, we can clearly see, that there're some problems with our template

Summary

In current shape ARMVIZ has very limited capabilities and can act only as a quick support when you have a very complicated ARM template. On the other hand, the possibility to write and see it increases your productivity and really helps when you're struggling to understand what is related to what and why.