Accessing Azure Key Vault using Managed Service Identity Logic Apps


Azure Key Vault is a great service to manage secrets, keys & certificates.

It uses RBAC to control access. Like all access control system, there is a chain of access. For instance, my user account has access to the vault: this means if my account’s credentials get leaked, the access to the vault is compromised.

Often this chain has its weakest link at the origin. People will put service principal’s secret in an application configuration. This can then be leaked by someone having access to the application configuration.

Azure solves this secret bootstrapping problem quite elegantly with Managed Service Identity (MSI).

An MSI is an identity bound to a service. It is created for the service and its credentials are managed (e.g. renewed) by Azure. The credentials are never divulged. Only tokens are dilvulged. The identity is terminated when the service is deleted.

There are currently (end of 2018) no integration between Azure Key Vault and Azure Logic App.

I thought I would get two birds with one stone by demonstrating how to use Azure Key Vault REST API with Azure Logic Apps using MSI.

I based the Logic App / Key Vault integration on the great article from DevKimchi. What I’ve added is the automation (ARM) & MSI.

As usual the code is on GitHub.

ARM Template

We can deploy the demo ARM template with the following button:

Deploy button

This should quickly (seconds) deploy 3 resources:

3 resources

Key vault

By default we do not have access to the key vault. This is a little unintuitive since we created it.

In order to give ourselves access, we need to add an access policies.

Access Policies

We see there exists one already for the get-secret-app Service Principal. This is the Manage Service Identity (MSI) of the get-secret-app Logic App.

This was done by the ARM template

"accessPolicies": [
    {
    "tenantId": "[reference(resourceId('Microsoft.Logic/workflows', variables('Get Secret App Name')), '2017-07-01', 'Full').identity.tenantId]",
    "objectId": "[reference(resourceId('Microsoft.Logic/workflows', variables('Get Secret App Name')), '2017-07-01', 'Full').identity.principalId]",
    "permissions": {
        "secrets": [
        "get"
        ]
    }
    }
]

That policy gives the get access on secrets only. This is the minimal privilege needed for the application since it will only access a secret.

We can add our own user account by adding a policy and giving it maximum permission. DO NOT FORGET TO SAVE POLICIES AFTER.

We should then be able to see the secrets.

secrets

The template created only one secret:

{
    "name": "[variables('Secret Name')]",
    "type": "secrets",
    "apiVersion": "2018-02-14",
    "tags": {},
    "dependsOn": [
        "[resourceId('Microsoft.KeyVault/vaults', parameters('Vault Name'))]"
    ],
    "properties": {
        "value": "[variables('Secret Value')]",
        "contentType": "",
        "attributes": {
            "enabled": "true"
        }
    }
}

Demo App

The demo app really is a wrapper on the get-secret-app. The idea was to make get-secret-app parameterizable by the name of the secret. This makes it reusable.

Demo app

If we run the app, it should be all green with the response task returning the answer.

The Answer

This is the value of the my-secret secret in the Key Vault.

This Logic App doesn’t have a Managed Service Identity (MSI) as it doesn’t access privilege service. It simply calls on an app that does. This shows that we can centralize access and give it least privilege.

Get Secret App

This Logic App is a little more sophisticated although quite straightforward.

Get Secret App

It uses two REST API.

  1. It gets the current version of the secret
  2. It parses the result
  3. It fetches the value of the secret for that version
  4. It parses the result
  5. It returns the value in the HTTP response

There is an API to list all the versions of a secret. Unfortunately, it isn’t trivial to find the current version with that list. We instead used an undocumented API:

GET {vaultBaseUrl}/secrets/{secret-name}?api-version=7.0

which returns the current version.

To get the value of the secret’s version, we used the get secret API.

The trick to use REST API is of course to authenticate with it. This is done by specifying the authentication section in the ARM Template:

"get-current-version": {
    "inputs": {
        "authentication": {
            "audience": "https://vault.azure.net",
            "type": "ManagedServiceIdentity"
        },
        "method": "GET",
        "uri": "https://@{parameters('vault-name')}.vault.azure.net/secrets/@{triggerBody()['secret']}?api-version=7.0"
    },
    "runAfter": {},
    "type": "Http"
}

This can also be seen in the HTTP tasks by showing advanced options:

Authentication in Portal

As DevKimchi stretches out, the audience needs to be precise. It needs to be https://vault.azure.net. It shouldn’t contain a trailing slash or capital letters.

Using this authentication means App Logics uses its Managed Service Identity (MSI) to access the REST API. As mentioned earlier, no credentials are shown here.

Summary

I hope this was useful to show how we can:

  1. Integrate Azure Key Vault with Logic Apps despite no integration exists today (end of 2018)
  2. Use Managed Service Identity (MSI) to securely access the REST API

The combination of MSI with Logic Apps makes it very easy to leverage Azure REST APIs. It becomes comparable to using integration tasks.

Advertisements

One thought on “Accessing Azure Key Vault using Managed Service Identity Logic Apps

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s