{tocify} $title={Table of Contents}
Using Managed Identity we can authenticate to any service that supports Azure AD authentication without having credentials in your code. But we would need access token for the target app in order to access it.
Microsoft has provided a library Microsoft.Azure.Services.AppAuthentication which has azureServiceTokenProvider.GetAccessTokenAsync method which can be used to get access token by just providing Audience ID.
In some cases, we need to explicitly provide access to an identity apart from token e.g., in Key Vault we have to add identity in it's access policy. The access mechanism can be different for each Azure Service.
Go to Portal and create an instance on Function App and once created select it and go to Platform features and select Identity
In Visual Studio, create a project using Azure functions Template and add a http triggered function .
Now we create a function which will use the above identity to call the AD secured function app by getting access token from Active Directory and pass it in header along with request.
However here no details other than AudienceID and TargetURL is required, this we store in App settings of function app (on local machine it is to be kept in local.settings.json file). As rest is taken care by azureServiceTokenProvider.GetAccessTokenAsync method and to use it we need to install Microsoft.Azure.Services.AppAuthentication nuget package.Microsoft has provided this library to work with Managed Identity.
Following code is used to get the access token
Build it and deploy it to Function App created in step1. And do not forget to add the TargetUrl and AudienceID in app settings.
The target function expects input in following form
and it returns result as "Hello,Reply from target app,+input it received"
Grab the url of caller function, use any rest client and make call to caller function app and pass on input in expected format as above and check the response.
GetAccessTokenAsync method automatically manages the authentication part before raising an access token request to authority. And to get the details required it makes a call internally to Managed Identity rest api.
Thus this process eliminates the overhead of managing the app, it's credentials and helps in avoiding the credentials in code.
What is Managed Service Identity / Managed Identity
In last post we saw how to secure a Function App with Active directory and how to make call to it from another function App.
And for doing it from function we used libraries provided by Microsoft i.e., Microsoft.IdentityModel.Clients.ActiveDirectory;
So we needed to authenticate first with AD and then request for access token. For that we create an AD app, create secret/add certificate , manage secrets expiry and storing the info somewhere so as to use in our code
With this approach there are two problem areas
1. We have to create/manage the AD app and the certificates/secrets associated with it.
2. We have to use credentials in our code, although from app settings (they are visible to all) or keyvault - but to access those you need credential to authenticate to it.
To avoid this, we can use Managed Service identity (MSI)/Managed Identity feature, and the Azure will do this for us automatically. To use MI/MSI, turn on Identity of the respective Azure Service(here function app) from the Azure Portal.
Note: MSI/MI feature is not available for all services. See Services that support managed identities for Azure resources
So we needed to authenticate first with AD and then request for access token. For that we create an AD app, create secret/add certificate , manage secrets expiry and storing the info somewhere so as to use in our code
With this approach there are two problem areas
1. We have to create/manage the AD app and the certificates/secrets associated with it.
2. We have to use credentials in our code, although from app settings (they are visible to all) or keyvault - but to access those you need credential to authenticate to it.
To avoid this, we can use Managed Service identity (MSI)/Managed Identity feature, and the Azure will do this for us automatically. To use MI/MSI, turn on Identity of the respective Azure Service(here function app) from the Azure Portal.
Note: MSI/MI feature is not available for all services. See Services that support managed identities for Azure resources
What happens when Identity is switched on ? -- When you switch on Identity of any Azure service, Azure itself creates an AD app with same name of the service thus creating an identity in Azure Active Directory.
And you don't have to worry about Tenant ID(Directory ID),
Client ID and Client Secret - as it is taken care(managed) by Azure thus the name Managed Identities.And you don't have to worry about Tenant ID(Directory ID),
Using Managed Identity we can authenticate to any service that supports Azure AD authentication without having credentials in your code. But we would need access token for the target app in order to access it.
Microsoft has provided a library Microsoft.Azure.Services.AppAuthentication which has azureServiceTokenProvider.GetAccessTokenAsync method which can be used to get access token by just providing Audience ID.
In some cases, we need to explicitly provide access to an identity apart from token e.g., in Key Vault we have to add identity in it's access policy. The access mechanism can be different for each Azure Service.
I personally feel, the access mechanism should be unified across all Azure service.
How to do it
Create Function App and Enable Identity (Caller AD App)
Go to Portal and create an instance on Function App and once created select it and go to Platform features and select Identity
Upon selecting Identity you will be presented with two option System assigned and User assigned - Select System assigned.
Make Status as On and save
What happens when we switch on Identity?
As mentioned earlier, an AD app gets created with same name as that of the azure service in Active directory, you can check it in Enterprise Application
Difference between System assigned and user assigned Identity
The lifecycle of a system-assigned identity is directly tied to the Azure service instance that it's enabled on (function app here). So if this function app is deleted, Azure automatically cleans up the credentials and the identity in Azure AD
user-assigned managed identity is created as a standalone Azure resource i.e.not tied to any service. So it is same as explicitly creating AD app and can be shared by any number of service.
Create Function
In Visual Studio, create a project using Azure functions Template and add a http triggered function .
Now we create a function which will use the above identity to call the AD secured function app by getting access token from Active Directory and pass it in header along with request.
However here no details other than AudienceID and TargetURL is required, this we store in App settings of function app (on local machine it is to be kept in local.settings.json file). As rest is taken care by azureServiceTokenProvider.GetAccessTokenAsync method and to use it we need to install Microsoft.Azure.Services.AppAuthentication nuget package.Microsoft has provided this library to work with Managed Identity.
Following code is used to get the access token
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken= awaitazureServiceTokenProvider.GetAccessTokenAsync(Environment.GetEnvironmentVariable("AudienceID"));
And this access token is passed with request in header as AuthenticationHeaderValue
httpClient.DefaultRequestHeaders.Authorization = newSystem.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var content = new StringContent(body, System.Text.Encoding.UTF8, "application/json");
response = httpClient.PostAsync(Environment.GetEnvironmentVariable("TargetURL"), content).Result;
And below is the full code
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using
Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net.Http;
using
Microsoft.Azure.Services.AppAuthentication;
namespace DevT2
{
public static class CallerFunctionMSI
{
[FunctionName("CallerFunctionMSI")]
public static async
Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger
function processed a request.");
string requestBody = await new
StreamReader(req.Body).ReadToEndAsync();
HttpResponseMessage Targetresp = await PostMessage(requestBody);
return Targetresp != null
?
(ActionResult)new
OkObjectResult($"Hello, {Targetresp.Content.ReadAsStringAsync().Result}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request
body");
}
public static async
Task<HttpResponseMessage> PostMessage(string body)
{
HttpResponseMessage response;
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await
azureServiceTokenProvider.GetAccessTokenAsync(Environment.GetEnvironmentVariable("AudienceID"));
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new
System.Net.Http.Headers.AuthenticationHeaderValue("Bearer",
accessToken);
var content = new StringContent(body,
System.Text.Encoding.UTF8, "application/json");
response =
httpClient.PostAsync(Environment.GetEnvironmentVariable("TargetURL"),
content).Result;
}
return response;
}
}
}
|
Testing
The target function expects input in following form
{"name":"Input"}
and it returns result as "Hello,Reply from target app,+input it received"
How it works
GetAccessTokenAsync method automatically manages the authentication part before raising an access token request to authority. And to get the details required it makes a call internally to Managed Identity rest api.
Thus this process eliminates the overhead of managing the app, it's credentials and helps in avoiding the credentials in code.
If you have questions or suggestions, feel free to do in comments section below !!!
Do share if you find this helpful .......
Knowledge Sharing is Caring !!!!!!
Learn More about Logic App
- How to configure Logic App Standard workflow behind Azure APIM
- How to Query Azure Table storage from Logic App | How to filter results of Azure Table storage from Logic App
- Understanding expressions in Logic Apps | Frequently used expressions in Logic Apps | What is expressions in Logic App
- How to use Logic app Run History | How to troubleshoot Logic App workflow execution
- Logic App and Slack - Sending messages to slack channel | Logic app and slack integration | Connecting Logic App to Slack channel
- How to access Application settings fields value from Logic app Standard workflow | Using Application settings as configuration store for Logic app standard workflow
- Developing Logic app standard workflow which uses Map locally and deploying to Azure
- Developing Logic App Standard Workflow Using Visual Studio Code | Create Logic App Standard Workflow Using Visual Studio Code
- Logic App - Xml to Json using Liquid Map | Append in Liquid Map
- How to use Azure Event Grid Custom Topic | Publishing and Subscribing from Azure Event Grid Custom Topic using Logic App
- Using Azure Storage Account Table as Config Store for Logic Apps | How to read and write from Logic App to Azure Storage Account Table
- Get Logic App Name in Logic App
- Difference between Logic App Consumption and Logic App Standard
- Getting Started with Logic App Standard | Overview of Logic App Standard | Basics of Logic App Standard
- How to find count of Logic App executions using Azure Portal
- Azure Functions vs Azure Logic App | Difference between Azure Functions and Azure Logic App
- Getting started with Logic App : Liquid Map | Using Liquid template in Logic app
- How to get actual error message of Scope in Logic App | Exception Handling in Logic app
- Interview questions and answers on Logic Apps | Interview questions for azure logic app developers
- How to execute Stored Procedure in Logic App | How to connect to SQL in Logic App
- How to get current date in logic app | How to format date time in Logic App
- BizTalk Developer getting started with Logic App
- Getting Started with Logic Apps - Fundamentals
- Getting Started with Logic Apps - Enterprise Application Integration
- Getting Started with Logic Apps - AS2
- Getting Started with Logic Apps - EDI X12 Fundamentals
- Getting Started with Logic Apps - XML to EDI X12
- Getting Started with Logic Apps - EDI X12 to XML
- Getting Started with Logic Apps - What happened to the Request?
- Inserting Multiple Records In On Prem SQL Using Logic App
- Inserting data in On Premises SQL Database using Logic Apps
- Installing and Configuring On Premises Data Gateway - By adding user to Active Directory
- XML Batching(Aggregation) in Logic App
- Batching(Aggregating) messages in Logic App
- Debatching(Splitting) JSON Message in Logic Apps - ForEach and SplitOn
- Debatching(Splitting) XML Message in Logic Apps - ForEach and SplitOn
- Securing Logic App with Azure Active Directory authentication
- Removing ns0: prefix from xml output from BizTalk/Logic app XSLT map
- Using Managed Identity in Logic Apps for Calling Active Directory Secured Function App
- Logic Apps : Fetching ISA and GS Segment Values From Interchange Envelope and Mapping
- Logic Apps : For Each Inside a For Each - Fetching values from field in an array inside an array
- How to configure Logic App Standard workflow behind Azure APIM
- How to Query Azure Table storage from Logic App | How to filter results of Azure Table storage from Logic App
- Understanding expressions in Logic Apps | Frequently used expressions in Logic Apps | What is expressions in Logic App
- How to use Logic app Run History | How to troubleshoot Logic App workflow execution
- Logic App and Slack - Sending messages to slack channel | Logic app and slack integration | Connecting Logic App to Slack channel
- How to access Application settings fields value from Logic app Standard workflow | Using Application settings as configuration store for Logic app standard workflow
- Developing Logic app standard workflow which uses Map locally and deploying to Azure
- Developing Logic App Standard Workflow Using Visual Studio Code | Create Logic App Standard Workflow Using Visual Studio Code
- Logic App - Xml to Json using Liquid Map | Append in Liquid Map
- How to use Azure Event Grid Custom Topic | Publishing and Subscribing from Azure Event Grid Custom Topic using Logic App
- Using Azure Storage Account Table as Config Store for Logic Apps | How to read and write from Logic App to Azure Storage Account Table
- Get Logic App Name in Logic App
- Difference between Logic App Consumption and Logic App Standard
- Getting Started with Logic App Standard | Overview of Logic App Standard | Basics of Logic App Standard
- How to find count of Logic App executions using Azure Portal
- Azure Functions vs Azure Logic App | Difference between Azure Functions and Azure Logic App
- Getting started with Logic App : Liquid Map | Using Liquid template in Logic app
- How to get actual error message of Scope in Logic App | Exception Handling in Logic app
- Interview questions and answers on Logic Apps | Interview questions for azure logic app developers
- How to execute Stored Procedure in Logic App | How to connect to SQL in Logic App
- How to get current date in logic app | How to format date time in Logic App
- BizTalk Developer getting started with Logic App
- Getting Started with Logic Apps - Fundamentals
- Getting Started with Logic Apps - Enterprise Application Integration
- Getting Started with Logic Apps - AS2
- Getting Started with Logic Apps - EDI X12 Fundamentals
- Getting Started with Logic Apps - XML to EDI X12
- Getting Started with Logic Apps - EDI X12 to XML
- Getting Started with Logic Apps - What happened to the Request?
- Inserting Multiple Records In On Prem SQL Using Logic App
- Inserting data in On Premises SQL Database using Logic Apps
- Installing and Configuring On Premises Data Gateway - By adding user to Active Directory
- XML Batching(Aggregation) in Logic App
- Batching(Aggregating) messages in Logic App
- Debatching(Splitting) JSON Message in Logic Apps - ForEach and SplitOn
- Debatching(Splitting) XML Message in Logic Apps - ForEach and SplitOn
- Securing Logic App with Azure Active Directory authentication
- Removing ns0: prefix from xml output from BizTalk/Logic app XSLT map
- Using Managed Identity in Logic Apps for Calling Active Directory Secured Function App
- Logic Apps : Fetching ISA and GS Segment Values From Interchange Envelope and Mapping
- Logic Apps : For Each Inside a For Each - Fetching values from field in an array inside an array
Thank you for your nice article. Can you please explain a little more in detail what is AudicanID and where can I find it? Dont we need to add manged Identity of Caller Azure function in target azurefunction?
ReplyDelete@Kaja : audience - It is the AD app for which the token was generated. This is the AD app which intercepts the request coming to target function app. So to make sure that the token is for this AD App (audience), it's AudienceID is passed .
ReplyDeleteAudience ID is just a name given to ClientID of Target AD App.
NO need to add Managed Identity of caller function as at Target azurefunction you have set Active Directory to handle authentication/authorization part.
Would request you to read following blog post for more insights-
https://www.tech-findings.com/2020/01/understanding-azure-active-directory-authorization.html
https://www.tech-findings.com/2020/01/securing-function-app-with-azure-active-directory.html