I want to create an Azure Function that accesses Cosmos DB Containers and Key Vault Scopes. Function calls require Active Directory sign in and users are granted access to resources via Groups.
Azure resources should be accessed or denied based on the signed in user's permissions or group memberships.
How can the Azure Function access other Azure Resources on behalf of the authenticated caller?
It's pretty complex unfortunately, you'd need to have a new OAuth2 access token scoped to cosmosdb resource to be able to access it.
Please check OAuth2 On-Behalf-Of flow:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
When I used it 2 years ago, there was no SDK support for this flow, I simply used http request against https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
In your case, you would also have to add https://cosmos.azure.com/user_impersonation delegated API permission to your app registration and users will be asked for a consent when they try to access your API.
Related
I have seen many examples of how to use RBAC and request a bearer token using a registered app for which you give access to your blob storage account or container.
What I need instead is to give access to a specific group of users in an AzureAD group and now request an access token as an individual user, without any application (clietn_id) in between.
Would someone help/guide me to achieving that with a tool like postman for example.
Thanks a lot in advance!
Azure AD tokens are requested trough registered or enterprise apps. You will need a client id in between.
If you want to authenticate a user programmatically you will need to implement the ROPC flow. Click here for the Postman request. Keep in mind ROPC is not recommended, do not support personal accounts or passwordless logins, MFA and others.
Remember to Grant your registered app permissions to Azure Storage and set the scope parameter to https://storage.azure.com/user_impersonation in Postman.
I need to receive list of user's subscriptions using service principal.
For user which has token now it's easy - A GET call to https://management.azure.com/subscriptions?api-version=<API_version>
But how is ti possible for any user in Azure AD, if my service principal has enough permissions in Azure AD?
Thanks in advance!
You could not use the service principal to get the user's subscriptions(i.e. the subscriptions that the user can access in one tenant) via this REST API.
When you use the REST API Subscriptions - List, it will make the request depends on the access token passed, if you use the service principal to get the token, you can just get the subscriptions that the service principal can access, not the user.
In this case, your option here is to use the auth code flow or implicit grant flow(the Try it button in the doc use it, not recommended) to get the token, then use the token to call the REST API to list the subscriptions that the user can access.
I am trying to find security best practice on App permissions in the context of azure resource management.
Currently, there is only one permission listed for management.azure.com and it is
management.azure.com/user_impersonation (preview). This delegated user impersonation can be a serious problem and it can led to account takeover by malicious app.
Think about a scenario where a user with global administrator role consent and authorize an access token to the app. App can use the token and do whatever it wants with the azure tenant.
Another scenario where a privileged user assigned contributor role to multiple subscriptions. Token authorized by this user can be misused by app to modify resources in any of the subscriptions.
Unlike graph (graph.microsoft.com) api where you can handpick the permission (user.read), resource management api has only one option - user_impersonation!
You may argue why would a privileged user authorize the action but people make mistakes. Our job is to stop or minimize such risk by design. So, what's the best way to allow app to manage resources in azure and minimize the security risk?
Thanks to #juunas for outline and tips. Thanks to #Gaurav for attempting to address my question. I was able to modify azure resources on a subscription without having to grant user_impersonation on management.azure.com api. Here are the steps-
1) Register an app (TestPermissions in my case)
2) Add API Permissions (optional). You don't need to add management.azure.com.
3) Go the Azure resource (subscription, resource group or management group level based on your requirement) and add IAM/RBAC role to the registered app. I assigned Contributor role to TestPermissions app at the subscription level.
4) Request a oauth2 access token following client credential grant flow. You can provide client_id and client_secret in the body of the POST request or you can provide it as Authorization Basic base64 encoded header (that's what I did). Save the access token for future use (until it expires).
Note: I could not add multiple audience (scope) at the same time. If you would like to get a token for graph api, you can request a separate token by changing the scope to http://graph.microsoft.com/.default
5) Use the access token captured in the previous step to interact with azure resource manager. You will need to add the jwt bearer token in the Authorization header (not shown here) on every request to https://management.azure.com. In this example, I am creating a new resource group named TestCreateRG003 to one of my Pay-as-you-go subscription.
6) Let's validate/verify that the resource is created or updated in Azure. Bingo, there they are! App can read/modify (based on RBAC) azure resources w/o having to grant impersonation permission.
It is true that by granting that permission you are allowing the app to act as you, with all the permissions that brings.
The main way I've seen used when limitations are desired is that you:
Register an app in your Azure AD
Grant the service principal the necessary roles (e.g. Reader on specific resources)
Set the tenant id, client id, client secret etc. in the app
This of course requires that the app itself supports this approach.
If it only allows usage through impersonation, then you'll need to either trust or not use it.
Let me see if I can answer this question.
When a user requests a token for management.azure.com, all is done at that time is that the user has permission to execute Azure ARM API. That doesn't mean that they can do everything that's possible with Azure ARM API.
The things that they can do is controlled by Azure Role Based Access Control (RBAC). So if a user is in the Reader role, the token got on behalf of the user can only read information about resources in their Azure Subscription. They will not be allowed to create, update or delete resources in their Azure Subscription.
What you will need to do is grant users appropriate RBAC role to minimize the risks of misuse.
We are working on WEB APIs and want to integrate Azure AD for AuthN and AuthZ. We have successfully integrated the same. We have created enterprise applications, custom roles, assigned users for the same.
Now we need to allow access to APIs with AWS like keys (Secret / Access keys). Individual user can generate their own keys and store those in Azure AD so that when those keys are used, user can be authenticated.
I didn't find any way to achieve this using Azure AD. Any suggestions around same are welcome.
Meanwhile I have gone through custom store for keys. Please refer link : https://www.codeproject.com/Articles/1228892/Securing-ASP-NET-CORE-Web-API-using-Custom-API-Key
Thanks in advance.
Azure AD authentication uses tokens.
So any app wishing to call your API must authenticate with AAD and acquire a token for the API.
If these users are making apps within your organisation, then they can register their app in your AAD and require access to your API. They will create and manage their own keys.
If on the other hand these users are making an app for another organisation, you'll have to make your API a multi-tenant app.
And you'll need to have an on-boarding page in your API through which you will redirect their admin/user to the AAD login page, where they will consent to any permissions your API requires.
After this a service principal is created in their tenant.
Then they can register their client apps and require access to your API.
They will have full control which permissions they want to assign to each app, what roles to give to users etc. But of course the tokens will contain their tenant id so you can filter access on that.
I create an Azure APIM instance, register it as an app in AD and then create a OAUTH2.0 server under APIM which is setup using the clientid/secret key of above registered app. I make a dummy API under this APIM and then protect it with this OAUTH2.0 server. I also add a JWT policy on my api to look for a token and authenticate against the tenant-id.(No claims mentioned).
Now lets say, i have a Customer (ABC) and for that i register another app in AD and create its Clientid/secret. Customer generates its token with the help of token endpoint (this endpoint is given under Endpoints tab of AD app registration option). Customer calls the API with this token and it works.
Issue: I didn't give any permission for my APIM App in AD to the Client App in AD but it still works, which essentially means that any Clientid/secret from any app registered in AD will go through my JWT policy of the API. Because it is just validating against the tenantid. How can we stop this and make sure that it works only for a customer to which permissions is given.
This is one of the major things I mentioned in my recent article: https://joonasw.net/view/azure-ad-authentication-aspnet-core-api-part-1.
Any app of type Web App/API in Azure AD can get a valid access token for any API in that Azure AD tenant.
Even before any permissions are given to it.
This is kind of a "feature" I guess.
Quote from the article:
If you only require an authenticated user, any confidential client in your Azure AD can acquire an access token for your API and call it. So it is important that you implement the user_impersonation scope check at minimum.
Now since your caller will call your API as itself, you need to implement an App Permission.
You can see how those are defined here: https://joonasw.net/view/defining-permissions-and-roles-in-aad.
Then implement a check that ensures the roles claim contains the value of the app permission you defined.
The claim will be a string array, so some kind of contains check needs to be made.
This will then require that this app permission is granted the caller before they can make the call successfully.
If you also want to allow delegated calls (i.e. calls on behalf of a user),
then add an optional requirement for the user_impersonation scope.
Those are stored in a single string claim (scp), space-separated.
So for that one you'll need a contains check on the string.