Right now I'm using AAD app to make Service A => Service B calls. This includes:
AAD app
KeyVault which keeps a secret/certificate for AAD app
Managed Identity with access to KeyVault
The flow looks like this:
Service A: Get token from Managed Identity
Service A: Go to KeyVault, present a token and get a secret for AAD app
Service A: Go to AAD, present a secret and request a token for a particular resource
Service A: Make a call to Service B
Service B: Validate a token and a resource
I wonder whether it is possible to register a managed identity with my service, so if a Managed Identity token is presented then Service B can trust Service A. Something like this:
Service A: Get token from Managed Identity
Service A: Make a call to Service B
Service B: Validate that token comes from registered Managed Identity
Is it feasible? Does it violate any security best practices?
Update: beside below answer, the following stack overflow post describes how to make Managed Identity in one tenant to get a role claim for an app in another tenant
Grant service principal access to application in other tenant
I've written a blog article on this topic: https://joonasw.net/view/calling-your-apis-with-aad-msi-using-app-permissions.
You can definitely do it,
it'll mean you don't need to use any secrets to call Service B from Service A :)
You'll need to assign application permissions to the managed identity service principal using PowerShell / Graph API though.
There is no UI for this.
Example PowerShell command:
New-AzureADServiceAppRoleAssignment -ObjectId 1606ffaf-7293-4c5b-b971-41ae9122bcfb -Id 32028ccd-3212-4f39-3212-beabd6787d81 -PrincipalId 1606ffaf-7293-4c5b-b971-41ae9122bcfb -ResourceId c3ccaf5a-47d6-4f11-9925-45ec0d833dec
The ObjectId and PrincipalId are both the MSI-generated service principal's id. Id is the id of the role. ResourceId is the id for the API service principal.
This is using the AzureAD PowerShell module.
After the permission is assigned, your Managed Identity should be able to get you a token for Service B.
Your local development environment will need a different approach though, since there is no Managed Identity there.
You might for example use a client secret in there to test calls to Service B.
Sorry, I can't comment to juunas's reply as I don't have enough reputation to comment. Just wanted to say that the solution recommended by juunas worked for me only after I rebooted the VM from where I was trying to acquire the token using user-assigned managed identity. The idea to reboot the VM came from below article. This article also recommends exact same solution as juunas' but also mentions about rebooting VM to clear cache in case token still doesn't show roles after following the recommended steps. https://www.jasonfritts.me/2019/07/15/assigning-azure-ad-graph-api-permissions-to-a-managed-service-identity-msi/
Related
We aim to collect data from the Azure Management APIs. These APIs provide information on the resources we have running in Azure, the consumed budget, etc (example). Following our design choices, we prefer to exclusively use Azure Data Factory to make the HTTP requests and store the data into our data lakes. This is fairly obvious, using the REST linked service. However, we struggle to correctly set up the OAuth2 authentication dance with this method.
Our first idea was to store the token and the refresh token within the Azure Key Vault. A series of HTTP requests within the pipeline would then test whether the token is still valid or otherwise use the refresh token to get a new token. The downside to this approach is that the token within the Azure Key Vault is never updated, when needed, and that the logic becomes more complex.
Alternatively, we were trying to set up the authorization through combination of a registered app and service principal to our Azure AD account. The REST linked service within Data Factory can be created with a service principal, which would then handle most of the information of the scope and consent. The service principal is also accompanied with a Azure app, which would hold the token etc. Unfortunately, we are unable to make this setup function correctly.
Questions we have:
Can we actually use a service principal / app to store our OAuth2 tokens? If so, will these be automatically refreshed within our app?
How do we assign the correct privileges / authorizations to our app that it can use this (external) API?
Is the additional logic with HTTP calls within Azure Data Factory pipeline needed to update the tokens or can these apps / service principals handle this?
Thank you for your time and help!
It is not a good idea to store the tokens in the keyvault, because they will expire.
In your case, two options for you to use.
Use service principal to auth
Use managed identity to auth(best practice)
Steps to use service principal to auth:
1.Register an application with Azure AD and create a service principal.
2.Get values for signing in and create a new application secret.
3.To call the Azure REST API e.g. Resources - List you mentioned, your service principal needs the RBAC role in your subscription.
Navigate to the Azure portal -> Subscription -> add your service principal as a Contributor/Owner role in the subscription like below.
4.In the linked service, configure it like below, fix them with the values got from step 2.
Don't forget to replace the {subscriptionId} in the Base URL.
https://management.azure.com/subscriptions/{subscriptionId}/resources?api-version=2020-06-01
5.Test the linked service with a copy activity, it works fine.
Steps to use managed identity to auth:
1.Make sure your data factory has enabled the MSI(managed identity), if you create it in the portal or powershell, MSI will be enabled automatically, don't worry about that.
2.Navigate to the Subsctiption in the portal, add the role to the MSI like step 3 in Steps to use service principal to auth, just search for your ADF name in the bar, the MSI is essentially a service principal with the same name of your ADF, which is managed by azure.
3.Then in the linked service, just change it like below.
At last, answer your questions.
Can we actually use a service principal / app to store our OAuth2 tokens? If so, will these be automatically refreshed within our app?
As I mentioned, it is not a good idea, just use the service principal/MSI to auth like the steps above.
How do we assign the correct privileges / authorizations to our app that it can use this (external) API?
To use the Azure REST API, just assign the RBAC roles like above, specify the correct AAD resource e.g. https://management.azure.com in this case.
Is the additional logic with HTTP calls within Azure Data Factory pipeline needed to update the tokens or can these apps / service principals handle this?
No need to do other steps, when you use the configuration above, essentially it will use the client credential flow to get the token in the background for you automatically, then use the token to call the API.
We are having an Azure AD Protect API which is hosted on prem. We have a requirement to call this API from Logic App. We have currently created or registered a new client App in App Registration for this logic App and have provided the necessary permissions and have called API passing the Bearer Token.
My question, is there a way we can leverage Managed Identity for Logic App (either User Assigned or System Assigned) for calling the API?
Yes there is.
I wrote an article on the topic (though it is not specific to Logic Apps): https://joonasw.net/view/calling-your-apis-with-aad-msi-using-app-permissions.
You will need to create an appRoleAssignment that gives an application permission to your managed identity service principal.
To do this, we must use PowerShell or Microsoft Graph API.
With Azure AD PowerShell, we can do this:
Connect-AzureAD
New-AzureADServiceAppRoleAssignment -ObjectId $miSpId -Id $appRoleId -PrincipalId $miSpId -ResourceId $targetApiSpId
There we have 3 arguments you need to find:
miSpId: The objectId of the Managed Identity (easy, we can find this from the Identity blade in the Logic App)
appRoleId: The id of the appRole defined on your API's manifest (this should be easy to find as well, it's in your API's manifest)
If you haven't defined an appRole (app permission) on your API, you will need to do that first (https://joonasw.net/view/defining-permissions-and-roles-in-aad)
targetApiSpId: The objectId of the target API service principal (this one you can get by going to Enterprise Applications and finding your API there)
I'm trying to call an Azure function from an API Management instance by using Managed Identity.
I have set a System Managed Identity to my APIM instance.
I have granted the Contributor role to this identity on the Azure Function App.
I have also change the App Service Authentication to AD.
Now I'm trying to call the function from an API.
I have two issues:
First One: when I use the authentication-managed-identity policy to get a token, I got an error when I use the audience https://myfunctionapp.azurewebsites.net. AD tells me that this app is not registered in the tenant
Second: If I retrieve a token for https://management.azure.com, I got a token but I received a 401 Unauthorized error from the Azure Function.
Maybe I'm just trying to get a token on the wrong audience, but unfortunately the audience of functions is not listed in the document (for service bus for example, there is a common URI to use, also for KeyVault, ...).
I think that I probably missed something in the picture...
Thanks.
You need to use the authentication-managed-identity policy to authenticate with a backend service using the managed identity of the API Management service.
https://learn.microsoft.com/en-us/azure/api-management/api-management-authentication-policies#ManagedIdentity
EDIT
1-In your APIM application on Azure AD,
grab the Application ID assigned for enterprise application.
2-Then go to Platform features in your Azure Function App, and click on Authentication / Authorization.
3-Select Azure Active Directory as the authentication provider, and the management mode "express".
4-Back to authentication-managed-identity policy, set the Application ID from step 1 as the resource.
you need to add the url in apim required resource. If you're planning to use delegated flow. To check if the issue is with the url registration you can use the AppId instead. This will at least tell you if the token can be retrieved.
I want to get the health and other resource details of a particular Azure Account or Subscription using these API's
https://learn.microsoft.com/en-us/rest/api/resourcehealth/availabilitystatuses/listbysubscriptionid
When i do TryIt on the web page it works, but If i want to do it using say PostMan or programatically, how do i generate the Authorization key, I have seen docs to create Authorization Key using "App Registrations", but i dont have any WebApp here, All i want to do is get the details of a particular account or subscription using Azure provided API calls and using any AD user with proper roles for authentication.
This link provides some details but then i dont have a clientid here, since i dont have any webapp
https://msdn.microsoft.com/en-gb/library/azure/dn645543.aspx
Please let me know if anyone has tried doing this.
Thanks
You have to register an app in Azure AD.
This does not need to be an actual "Web app".
You are registering a service principal (you can think of it as a service account).
After registering the app (with type Web App/API), generate a Key for it.
Write down the Application Id (Client Id) and the key (Client Secret).
Then give the service principal access through the Access Control (IAM) section on the subscription/resource group/resource where you want to give the app access to.
You can then follow the instructions here to generate the access token: https://msdn.microsoft.com/en-gb/library/azure/dn645543.aspx.
Remember to use https://management.azure.com/ as the resource since you are calling the ARM API.
I am trying to implement KeyVault managed Storage Account in Azure to rotate storage keys using KeyVault. I did follow the documentation, which uses both "ServicePrincipalID" and "UserPrincipalID", but in my case i am provisioning my resources and implementing all the steps involved using my service principal (as we deploy using VSTS with service principal) and using "ServicePrincipalID" as ObjectID in place of "UserPrincipalID" (as there is no user intervention during provisioning and post-provisioning process). I did give my service principal "Owner" role and all required permissions for keyvault to access storage. But when i do "Add-AzureKeyVaultManagedStorageAccount" i get the below error which says "KeyVault is unable to perform the action on behalf of the caller". So i am not sure what access i am still missing, even after making my principal as Owner. Please find my screenshots below for more details. Would be glad to hear any suggestions to cross this hurdle.
Error
KeyVault details
Thanks
Chaitanya Alladi.
i get the below error which says "KeyVault is unable to perform the action on behalf of the caller". So i am not sure what access i am still missing, even after making my principal as Owner.
Unfortunly, we can't do that with service principle now.
AAD doesn't support get OBO(OnBehalfOf) token for service principle caller tokens.
We need to use the user credentials instead of Service Principal credentials. There are some operations that are only possible on behalf of the user and not Service Principal when it comes to storage account keys as of now.