I am trying to query with an app ID all the resources a user has. My current implementation is to get all the resources my app has access to, and then query the RBAC of each one of those resources to see if the user has access. It seems to be way too many calls for something it can be done for my current user using Azure Resource Graph. Is there a way to use Azure Resource Graph but specify which user I want to get the resources for (assuming my app has reader access to all resources in the tenant)?
From your description, want you need to find is the role assignments in your subscription, its resource type is Microsoft.Authorization/roleAssignments, which is not included in the Azure Resource Graph.
Your option is to use the REST API - Role Assignments - List, filter with the ObjectId of the user in Azure AD. To get the access token to call the REST API with the AD App(the AppId you mentioned), you need to use the client credential flow, refer to this link.
Sample:
Check the scope in the response, they are the resources the user can access.
GET https://management.azure.com/subscriptions/<subscription-id>/providers/Microsoft.Authorization/roleAssignments?$filter=principalId eq '<object-id>'&api-version=2018-09-01-preview
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.
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.
I have created an apim gateway, now i need to add some users and they only have rights to do some specific operations to the API's, like some users only have the right to execute GET requests, some users only have the right to execute POST requests etc. How can i achieve that?
Role-based access control helps that, please see the below extract from the URL
How RBAC determines if a user has access to a resource
The following are the high-level steps that RBAC uses to determine if you have access to a resource on the management plane. This is helpful to understand if you are trying to troubleshoot an access issue.
A user (or service principal) acquires a token for Azure Resource Manager.
The token includes the user's group memberships (including transitive group memberships).
The user makes a REST API call to Azure Resource Manager with the token attached.
Azure Resource Manager retrieves all the role assignments and deny assignments that apply to the resource upon which the action is being taken.
Azure Resource Manager narrows the role assignments that apply to this user or their group and determines what roles the user has for this resource.
Azure Resource Manager determines if the action in the API call is included in the roles the user has for this resource.
If the user doesn’t have a role with the action at the requested scope, access is not granted. Otherwise, Azure Resource Manager checks if a deny assignment applies.
If a deny assignment applies, access is blocked. Otherwise access is granted.
APIM runtime part does not rely on ARM RBAC. Instead APIM maintains its own user database. Scenario you describe is achievable by splitting your operations into multiple APIs, and controlling access to those APIs via subscriptions.
All that is built-in into APIM, so it's simple to setup, but may be cumbersome to maintain. If that is the case, then your next option is to use policies and policy expressions. Look at choose policy, it allows you to conditionally stop request processing (return-response policy). Of course that requires you to be able to make authorization decision purely based on what is available in request, i.e. path, headers, user id e.t.c.
I cases like this using validate-jwt policy is preferable since it allows you to rely on a limited set of claims in provided identity, rather than hard-coded list of user ids/names. But it does require you to have an JWT token with every request.
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.
Is it possible to assign an application (as an Application or Service Principal) to a group programatically, via the graph client or API? (Including the app user credentials needed to allow access of the members of the group to the app)
I searched everywhere and couldn't find documentation for it.
Thanks
No, 'Applications' in Azure AD are used to segment authorization and settings within Azure AD. It creates a trust between Azure AD and your application. The Application is not a User.
Users are Azure AD entities that have identity and can be authorized to access resources (like an Application). Users can be added to groups. See the below link for the Azure AD graph API documentation:
https://msdn.microsoft.com/Library/Azure/Ad/Graph/api/groups-operations#AddGroupMembers
And the documentation on what a user entity looks like:
https://msdn.microsoft.com/Library/Azure/Ad/Graph/api/entity-and-complex-type-reference#UserEntity
Thanks for the answer emseetea, but we do have a little more than that.
Back to the original question - can you programmatically "assign a group to an application". The answer is yes, using appRoleAssignments on the service principal. The service principal represents an application instance, that typically gets provisioned as part of a consent grant. On this tenant specific app instance (service principal) you can attach tenant specific permissions and policy. Permissions get created as part of consent, but you can also programmatically assign an application role (defined by the application) to a user or group. If no application role is assigned, then you can make a "default" assignment. You can find a little more on this topic here http://blogs.msdn.com/b/aadgraphteam/archive/2014/12/12/announcing-the-new-version-of-graph-api-api-version-1-5.aspx which describes a little about this with some sample REST API calls.
This same operation is also possible through the client library. You can take a look at https://github.com/Azure-Samples/active-directory-dotnet-graphapi-console. Look at the section titled "#region Assign Direct Permission". This shows how to assign an app role to a user. You can do the same thing on a group too. If your app doesn't specify any app roles, set the appRoleAssignment.Id to a zero GUID.
Hope this helps,