Azure Functions – connect to an Event Hub using a Managed Identity

Took me a while to figure this out…

So by default you can use a Managed Identity in an Azure Function to connect to a Key Vault. You 1) add a Managed Identity to the Azure Function, 2) give it access to the Secrets or whatever in the Key Vault, and 3) in the Configuration section of the Azure Function you make a configuration item with this Key Vault reference:

You can then refer to this within the Function as an environment variable. I use PowerShell so I can refer to it as $env:topSecret or (Get-ChildItem -Name Env:topSecret).Value. This is something everyone should be doing by default… not just with Azure Functions, but also Web Apps and anything else. Try and use the Key Vault for storing your secrets – your code should not have any secrets!

However, my Azure Function connects to an Event Hub and when I create the connection the portal creates a configuration variable in the Azure Function called (say) my-eventhub-name_Function_EVENTHUB and it has the following value:"Endpoint=sb://my-eventhub-name.servicebus.windows.net/;SharedAccessKeyName=<KeyName>;SharedAccessKey=<Secret>"

Whoa! That’s crazy. Anyone viewing my Azure Function can easily see the Event Hub creds and connect to it. I don’t want that – the Event Hub could contain security sensitive info (like Security Event logs in my case).

I tried adding the value to a Key Vault and changing the configuration item to be a Key Vault reference… and that works, but any time I want to change the Function input or output bindings it complains that it can’t find a connection. (Or maybe it didn’t really work and it worked during my testing coz of some cached info… I didn’t test it too thoroughly).

Anyways, I left things as I had bigger problems at hand like trying to get the Function workign in the first place :) but today I was reading more about this and came across this section of the Functions Reference document. Screnshot:

Seems to be straight-forward. The default host.json file has the following snippet:

Change that to:

Then we need to grant the Managed Identity permission to the Event Hub (or whatever supported source above you are trying to use).

I did that too, but what next? If I remove Event Hub connection from the Configuration setting it would complain… so I am missing something.

I found some mention of how to connect to a Storage Account but that didn’t make much sense to me. Then I realized if I go to the Extension page itself (there’s a link of the Functions Reference page) it has the following:

Ok, so in my case I know the Connection looks like: my-eventhub-name_Function_EVENTHUB. So I added the __fullyQualifiedNamespace part to it. That is to say change my-eventhub-name_Function_EVENTHUB with value "Endpoint=sb://my-eventhub-name.servicebus.windows.net/;SharedAccessKeyName=<KeyName>;SharedAccessKey=<Secret>" to my-eventhub-name_Function_EVENTHUB__fullyQualifiedNamespace with value my-eventhub-name.servicebus.windows.net.

And that worked! Awesome! I removed the Shared access policies on the Event Hub side too and things continue to work. Sweet.

I have to say – Managed Identities is one of the coolest things about Azure and Azure AD. It’s amazing how I can use that to access Key Vaults, assign roles to Automation Accounts, use it for a lot of things…

Update: Some 10 mins after posting this I was reading another Microsoft document and they have the same info as above.

That document too tells you what RBAC permissions are needed for the Managed Identity.

Addendum

Key Vault references are useful not just for secrets but even for storing the AzureWebJobsStorage configuration setting for your Function. When you create an Azure Function it also creates a Storage Account and a reference to is created as a configuration setting in the Azure Function. This contains the account key for that Storage Account, and that’s obviously something you should protect. So add that to a Key Vault, give the Functions’ Managed Identity access to the Key Vault, and change AzureWebJobsStorage to be a Key Vault reference instead (do the same for anything else too – I had WEBSITE_CONTENTAZUREFILECONNECTIONSTRING for instance).