How to properly use "get_token" of "ManagedIdentityCredential" of azure identity - python-3.x

I am trying to use managed identity of Azure function to access AAD protected web app, which requires a custom flow instead of using different clients. So the first step is to obtain an access token:
credential = DefaultAzureCredential()
scope = "https://graph.microsoft.com/.default"
token = credential.get_token(scope)
I am able to get a token successfully.
Then access the AAD protected web app:
uri = "https://my-web-app-1.azurewebsites.net/"
headers = {
'Authorization': 'Bearer ' + token.token
}
api_response = requests.get(uri, headers=headers)
However, this step returns error:
{"code":401,"message":"IDX10511: Signature validation failed. Keys
tried: '[PII is hidden]'. \nkid: '[PII is hidden]'. \nExceptions
caught:\n '[PII is hidden]'.\ntoken: '[PII is hidden]'."}
So I suspect I used a wrong scope to get the token. So I am confused which scope to use here?
------context-----
I have an azure function which has been enabled system identity which has been enabled to access my web app my-web-app-1.azurewebsites.net/. The web app my-web-app-1.azurewebsites.net/ is AAD protected.
Here is the API permissions under my AAD application which I used for the web app authentication. The mistake here is I set API permissions for web app instead of Azure functions which in case has no way to set (because Functions have a system identity instead of AAD application where we can set API permissions.)

Try to set scope as {your-api-client-id}/.default to get access token. Replace your-api-client-id with the client id/application id for your API app in Azure AD.

Related

Azure API Management & Function Apps - Only allow APIM access to apps with user assigned identity

Currently I am using a backend connection with a function key in the header to access my function apps. Instead of needing to store & pass around these keys, I would like to use a managed identity to implicitly grant access to my API Management, and reject any direct calls.
I've read through this and it seems that I should be able to do this by doing the following:
Create User Managed Identity
Give it Contributor role to all of my function apps
Assign it to my API Management
Update the API Policy to include the following:
<authentication-managed-identity
resource="${function_id}"
output-token-variable-name="msi-access-token"
ignore-error="false"
client-id="#{function_access_client_id}"
/>
Where
a. "function_id" is the ID of my function app (also tried https://management.azure.com/)
b. "function_access_client_id" is the ID of my User Managed Identity
And this is where I now am confused.
If for (a) I use https://management.azure.com/, then i am able to successfully get a token, but it fails to authenticate against the "Authentication" of the function app.
If for (a) I use the ID of the function app, then i receive the following error:
"errorResponse": "System.InvalidOperationException: [MSAL] Authentication failed for ClientId: <user managed client id> Certificate: <certificate> AuthorizationUrl: https://login.windows.net/<id> resourceId: /subscriptions/<subscription>/resourceGroups/<res group>/providers/Microsoft.Web/sites/<function app name> ---> Microsoft.Identity.Client.MsalServiceException: AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope /subscriptions/<subscription>/resourceGroups/<res group>/providers/Microsoft.Web/sites/<function app>/.default is not valid.
I am able to make this work if I set the client_id variable to be the value of the Authentication Identity Provider of the function app. I also noticed that if I remove the user managed identity from the API Management after this worked, then it fails because it says that APIM doesn't have management identities enabled.
I guess I'm just really confused with the logic of this. If this is set up correctly, that means I need
A user assigned managed identity to say I can access the application. This Identity can create it's own JWT using it's client ID, but we don't use it
An authentication on the function application requiring a JWT
A policy which references the client ID of the authentication listed in step 2.
Is this set up wrong? It works it just feels very odd. What's the point of user managed identity?

How to Fetch Token to access APIM from Function App with Managed identity

I am trying to access APIM from Azure Function and want APIM to authenticate through Managed Identity Token. I have assigned system assigned identity to the function app.I am following this (sample)[https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=dotnet#asal] to generate token. In the below line if I give "https://vault.azure.net" to GetAccessTokenAsync method I am getting the token. but I want the audience to be APIM so I provided https://azure-api.net like mentioned in the last line. but I am getting exception. how can I provide the APIM Url to fetch the access token?
using Microsoft.Azure.Services.AppAuthentication;
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://vault.azure.net");
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://azure-api.net");
An Update. I think something wrong with listing the resources. because when I give the proper resource name it says resource doesnt exist in the tenant though I can see the subscription is under the same tenant when I run through az cli.
As I mentioned in the comment, you need to Register an application in Azure AD to represent the API, then you can get the token for it(i.e. with the Application ID URI in the previous link).
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("<Application ID URI>");
Something you need to know:
You can use azureServiceTokenProvider to get the token for https://vault.azure.net, https://managment.azure.com, because they are all the APIs exposed by Microsoft, i.e. azure keyvault rest api and azure management rest api, essentially they are all AD App registered by Microsoft, so if you want to get the token for your own API, you need to register the AD App first to represent the API first.
Also, when you use managed identity to get the token, essentially it uses the client credential flow to get the token, actually the managed identity is a service principal(i.e. enterprise application) managed by azure. Remember to leverage the app role if you need to validate the roles claim when you get the access token.

Azure usage details API shows "Authentication failed" after sign in with azure active directory v1 connection

I completely followed this link https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-authentication?view=azure-bot-service-4.0&tabs=aadv1%2Ccsharp%2Cbot-oauth and created a Azure AD app registration and used Azure Active Directory v1 for my web app bot.
After sign in, I view the token but with that token I cannot access the Azure API's, as it shows below response in Postman:
{
"error": {
"code": "AuthenticationFailed",
"message": "Authentication failed."
}
I called the Azure API below:
https://management.azure.com/subscriptions/${subscriptionId}/providers/Microsoft.Consumption/usageDetailsapi-version=2018-10-01
In my app registration in Azure AD, I have given these permission to access the Azure API:
In my Web App Bot -> Settings -> OAuth Connection Settings, I select:
ClientId -> My application client id
ClinetSecret -> My application client secret
GrantType -> I does not know what to give so I just typed "authorization_code" (If this wrong then Where I need to find my grantType)
LoginURL -> https://login.microsoftonline.com
TenantId -> common (To allow any user)
ResourceURL -> https://graph.microsoft.com/
Scopes -> I just left blank
Why am I not able to access the Azure API with that token?
Any Help. Thanks
An access token issued by Azure AD will always be for a specific resource. Which service a token is intended for is identified in the token's "audience" (in the aud claim). When using the v1 endpoint, the resource for which an app requests an access token is identified in the resource parameter of the authorization request. In the v2 endpoint, the resource is identified as part of the scope parameter.
In your case, the resource you've configured your bot to get a token for is Microsoft Graph (https://graph.microsoft.com), but then you're trying to use the resulting token to call the Azure Management API. The first thing the Azure Management API does is check if the access token it received is actually intended for it. If the audience does not match, it will immediately respond with an error.
Instead of trying to get a token for Microsoft Graph, you need to configure your bot to get a token for the Azure Management API. You should use https://management.azure.com, which is the resource URI for the Azure Management API, instead of https://graph.microsoft.com which is the resource URI for Microsoft Graph.

Azure monitor REST API throwing invalid token error

I created a native APP with Client credentials
AuthenticationContext authContext = new AuthenticationContext(AUTHORITY, false, service);
ClientCredential clientCred = new ClientCredential(CLIENT_ID, "myclientsecret");
//Future<AuthenticationResult> future = authContext.acquireToken("https://graph.microsoft.com", clientCred, null);
Future<AuthenticationResult> future = authContext.acquireToken("https://graph.microsoft.com", clientCred, null);
Authority is:
https://login.microsoftonline.com/{tenetID}/oauth2/authorize/
This worked fine and got a access token. Then I tried to access Azure Management REST API by setting this token as Bearer Token. Getting
401 Unauthorized
WWW-Authenticate: Bearer authorization_uri="https://login.windows.net/{tenentid}", error="invalid_token", error_description="Could not find identity for access token."
Any idea what am I doing wrong?
Another observation is, based on this create service principal documentation, when we add an app in AD it should show up in IAM --> assignment roles, some how my app is not showing up there. Seems I am missing some critical step.
If you want to call Azure Management REST API, the resource should be https://management.azure.com in your code, not the https://graph.microsoft.com which is for Microsoft Graph API.
Another observation is, based on this create service principal documentation, when we add an app in AD it should show up in IAM --> assignment roles, some how my app is not showing up there.
When you create an app in AAD, it will not be added to the Access control (IAM) of your subscription automatically, you need to add it as a role manually. Navigate to the Access control (IAM) in your subscription -> Add -> Add role assignment -> search for your service principal(AD App) by name and select a role (e.g. Owner) -> Save.

Azure AD token has already access to other app without permissions

We have 2 apps registered in Azure AD, let's call them WebApi1 and WebApi2.
WebApi1 needs to call WebApi2. A secret has been configured in WebApi1 in order to get a token. Here is the code I'm using to get the token and then make the call to WebApi2:
And here is how my WebApi2 is configured:
The thing that I don't understand is that I would expect WebApi2 to return a 401 exception since I have not set any permissions in Azure (via the App Registration portal) to WebApi1.
Yet, the call is made successfully and WebApi1 has access to WebApi2.
Why WebApi1 has access to WebApi2 without the use of permissions in Azure?
Your web api application should check access using the IsInRole() or the [Authorize] attribute. If your web api doesn't check access , by default the access token with no application roles(permission) could access to your web api .
Please refer to document Roles based access control in cloud applications using Azure AD . Since you are acquiring token with application identity (client credential flow) , please check the Assigning client applications to application roles of resource APIs section in the document .
Just another thing.
If you're working with Azure and roles, when setting the WindowsAzureActiveDirectoryBearerAuthenticationOptions, you'll need to set the right role type in order for IsInRole (or Authorize("YourRole")) to work.
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false,
ValidAudience = ConfigurationManager.AppSettings["AzureAd:Audience"],
RoleClaimType = System.Security.Claims.ClaimTypes.Role
},
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
Tenant = ConfigurationManager.AppSettings["AzureAd:Tenant"],
});

Resources