The problem
Recently I was working on a project where we needed to access Azure resources in a different tenant from where an Azure Function was hosted. The client had a security policy that prohibited the use of connection strings/keys and only allowed Azure Entra (OAuth 2.0) authentication. Not only that but the Function also needed to access resources in the tenant it was hosted in.
The first thought
I could have just implemented code that authenticated using the Azure.Identity package but that would mean I could not use those sweet built-in bindings of Azure Functions. I would have to implement all the code to access the resources myself and the more code you type the more maintenance you have to do…
The simple solution is (almost) always the best
Luckily I found a simple way to solve this problem. You can set the following application settings for a Azure Event Hub trigger:
Name | Value |
---|---|
{VARIABLE}__tenantId | {TENANT_ID_OF_THE_OTHER_TENANT} |
{VARIABLE}__clientId | {CLIENT_ID_OF_THE_SERVICE_PRINCIPAL} |
{VARIABLE}__clientSecret | {CLIENT_SECRET_OF_THE_SERVICE_PRINCIPAL} |
{VARIABLE}__fullyQualifiedNamespace | {FULLY_QUALIFIED_NAMESPACE_OF_THE_EVENT_HUB} |
Please note that storing secrets in application settings is not recommended. You should use Key Vault for that. To do this you can instead set the {VARIABLE}__clientSecret
value to:
@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/)
This will automatically retrieve the secret from Key Vault. Do keep in mind that the Managed Identity of the Function needs to have access to the Key Vault.
The code
Now to actually use the identity most bindings have a property to set the identity. Here is an example for a .NET Event Hub trigger:
[FunctionName("EventHubTrigger")]
public static async Task Run([EventHubTrigger("EVENT_HUB", Connection = "{VARIABLE}")] EventData[] events, ILogger log)
{
var exceptions = new List<Exception>();
foreach (EventData eventData in events)
{
// Do something with the event
}
}
It’s also possible to use the identity in Python. Here is an example for that:
import logging
import azure.functions as func
app = func.FunctionApp()
@app.function_name(name="EventHubTrigger")
@app.event_hub_message_trigger(arg_name="my_hub",
event_hub_name="my_hub_name",
connection="{VARIABLE}")
def test_function(my_hub: func.EventHubEvent):
logging.info('Python EventHub trigger processed an event: %s',
my_hub.get_body().decode('utf-8'))
Note the {VARIABLE}
in the connection property. This will check if there are any application settings with that name as a prefix and use those values to authenticate.
Conclusion
Using an identity from a different tenant in an Azure Function to access resources is easy. Just set the right application settings, configure the bindings and you are good to go!