azure active directory
31 TopicsDevelop Custom Engine Agent to Microsoft 365 Copilot Chat with pro-code
There are some great articles that explain how to integrate an MCP server built on Azure with a declarative agent created using Microsoft Copilot Studio. These approaches aim to extend the agent’s capabilities by supplying it with tools, rather than defining a fixed role. Here were some of the challenges w encountered: The agent's behavior can only be tested through the Copilot Studio web interface, which isn't ideal for iterative development. You don’t have control over which LLM is used as the orchestrator—for example, there's no way to specify GPT-4o. The agent's responses don’t always behave the same as they would if you were prompting the LLM directly. These limitations got me thinking: why not build the entire agent myself? At the same time, I still wanted to take advantage of the familiar Microsoft 365 Copilot interface on the frontend. As I explored further, I discovered that the Microsoft 365 Copilot SDK makes it possible to bring in your own custom-built agent.1.8KViews12likes1CommentSuperfast using Web App and Managed Identity to invoke Function App triggers
TOC Introduction Setup References 1. Introduction Many enterprises prefer not to use App Keys to invoke Function App triggers, as they are concerned that these fixed strings might be exposed. This method allows you to invoke Function App triggers using Managed Identity for enhanced security. I will provide examples in both Bash and Node.js. 2. Setup 1. Create a Linux Python 3.11 Function App 1.1. Configure Authentication to block unauthenticated callers while allowing the Web App’s Managed Identity to authenticate. Identity Provider Microsoft Choose a tenant for your application and it's users Workforce Configuration App registration type Create Name [automatically generated] Client Secret expiration [fit-in your business purpose] Supported Account Type Any Microsoft Entra Directory - Multi-Tenant Client application requirement Allow requests from any application Identity requirement Allow requests from any identity Tenant requirement Use default restrictions based on issuer Token store [checked] 1.2. Create an anonymous trigger. Since your app is already protected by App Registration, additional Function App-level protection is unnecessary; otherwise, you will need a Function Key to trigger it. 1.3. Once the Function App is configured, try accessing the endpoint directly—you should receive a 401 Unauthorized error, confirming that triggers cannot be accessed without proper Managed Identity authorization. 1.4. After making these changes, wait 10 minutes for the settings to take effect. 2. Create a Linux Node.js 20 Web App and Obtain an Access Token and Invoke the Function App Trigger Using Web App (Bash Example) 2.1. Enable System Assigned Managed Identity in the Web App settings. 2.2. Open Kudu SSH Console for the Web App. 2.3. Run the following commands, making the necessary modifications: subscriptionsID → Replace with your Subscription ID. resourceGroupsID → Replace with your Resource Group ID. application_id_uri → Replace with the Application ID URI from your Function App’s App Registration. https://az-9640-faapp.azurewebsites.net/api/test_trigger → Replace with the corresponding Function App trigger URL. # Please setup the target resource to yours subscriptionsID="01d39075-XXXX-XXXX-XXXX-XXXXXXXXXXXX" resourceGroupsID="XXXX" # Variable Setting (No need to change) identityEndpoint="$IDENTITY_ENDPOINT" identityHeader="$IDENTITY_HEADER" application_id_uri="api://9c0012ad-XXXX-XXXX-XXXX-XXXXXXXXXXXX" # Install necessary tool apt install -y jq # Get Access Token tokenUri="${identityEndpoint}?resource=${application_id_uri}&api-version=2019-08-01" accessToken=$(curl -s -H "Metadata: true" -H "X-IDENTITY-HEADER: $identityHeader" "$tokenUri" | jq -r '.access_token') echo "Access Token: $accessToken" # Run Trigger response=$(curl -s -o response.json -w "%{http_code}" -X GET "https://az-9640-myfa.azurewebsites.net/api/my_test_trigger" -H "Authorization: Bearer $accessToken") echo "HTTP Status Code: $response" echo "Response Body:" cat response.json 2.4. If everything is set up correctly, you should see a successful invocation result. 3. Invoke the Function App Trigger Using Web App (nodejs Example) I have also provide my example, which you can modify accordingly and save it to /home/site/wwwroot/callFunctionApp.js and run it cd /home/site/wwwroot/ vi callFunctionApp.js npm init -y npm install azure/identity axios node callFunctionApp.js // callFunctionApp.js const { DefaultAzureCredential } = require("@azure/identity"); const axios = require("axios"); async function callFunctionApp() { try { const applicationIdUri = "api://9c0012ad-XXXX-XXXX-XXXX-XXXXXXXXXXXX"; // Change here const credential = new DefaultAzureCredential(); console.log("Requesting token..."); const tokenResponse = await credential.getToken(applicationIdUri); if (!tokenResponse || !tokenResponse.token) { throw new Error("Failed to acquire access token"); } const accessToken = tokenResponse.token; console.log("Token acquired:", accessToken); const apiUrl = "https://az-9640-myfa.azurewebsites.net/api/my_test_trigger"; // Change here console.log("Calling the API now..."); const response = await axios.get(apiUrl, { headers: { Authorization: `Bearer ${accessToken}`, }, }); console.log("HTTP Status Code:", response.status); console.log("Response Body:", response.data); } catch (error) { console.error("Failed to call the function", error.response ? error.response.data : error.message); } } callFunctionApp(); Below is my execution result: 3. References Tutorial: Managed Identity to Invoke Azure Functions | Microsoft Learn How to Invoke Azure Function App with Managed Identity | by Krizzia 🤖 | Medium Configure Microsoft Entra authentication - Azure App Service | Microsoft Learn900Views1like2CommentsUse managed identity instead of AzureWebJobsStorage to connect a function app to a storage account
In a function app, usually we use appsetting AzureWebJobsStorage to connect to storage. This blog shows you how to configure a function app using Azure Active Directory identities instead of secrets or connection strings, where possible. Using identities helps you avoid accidentally leaking sensitive secrets and can provide better visibility into how data is accessed. This will not work if the storage account is in a sovereign cloud or has a custom DNS. IMPORTANT! When running in a Consumption or Elastic Premium plan, your app uses the WEBSITE_AZUREFILESCONNECTIONSTRING and WEBSITE_CONTENTSHARE settings when connecting to Azure Files on the storage account used by your function app. Azure Files doesn't support using managed identity when accessing the file share. That is to say, if your functio app is running on Consumption/EP, plan, you can only delete and recreate function app on app service plan to avoid using File Share. For more information, see Azure Files supported authentication scenarios Below are the steps to do configuration. 1. Enable system assigned identity in your function app and save it. 2. Give storage access to your function app. Search for Storage Blob Data Owner, select it. 3. If you configure a blob-triggered function app, repeat the step 2 to add Storage Account Contributor and Storage Queue Data Contributor roles which will be used for blob trigger. 4. Return to Access Control (IAM), click Role assignments, search for your function app name to confirm the roles are added successfully. 5. Navigate to your function app. Select Configuration and edit AzureWebJobsStorage. Change the name to AzureWebJobsStorage__accountname. Change the value to your storage account name. (The new setting uses a double underscore ( __ ), which is a special character in application settings.) 6. Delete the previous AzureWebJobsStorage. Then you will find your function app still works fine.89KViews9likes56CommentsAzure Kubernetes Service Baseline - The Hard Way, Third time's a charm
1 Access management Azure Kubernetes Service (AKS) supports Microsoft Entra ID integration, which allows you to control access to your cluster resources using Azure role-based access control (RBAC). In this tutorial, you will learn how to integrate AKS with Microsoft Entra ID and assign different roles and permissions to three types of users: An admin user, who will have full access to the AKS cluster and its resources. A backend ops team, who will be responsible for managing the backend application deployed in the AKS cluster. They will only have access to the backend namespace and the resources within it. A frontend ops team, who will be responsible for managing the frontend application deployed in the AKS cluster. They will only have access to the frontend namespace and the resources within it. By following this tutorial, you will be able to implement the least privilege access model, which means that each user or group will only have the minimum permissions required to perform their tasks. 1.1 Introduction In this third part of the blog series, you will learn how to: Harden your AKS cluster. - Update an existing AKS cluster to support Microsoft Entra ID integration enabled. Create a Microsoft Entra ID admin group and assign it the Azure Kubernetes Service Cluster Admin Role. Create a Microsoft Entra ID backend ops group and assign it the Azure Kubernetes Service Cluster User Role. Create a Microsoft Entra ID frontend ops group and assign it the Azure Kubernetes Service Cluster User Role. Create Users in Microsoft Entra ID Create role bindings to grant access to the backend ops group and the frontend ops group to their respective namespaces. Test the access of each user type by logging in with different credentials and running kubectl commands. 1.2 Prequisities: This section outlines the recommended prerequisites for setting up Microsoft entra ID with AKS. Highly recommended to complete Azure Kubernetes Service Baseline - The Hard Way here! or follow the Microsoft official documentation for a quick start here! Note that you will need to create 2 namespaces in kubernetes one called frontend and the second one called backend. 1.3 Target Architecture Throughout this article, this is the target architecture we will aim to create: all procedures will be conducted by using Azure CLI. The current architecture can be visualized as followed: 1.4 Deployment 1.4.1 Prepare Environment Variables This code defines the environment variables for the resources that you will create later in the tutorial. Note: Ensure environment variable $STUDENT_NAME and placeholder <TENANT SUB DOMAIN NAME>is set before adding the code below. # Define the name of the admin group ADMIN_GROUP='ClusterAdminGroup-'${STUDENT_NAME} # Define the name of the frontend operations group OPS_FE_GROUP='Ops_Fronted_team-'${STUDENT_NAME} # Define the name of the backend operations group OPS_BE_GROUP='Ops_Backend_team-'${STUDENT_NAME} # Define the Azure AD UPN (User Principal Name) for the frontend operations user AAD_OPS_FE_UPN='opsfe-'${STUDENT_NAME}'@<SUB DOMAIN TENANT NAME HERE>.onmicrosoft.com' # Define the display name for the frontend operations user AAD_OPS_FE_DISPLAY_NAME='Frontend-'${STUDENT_NAME} # Placeholder for the frontend operations user password AAD_OPS_FE_PW=<ENTER USER PASSWORD> # Define the Azure AD UPN for the backend operations user AAD_OPS_BE_UPN='opsbe-'${STUDENT_NAME}'@<SUB DOMAIN TENANT NAME HERE>.onmicrosoft.com' # Define the display name for the backend operations user AAD_OPS_BE_DISPLAY_NAME='Backend-'${STUDENT_NAME} # Placeholder for the backend operations user password AAD_OPS_BE_PW=<ENTER USER PASSWORD> # Define the Azure AD UPN for the cluster admin user AAD_ADMIN_UPN='clusteradmin'${STUDENT_NAME}'@<SUB DOMAIN TENANT NAME HERE>.onmicrosoft.com' # Placeholder for the cluster admin user password AAD_ADMIN_PW=<ENTER USER PASSWORD> # Define the display name for the cluster admin user AAD_ADMIN_DISPLAY_NAME='Admin-'${STUDENT_NAME} 1.4.2 Create Microsoft Entra ID Security Groups We will now start by creating 3 security groups for respective team. Create the security group for Cluster Admins az ad group create --display-name $ADMIN_GROUP --mail-nickname $ADMIN_GROUP 2. Create the security group for Application Operations Frontend Team az ad group create --display-name $OPS_FE_GROUP --mail-nickname $OPS_FE_GROUP 3. Create the security group for Application Operations Backend Team az ad group create --display-name $OPS_BE_GROUP --mail-nickname $OPS_BE_GROUP Current architecture can now be illustrated as follows: 1.4.3 Integrate AKS with Microsoft Entra ID 1. Lets update our existing AKS cluster to support Microsoft Entra ID integration, and configure a cluster admin group, and disable local admin accounts in AKS, as this will prevent anyone from using the --admin switch to get full cluster credentials. az aks update -g $SPOKE_RG -n $AKS_CLUSTER_NAME-${STUDENT_NAME} --enable-azure-rbac --enable-aad --disable-local-accounts Current architecture can now be described as follows: 1.4.4 Scope and Role Assignment for Security Groups This chapter describes how to create the scope for the operation teams to perform their daily tasks. The scope is based on the AKS resource ID and a fixed path in AKS, which is /namespaces/. The scope will assign the Application Operations Frontend Team to the frontend namespace and the Application Operation Backend Team to the backend namespace. Lets start by constructing the scope for the operations team. AKS_BACKEND_NAMESPACE='/namespaces/backend' AKS_FRONTEND_NAMESPACE='/namespaces/frontend' AKS_RESOURCE_ID=$(az aks show -g $SPOKE_RG -n $AKS_CLUSTER_NAME-${STUDENT_NAME} --query 'id' --output tsv) 2. Lets fetch the Object ID of the operations teams and admin security groups. Application Operation Frontend Team. FE_GROUP_OBJECT_ID=$(az ad group show --group $OPS_FE_GROUP --query 'id' --output tsv) Application Operation Backend Team. BE_GROUP_OBJECT_ID=$(az ad group show --group $OPS_BE_GROUP --query 'id' --output tsv Admin. ADMIN_GROUP_OBJECT_ID=$(az ad group show --group $ADMIN_GROUP --query 'id' --output tsv) 3) This commands will grant the Application Operations Frontend Team group users the permissions to download the credential for AKS, and only operate within given namespace. az role assignment create --assignee $FE_GROUP_OBJECT_ID --role "Azure Kubernetes Service RBAC Writer" --scope ${AKS_RESOURCE_ID}${AKS_FRONTEND_NAMESPACE} az role assignment create --assignee $FE_GROUP_OBJECT_ID --role "Azure Kubernetes Service Cluster User Role" --scope ${AKS_RESOURCE_ID} 4) This commands will grant the Application Operations Backend Team group users the permissions to download the credential for AKS, and only operate within given namespace. az role assignment create --assignee $BE_GROUP_OBJECT_ID --role "Azure Kubernetes Service RBAC Writer" --scope ${AKS_RESOURCE_ID}${AKS_BACKEND_NAMESPACE} az role assignment create --assignee $BE_GROUP_OBJECT_ID --role "Azure Kubernetes Service Cluster User Role" --scope ${AKS_RESOURCE_ID} 5) This command will grant the Admin group users the permissions to connect to and manage all aspects of the AKS cluster. az role assignment create --assignee $ADMIN_GROUP_OBJECT_ID --role "Azure Kubernetes Service RBAC Cluster Admin" --scope ${AKS_RESOURCE_ID} Current architecture can now be described as follows: 1.4.5 Create Users and Assign them to Security Groups. This exercise will guide you through the steps of creating three users and adding them to their corresponding security groups. Create the Admin user. az ad user create --display-name $AAD_ADMIN_DISPLAY_NAME --user-principal-name $AAD_ADMIN_UPN --password $AAD_ADMIN_PW 2. Assign the admin user to admin group for the AKS cluster. First identify the object id of the user as we will need this number to assign the user to the admin group. ADMIN_USER_OBJECT_ID=$(az ad user show --id $AAD_ADMIN_UPN --query 'id' --output tsv) 3. Assign the user to the admin security group. az ad group member add --group $ADMIN_GROUP --member-id $ADMIN_USER_OBJECT_ID 4. Create the frontend operations user. az ad user create --display-name $AAD_OPS_FE_DISPLAY_NAME --user-principal-name $AAD_OPS_FE_UPN --password $AAD_OPS_FE_PW 5. Assign the frontend operations user to frontend security group for the AKS cluster. First identify the object id of the user as we will need this number to assign the user to the frontend security group. FE_USER_OBJECT_ID=$(az ad user show --id $AAD_OPS_FE_UPN --query 'id' --output tsv) 6. Assign the user to the frontend security group. az ad group member add --group $OPS_FE_GROUP --member-id $FE_USER_OBJECT_ID 7. Create the backend operations user. az ad user create --display-name $AAD_OPS_BE_DISPLAY_NAME --user-principal-name $AAD_OPS_BE_UPN --password $AAD_OPS_BE_PW 8. Assign the backend operations user to backend security group for the AKS cluster. First identify the object id of the user as we will need this number to assign the user to the backend security group. BE_USER_OBJECT_ID=$(az ad user show --id $AAD_OPS_BE_UPN --query 'id' --output tsv) 9. Assign the user to the backend security group. az ad group member add --group $OPS_BE_GROUP --member-id $BE_USER_OBJECT_ID Current architecture can now be described as follows: 1.4.6 Validate your deployment in the Azure portal. Navigate to the Azure portal at https://portal.azure.com and enter your login credentials. Once logged in, on your top left hand side, click on the portal menu (three strips). From the menu list click on Microsoft Entra ID. On your left hand side menu under Manage click on Users. Validate that your users are created, there shall be three users, each user name shall end with your student name. On the top menu bar click on the Users link. On your left hand side menu under Manage click on Groups. Ensure you have three groups as depicted in the picture, the group names should end with your student name. Click on security group called Ops_Backend_team-YOUR STUDENT NAME. On your left hand side menu click on Members, verify that your user Backend-YOUR STUDENT NAME is assigned. On your left hand side menu click on Azure role Assignments, from the drop down menu select your subscription. Ensure the following roles are assigned to the group: Azure Kubernetes service Cluster User Role assigned on the Cluster level and Azure Kubernetes Service RBAC Writer assigned on the namespace level called backend. 11.On the top menu bar click on Groups link. Repeat step 7 - 11 for Ops_Frontend_team-YOUR STUDENT NAME and ClusterAdminGroup-YOUR STUDENT NAME 1.4.7 Validate the Access for the Different Users. This section will demonstrate how to connect to the AKS cluster from the jumpbox using the user account defined in Microsoft Entra ID. Note: If you deployed your AKS cluster using the quick start method We will check two things: first, that we can successfully connect to the cluster; and second, that the Operations teams have access only to their own namespaces, while the Admin has full access to the cluster. Navigate to the Azure portal at https://portal.azure.com and enter your login credentials. Once logged in, locate and select your rg-hub where the Jumpbox has been deployed. Within your resource group, find and click on the Jumpbox VM. In the left-hand side menu, under the Operations section, select Bastion. Enter the credentials for the Jumpbox VM and verify that you can log in successfully. First remove the existing stored configuration that you have previously downloaded with Azure CLI and kubectl. From the Jumpbox VM execute the following commands: rm -R .azure/ rm -R .kube/ Note: The .azure and .kube directories store configuration files for Azure and Kubernetes, respectively, for your user account. Removing these files triggers a login prompt, allowing you to re-authenticate with different credentials. 7. Retrieve the username and password for Frontend user. Important: Retrieve the username and password from your local shell, and not the shell from Jumpbox VM. echo $AAD_OPS_FE_UPN echo $AAD_OPS_FE_PW 8. From the Jumpbox VM initiate the authentication process. az login Example output: bash azureuser@Jumpbox-VM:~$ az login To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXX to authenticate. 9. Open a new tab in your web browser and access https://microsoft.com/devicelogin. Enter the generated code, and press Next 10. You will be prompted with an authentication window asking which user you want to login with select Use another account and supply the username in the AAD_OPS_FE_UPN variable and password from variable AAD_OPS_FE_PW and then press Next. Note: When you authenticate with a user for the first time, you will be prompted by Microsoft Authenticator to set up Multi-Factor Authentication (MFA). Choose "I want to setup a different method" option from the drop-down menu, and select Phone, supply your phone number, and receive a one-time passcode to authenticate to Azure with your user account. 11. From the Jumpbox VM download AKS cluster credential. SPOKE_RG=rg-spoke STUDENT_NAME= AKS_CLUSTER_NAME=private-aks az aks get-credentials --resource-group $SPOKE_RG --name $AKS_CLUSTER_NAME-${STUDENT_NAME} You should see a similar output as illustrated below: bash azureuser@Jumpbox-VM:~$ az aks get-credentials --resource-group $SPOKE_RG --name $AKS_CLUSTER_NAME-${STUDENT_NAME} Merged "private-aks" as current context in /home/azureuser/.kube/config azureuser@Jumpbox-VM:~$ 12. You should be able to list all pods in namespace frontend. You will now be prompted to authenticate your user again, as this time it will validate your newly created user permissions within the AKS cluster. Ensure you login with the user you created i.e $AAD_OPS_FE_UPN, and not your company email address. kubectl get po -n frontend Example output: azureuser@Jumpbox-VM:~$ kubectl get po -n frontend To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXX to authenticate. NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 89m 13. Try to list pods in default namespace bash kubectl get pods Example output: bash azureuser@Jumpbox-VM:~$ kubectl get po Error from server (Forbidden): pods is forbidden: User "opsfe-test@xxxxxxxxxx.onmicrosoft.com" cannot list resource "pods" in API group "" in the namespace "default": User does not have access t o the resource in Azure. Update role assignment to allow access. 14. Repeat step 6 and 13 for the remaining users, and see how their permissions differs. # Username and password for Admin user execute the command from your local shell and not from Jumpbox VM echo $AAD_ADMIN_UPN echo $AAD_ADMIN_PW # Username and password for Backend user execute the command from your local shell and not from Jumpbox VM echo $AAD_OPS_BE_UPN echo $AAD_OPS_BE_PW 🎉 Congratulations, you made it to the end! You’ve just navigated the wild waters of Microsoft Entra ID and AKS — and lived to tell the tale. Whether you’re now a cluster conqueror or an identity integration ninja, give yourself a high five (or a kubectl get pods if that’s more your style). Now go forth and secure those clusters like the cloud hero you are. 🚀 And remember: with great identity comes great responsibility.626Views1like0CommentsStreamline & Modernise ASP.NET Auth: Moving enterprise apps from IIS to App Service with Easy Auth
Introduction When modernising your enterprise ASP.NET (.NET Framework) or ASP.NET Core applications and moving them from IIS over to Azure App Service, one of the aspects you will have to take into consideration is how you will manage authentication (AuthN) and authorisation (AuthZ). Specifically, for applications that leverage on-premises auth mechanisms such as Integrated Windows Authentication, you will need to start considering more modern auth protocols such as OpenID Connect/OAuth which are more suited to the cloud. Fortunately, App Service includes built-in authentication and authorisation support also known as 'Easy Auth', which requires minimal to zero code changes. This feature is integrated into the platform, includes a built-in token store, and operates as a middleware running the AuthN logic outside of your code logic, as illustrated by the image below:- More information on how EasyAuth works can be found here. Easy Auth supports several providers as illustrated above, but in this blog we will purely focus on using Entra ID (formerly known as Azure Active Directory) as the provider. It also assumes all of the Active Directory users have been synced up to Entra ID. With a few clicks, you can enable Entra ID authentication across any of your web, mobile or API apps in App Service, restrict which tenants or even specific identities are allowed access – all without touching code. This can be quite powerful in many scenarios, such as when you do not have access to the source control to implement your own auth logic, reducing the maintenance overhead of maintaining libraries or simply want a quick path to apply auth across your apps. For more detailed scenarios and comparison on when it makes sense using Easy Auth versus other authentication methods can be found here. Setting up Easy Auth Let’s see Easy Auth in action. As you can see below I have a sample ASP.NET app hosted on App Service which is accessible without any authentication:- Now let’s demonstrate how quickly it is to setup Easy Auth for my app:- 1) I navigated to my App Service resource within the Azure Portal 2) I went to Authentication and used the below configuration o Selected Microsoft as the Identity provider o Workforce configuration (current tenant) o Create a new app registration (appropriate Entra ID roles are required) o Entra ID app name:- sot-easyauth o Client secret expiry:- 180 days (this means I must renew the secret in advance of the 180 days otherwise my app/authentication will fail to function upon expiry causing downtime). o Allow requests only from this application itself. o Current tenant – Single tenant (i.e users outside of my tenant will be denied access) o Identity requirement:- Allow requests from any identity o Restrict access:- Require authentication (this will require authentication across my whole app, whereas “Allow unauthenticated access” means it is up to my app to decide when authentication is required). o HTTP 302 Found redirect (redirects unauthenticated users to the login page rather than just a page stating 401 unauthorised for example). o Token store:- Enabled (also allows the app to have access to the token). 3) For permissions, I left the default User.Read Graph API permission selected. More information on the different permissions can be found here. Now if I go back to the app and refresh the page again, I am redirected to the login page which is surfaced by the Easy Auth middleware:- Only after successful authentication, will I be able to see the Welcome page again:- Now that is pretty impressive, but you might want to go even further and have questions such as: how will my app know who’s logged in? How can I access the claims? How do I perform more granular AuthZ? Well for starters, Easy Auth essentially creates the claims in the incoming token and exposes them to your app as request headers which your app can then leverage to interpret accordingly. The list of headers can be found here. Typically, you will be tasked with creating custom logic to decode and interpret these claims, but with the likes of ASP.NET (.NET Framework), App Service can populate the claims of the authenticated user without additional code logic. However for ASP.NET Core this does not hold true. Thus, given the approach differs between ASP.NET (.NET Framework) and ASP.NET Core (starting from .NET Core), I will split these up into two different sections after touching upon AuthZ and Entra ID app roles. AuthZ and Entra ID App Roles If your IIS ASP.NET app leverages Windows Authentication for AuthN, but your app manages AuthZ itself, perhaps by mapping the domain credentials (e.g. CONTOSO\Sam) to specific AuthZ roles stored in somewhere like a database and remains a requirement to do, you can achieve a similar outcome by using the claims provided by Easy Auth. However, it is not recommended to use fields such as domain credentials, e-mail or UPN (e.g. dan.long@contoso.com) given such attributes can change and even be re-used over time. For example, an employee called Dan Long has the UPN of dan.long@contoso.com leaves the company and another employee with the same name joins the company and is assigned the same UPN dan.long@contoso.com – potentially giving unauthorised access to resources belonging to the former employee. Instead you may consider using the oid (i.e objectId), which is a globally unique GUID that identifies the user across applications within a single tenant. You might also consider pairing oid with tid (i.e tenant ID) for sharding/routing if required. A note for multi-tenancy applications: the same user that exists in different tenants will have a different oid. More information on how to reliably identify a user and the different claim types available can be found here. Alternatively, if the built-in authorisation policies do not suffice, you can leverage Entra ID app roles to apply authorisation within your ASP.NET App, which we will cover in more depth further down below. For demonstration purposes, I have created an app role called Member in my Entra ID App Registration and assigned the Entra ID group “Contoso EA Members” to this role via the associated Entra ID Enterprise Application, which my identity is part of as shown below:- I am leveraging said role to restrict only the role Member from being able to access the Member Area page (more on this further down). More information on creating your own Entra ID app roles can be found here. ASP.NET (.NET Framework) claims and Entra ID App roles For ASP.NET 4.6 apps, App Service populates the user’s claims through ClaimsPrincipal.Current, which means you can easily reference the claims without additional logic. I have created sample code which demonstrates this here, and the output of this in App Service can be found below:- You will notice Easy Auth has picked up my Entra ID app role called Member under claim type roles. In the screenshot and sample, you will notice I have a link located on the top nav bar called Member Area which is guarded by an [Authorize] tag to restrict only members with the role Member access. Unfortunately, at this stage, if we were to access the page it will return with 401 Access Denied, regardless of my identity having the appropriate app role. The reason behind this, is because ASP.NET is looking for the claim type “http://schemas.microsoft.com/ws/2008/06/identity/claims/role” instead of “role”. Fortunately, Easy Auth can be configured to display the long claim name instead by configuring the Environment Variable WEBSITE_AUTH_USE_LEGACY_CLAIMS to False, as shown in the below screenshot:- After the change, if I logout and back in again, I will see this being reflected back into my application and the Member Area page will grant me access as shown in the screenshots below:- Voila, we now have claims and Entra ID app roles working within our ASP.NET application. ASP.NET Core claims and Entra ID App roles Out-of-the-box, Easy Auth does not support populating ASP.NET Core with the current user’s authentication context like it does for ASP.NET (.NET Framework) with ClaimsPrincipal. However, this can be achieved by using the nuget package Microsoft.Identity.Web which has built-in capability to achieve this. What I did was as follows:- 1) Installed the nuget package Microsoft.Identity.Web into my solution. 2) In my Program.cs file, I loaded in the library:- builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration); 3) I also added app.UseAuthorization() after app.UseAuthentication() app.UseAuthentication(); After these changes, User.Identities will now be populated with the claims, and the [Authorize] tag will work permitting only the role Member when visiting the Member Area page. The full sample code can be found here. Unlike with ASP.NET (.NET Framework), the downside with this approach is the added responsibility of managing an additional library (Microsoft.Identity.Web). Conclusion App Service Easy Auth can provide a streamlined and efficient way to manage authentication and authorisation for your ASP.NET applications. By leveraging Easy Auth, you can apply modern auth protocols with minimal to zero code changes. The built-in support for various identity providers, including Entra ID, can help developers implement flexible and robust auth mechanisms. As demonstrated, Easy Auth simplifies the process of integrating authentication and authorisation into your applications, making it an valuable tool for modernising enterprise apps. Good to know and additional resources Limitations of Entra ID app roles. For example “A user, group, or service principal can have a maximum of 1,500 app role assignment”:- Service limits and restrictions - Microsoft Entra ID | Microsoft Learn. You can leverage Azure Policy to audit across the organisation when App Service does not have Easy Auth enabled by turning on “App Service apps should have authentication enabled”:- Built-in policy definitions for Azure App Service - Azure App Service | Microsoft Learn. Work with User Identities in AuthN/AuthZ - Azure App Service | Microsoft Learn Configure Microsoft Entra Authentication - Azure App Service | Microsoft Learn Work with OAuth Tokens in AuthN/AuthZ - Azure App Service | Microsoft Learn665Views1like0CommentsConnect Azure SQL Server via System Assigned Managed Identity under ASP.NET
TOC Why we use it Architecture How to use it References Why we use it This tutorial will introduce how to integrate Microsoft Entra with Azure SQL Server to avoid using fixed usernames and passwords. By utilizing System-assigned managed identities as a programmatic bridge, it becomes easier for Azure-related PaaS services (such as Container Apps) to communicate with the database without storing connection information in plain text. Architecture I will introduce each service or component and their configurations in subsequent chapters according to the order of A-C: A: The company's account administrator needs to create or designate a user as the database administrator. This role can only be assigned to one person within the database and is responsible for basic configuration and the creation and maintenance of other database users. It is not intended for development or actual system operations. B: The company's development department needs to create a Container App (or other service) as the basic unit of the business system. Programmers within this unit will write business logic (e.g., accessing the database) and deploy it here. C: The company's data department needs to create or maintain a database and designate Microsoft Entra as the only login method, eliminating other fixed username/password combinations. How to use it A: As this article does not dive into the detailed configuration of Microsoft Entra, it will only outline the process. The company's account administrator needs to create or designate a user as the database administrator. In this example, we will call this user "cch," and the account, "cch@thexxxxxxxxxxxx" will be used in subsequent steps. B-1: In this example, we can create a Container App with any SKU/region. Please note that during the initial setup, we will temporarily use the nginx:latest image from docker.io. After creating our own ASP.NET image, we will update it accordingly. For testing convenience, please enable Ingress traffic and allow requests from all regions. Once the Container App has been created, please enable the System Assigned Managed Identity. Lastly, please make a note of your App Name (e.g., mine is az-1767-aca) as we will use it in the following steps. C-1: Create a database/SQL server. During this process, you need to specify the user created in Step A as the database administrator. Please note that to select "Microsoft Entra-only authentication." In this mode, the username/password will no longer be used. Then, click on "Next: Networking." Microsoft Entra and Username & Password login methods are selected, for security reasons, it is strongly recommended to choose Microsoft Entra Only. The Username & Password option will not be used in this tutorial.) Since this article does not cover the detailed network configuration of the database, temporarily allow public access during the tutorial. Use the default values for other settings, click on "Review + Create," and then click "Create" to finish the setup. During this process, you need to specify the system-assigned managed identity created in Step B as the entity that will actually operate the database. And leave it default from the rest of the parts, and finally create the Database. C-2: After the database has created, you can log in using the identity "cch@thexxxxxxxxxxxx" you've get from Step A which is the database administrator. Open a PowerShell terminal and using the "cch" account, enter the following command to log in to SQL Server. You will need to change the <text> to follow your company's naming conventions. sqlcmd -S <YOUR_SERVER_NAME>.database.windows.net -d <YOUR_DB_NAME> -U <YOUR_FULL_USER_EMAIL> -G You will be prompt for a 2 step verification. dentities setup from Step B. First, we will introduce the method for the system-assigned managed identity. The purpose of the commands is to grant database-related operational permissions to the newly created user. This is just an example. In actual scenarios, you should follow your company's security policies and make the necessary adjustments accordingly. Please enter the following command. CREATE USER [<YOUR_APP_NAME>] FROM EXTERNAL PROVIDER; USE [<YOUR_DB_NAME>]; EXEC sp_addrolemember 'db_owner', '<YOUR_APP_NAME>'; For testing purposes, we will create a test table, and insert some data. CREATE TABLE TestTable ( Column1 INT, Column2 NVARCHAR(100) ); INSERT INTO TestTable (Column1, Column2) VALUES (1, 'First Record'); INSERT INTO TestTable (Column1, Column2) VALUES (2, 'Second Record'); B-2: Developers can now start building the Docker image. In my sample development environment, I'm using .NET 8.0. Run the following command in your development environment to create a Hello World project: dotnet new web -n WebApp --no-https This command will generate many files used for the project. You will need to modify both Program.cs and WebApp.csproj. using Microsoft.Data.SqlClient; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", async context => { var response = context.Response; var connectionString = "Server=az-1767-dbserver.database.windows.net;Database=az-1767-db;Authentication=ActiveDirectoryMsi;TrustServerCertificate=True;"; await response.WriteAsync("Hello World\n\n"); try { using var conn = new SqlConnection(connectionString); await conn.OpenAsync(); var cmd = new SqlCommand("SELECT Column1, Column2 FROM TestTable", conn); using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { var line = $"{reader.GetInt32(0)} - {reader.GetString(1)}"; await response.WriteAsync(line + "\n"); } } catch (Exception ex) { await response.WriteAsync($"[Error] {ex.Message}"); } }); app.Run("http://0.0.0.0:80"); <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.4" /> </ItemGroup> </Project> Please note the connectionString in Program.cs. The string must follow a specific format — you’ll need to replace az-1767-dbserver and az-1767-db with your own server and database names. After making the modifications, run the following command in the development environment. It will compile the project into a DLL and immediately run it (press Ctrl+C to stop). dotnet run Once the build is complete, you can package the entire project into a Docker image. Create a Dockerfile in the root of your project. FROM mcr.microsoft.com/dotnet/sdk:8.0 # Install ODBC Driver RUN apt-get update \ && apt-get install -y unixodbc odbcinst unixodbc-dev curl vim \ && curl -sSL -O https://packages.microsoft.com/debian/12/prod/pool/main/m/msodbcsql18/msodbcsql18_18.5.1.1-1_amd64.deb \ && ACCEPT_EULA=Y DEBIAN_FRONTEND=noninteractive dpkg -i msodbcsql18_18.5.1.1-1_amd64.deb \ && rm msodbcsql18_18.5.1.1-1_amd64.deb # Setup Project Code RUN mkdir /WebApp COPY ./WebApp /WebApp # OTHER EXPOSE 80 CMD ["dotnet", "/WebApp/bin/Debug/net8.0/WebApp.dll"] In this case, we are using mcr.microsoft.com/dotnet/sdk:8.0 as the base image. To allow access to Azure SQL DB, you’ll also need to install the ODBC driver in the image. Use the following command to build the image and push it to your Docker Hub (docker.io). Please adjust the image tag, for example az-1767-aca:202504091739 can be renamed to your preferred version, and replace theringe with your own Docker Hub username. docker build -t az-1767-aca:202504091739 . --no-cache docker tag az-1767-aca:202504091739 theringe/az-1767-aca:202504091739 docker push theringe/az-1767-aca:202504091739 After building and uploading the image, go back to your Container App and update the image configuration. Once the new image is applied, visit the app’s homepage and you’ll see the result. References: Connect Azure SQL Server via User Assigned Managed Identity under Django | Microsoft Community Hub Managed identities in Azure Container Apps | Microsoft Learn Azure Identity client library for Python | Microsoft Learn773Views1like0CommentsConnection Between Web App and O365 Resources: Using SharePoint as an Example
TOC Introduction [not recommended] Application permission [not recommended] Delegate permission with Device Code Flow Managed Identity Multi-Tenant App Registration Restrict Resources for Application permission References Introduction In late 2024, Microsoft Entra enforced MFA (Multi-Factor Authentication) for all user login processes. This change has caused some Web Apps using delegated permissions to fail in acquiring access tokens, thereby interrupting communication with O365 resources. This tutorial will present various alternative solutions tailored to different business requirements. We will use a Linux Python Web App as an example in the following sections. [not recommended] Application permission Traditionally, using delegated permissions has the advantages of being convenient, quick, and straightforward, without being limited by whether the Web App and Target resources (e.g., SharePoint) are in the same tenant. This is because it leverages the user identity in the SharePoint tenant as the login user. However, its drawbacks are quite evident—it is not secure. Delegated permissions are not designed for automated processes (i.e., Web Apps), and if the associated connection string (i.e., app secret) is obtained by a malicious user, it can be directly exploited. Against this backdrop, Microsoft Entra enforced MFA for all user login processes in late 2024. Since delegated permissions rely on user-based authentication, they are also impacted. Specifically, if your automated processes originally used delegated permissions to interact with other resources, they are likely to be interrupted by errors similar to the following in recent times. AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access '00000003-0000-0000-c000-000000000000' The root cause lies in the choice of permission type. While delegated permissions can technically be used for automated processes, there is a more appropriate option—application permissions, which are specifically designed for use in automated workflows. Therefore, when facing such issues, the quickest solution is to create a set of application permissions, align their settings with your previous delegated permissions, and then update your code to use the new app ID and secret to interact with the target resource. This method resolves the issue caused by the mandatory MFA process interruption. However, it is still not entirely secure, as the app secret, if obtained by a malicious user, can be exploited directly. Nonetheless, it serves as a temporary solution while planning for a large-scale modification or refactor of your existing system. [not recommended] Delegate permission with Device Code Flow Similarly, here's another temporary solution. The advantage of this approach is that you don't even need to create a new set of application permissions. Instead, you can retain the existing delegated permissions and resolve the issue by integrating Device Code Flow. Let's see how this can be achieved. First, navigate to Microsoft Entra > App Registration > Your Application > Authentication, and enable "Allow public client flows". Next, modify your code to implement the following method to acquire the token. Replace [YOUR_TENANT_ID] and [YOUR_APPLICATION_ID] with your own values. import os, atexit, msal, sys def get_access_token_device(): cache_filename = os.path.join( os.getenv("XDG_RUNTIME_DIR", ""), "my_cache.bin" ) cache = msal.SerializableTokenCache() if os.path.exists(cache_filename): cache.deserialize(open(cache_filename, "r").read()) atexit.register(lambda: open(cache_filename, "w").write(cache.serialize()) if cache.has_state_changed else None ) config = { "authority": "https://login.microsoftonline.com/[YOUR_TENANT_ID]", "client_id": "[YOUR_APPLICATIOM_ID]", "scope": ["https://graph.microsoft.com/.default"] } app = msal.PublicClientApplication( config["client_id"], authority=config["authority"], token_cache=cache, ) result = None accounts = app.get_accounts() if accounts: print("Pick the account you want to use to proceed:") for a in accounts: print(a["username"]) chosen = accounts[0] result = app.acquire_token_silent(["User.Read"], account=chosen) if not result: flow = app.initiate_device_flow(scopes=config["scope"]) print(flow["message"]) sys.stdout.flush() result = app.acquire_token_by_device_flow(flow) if "access_token" in result: access_token = result["access_token"] return access_token else: error = result.get("error") if error == "invalid_client": print("Invalid client ID.Please check your Azure AD application configuration") else: print(error) Demonstrating the Process Before acquiring the token for the first time, there is no cache file named my_cache.bin in your project directory. Start the test code, which includes obtaining the token and interacting with the corresponding service (e.g., SharePoint) using the token. Since this is the first use, the system will prompt you to manually visit https://microsoft.com/devicelogin and input the provided code. Once the manual process is complete, the system will obtain the token and execute the workflow. After acquiring the token, the cache file my_cache.bin will appear in your project directory. This file contains the access_token and refresh_token. For subsequent processes, whether triggered manually or automatically, the system will no longer prompt for manual login. The cached token has a validity period of approximately one hour, which may seem insufficient. However, the acquire_token_silent function in the program will automatically use the refresh token to renew the access token and update the cache. Therefore, as long as an internal script or web job is triggered at least once every hour, the token can theoretically be used continuously. Managed Identity Using Managed Identity to enable interaction between an Azure Web App and other resources is currently the best solution. It ensures that no sensitive information (e.g., app secrets) is included in the code and guarantees that only the current Web App can use this authentication method. Therefore, it meets both convenience and security requirements for production environments. Let’s take a detailed look at how to set it up. Step 1: Setup Managed Identity You will get an Object ID for further use. Step 2: Enterprise Application for Managed Identity Your Managed Identity will generate a corresponding Enterprise Application in Microsoft Entra. However, unlike App Registration, where permissions can be assigned directly via the Azure Portal, Enterprise Application permissions must be configured through commands. Step 3: Log in to Azure via CloudShell Use your account to access Azure Portal, open a CloudShell, and input the following command. This step will require you to log in with your credentials using the displayed code: Connect-MgGraph -Scopes "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All" Continue by inputting the following command to target the Enterprise Application corresponding to your Managed Identity that requires permission assignment: $PrincipalId = "<Your web app managed identity object id>" $ResourceId = (Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'" | Select-Object -ExpandProperty Id) Step 4: Assign Permissions to the Enterprise Application Execute the following commands to assign permissions. Key Points: This example assigns all permissions with the prefix Sites.*. However, you can modify this to request only the necessary permissions, such as: Sites.Selected Sites.Read.All Sites.ReadWrite.All Sites.Manage.All Sites.FullControl.All If you do not wish to assign all permissions, you can change { $_.Value -like "*Sites.*" } to the specific permission you need, for example: { $_.Value -like "*Sites.Selected*" } Each time you modify the permission, you will need to rerun all the commands below. $AppRoles = Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'" -Property AppRoles | Select -ExpandProperty AppRoles | Where-Object { $_.Value -like "*Sites.*" } $AppRoles | ForEach-Object { $params = @{ "PrincipalId" = $PrincipalId "ResourceId" = $ResourceId "AppRoleId" = $_.Id } New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $PrincipalId -BodyParameter $params } Step 5: Confirm Assigned Permissions If, in Azure Portal, you see a screen similar to this: (Include screenshot or example text for granted permissions) This means that the necessary permissions have been successfully assigned. Step 6: Retrieve a Token in Python In your Python code, you can use the following approach to retrieve the token: from azure.identity import ManagedIdentityCredential def get_access_token(): credential = ManagedIdentityCredential() token = credential.get_token("https://graph.microsoft.com/.default") return token.token Important Notes: When permissions are assigned or removed in the Enterprise Application, the ManagedIdentityCredential in your Python code caches the token for a while. These changes will not take effect immediately. You need to restart your application and wait approximately 10 minutes for the changes to take effect. Step 7: Perform Operations with the Token Finally, you can use this token to perform the desired operations. Below is an example of creating a file in SharePoint: You will notice that the uploader’s identity is no longer a person but instead the app itself, indicating that Managed Identity is indeed in effect and functioning properly. While this method is effective, it is limited by the inability of Managed Identity to handle cross-tenant resource requests. I will introduce one final method to resolve this limitation. Multi-Tenant App Registration In many business scenarios, resources are distributed across different tenants. For example, SharePoint is managed by Company (Tenant) B, while the Web App is developed by Company (Tenant) A. Since these resources belong to different tenants, Managed Identity cannot be used in such cases. Instead, we need to use a Multi-Tenant Application to resolve the issue. The principle of this approach is to utilize an Entra ID Application created by the administrator of Tenant A (i.e., the tenant that owns the Web App) that allows cross-tenant use. This application will be pre-authorized by future user from Tenant B (i.e., the administrator of the tenant that owns SharePoint) to perform operations related to SharePoint. It should be noted that the entire configuration process requires the participation of administrators from both tenants to a certain extent. Please refer to the following demonstration. This is a sequential tutorial; please note that the execution order cannot be changed. Step 1: Actions Required by the Administrator of the Tenant that Owns the Web App 1.1. In Microsoft Entra, create an Enterprise Application and select "Multi-Tenant." After creation, note down the Application ID. 1.2. In App Registration under AAD, locate the previously created application, generate an App Secret, and record it. 1.3. Still in App Registration, configure the necessary permissions. Choose "Application Permissions", then determine which permissions (all starting with "Sites.") are needed based on the actual operations your Web App will perform on SharePoint. For demonstration purposes, all permissions are selected here. Step 2: Actions Required by the Administrator of the Tenant that Owns SharePoint 2.1. Use the PowerShell interface to log in to Azure and select the tenant where SharePoint resides. az login --allow-no-subscriptions --use-device-code 2.2. Add the Multi-Tenant Application to this tenant. az ad sp create --id <App id get from step 1.1> 2.3. Visit the Azure Portal, go to Enterprise Applications, locate the Multi-Tenant Application added earlier, and navigate to Permissions to grant the permissions specified in step 1.3. Step 3: Actions Required by the Administrator of the Tenant that Owns the Web App 3.1. In your Python code, you can use the following method to obtain an access token: from msal import ConfidentialClientApplication def get_access_token_cross_tenant(): tenant_id = "your-sharepoint-tenant-id" # Tenant ID where the SharePoint resides (i.e., shown in step 2.1) client_id = "your-multi-tenant-app-client-id" # App ID created in step 1.1 client_secret = "your-app-secret" # Secret created in step 1.2 authority = f"https://login.microsoftonline.com/{tenant_id}" app = ConfidentialClientApplication( client_id, authority=authority, client_credential=client_secret ) scopes = ["https://graph.microsoft.com/.default"] token_response = app.acquire_token_for_client(scopes=scopes) return token_response.get("access_token") 3.2. Use this token to perform the required operations. Restrict Resources for Application permission Application permission, allows authorization under the App’s identity, enabling access to all SharePoint sites within the tenant, which could be overly broad for certain use cases. To restrict this permission to access a limited number of SharePoint sites, we need to configure the following settings: Actions Required by the Administrator of the Tenant that Owns SharePoint During the authorization process, only select Sites.Selected. (refer to Step 4 from Managed Identity, and Step 1.3 from Multu-tenant App Registration) Subsequently, configure access separately for different SharePoint sites. During the process, we will create a temporary App Registration to issue an access token, allowing us to assign specific SharePoint sites' read/write permissions to the target Application. Once the permission settings are completed, this App Registration can be deleted. Refer to the above images, we need to note down the App Registration's object ID and tenant ID. Additionally, we need to create an app secret and grant it the Application permission Sites.FullControl.All. Once the setup is complete, the token can be obtained using the following command. $tenantId = "<Your_Tenant_ID>" $clientId = "<Your_Temp_AppID>" $clientSecret = "<Your_Temp_App_Secret>" $scope = "https://graph.microsoft.com/.default" $url = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" $body = @{ grant_type = "client_credentials" client_id = $clientId client_secret = $clientSecret scope = $scope } $response = Invoke-RestMethod -Uri $url -Method Post -Body $body $accessToken = $response.access_token Before granting the write permission to the target application, even if the Application Permission already has the Sites.Selected scope, an error will still occur. Checking the current SharePoint site's allowed access list shows that it is empty. $headers = @{ "Authorization" = "Bearer $accessToken" "Content-Type" = "application/json" } Invoke-RestMethod -Method Get -Uri "https://graph.microsoft.com/v1.0/sites/<Your_SharePoint_Site>.sharepoint.com" -Headers $headers Next, we manually add the corresponding Application to the SharePoint site's allowed access list and assign it the write permission. $headers = @{ "Authorization" = "Bearer $accessToken" "Content-Type" = "application/json" } $body = @{ roles = @("write") grantedToIdentities = @( @{ application = @{ id = "<Your_Target_AppID>" displayName = "<Your_Target_AppName>" } } ) grantedToIdentitiesV2 = @( @{ application = @{ id = "<Your_Target_AppID>" displayName = "<Your_Target_AppName>" } } ) } | ConvertTo-Json -Depth 10 Invoke-RestMethod -Method Post -Uri "https://graph.microsoft.com/v1.0/sites/<Your_SharePoint_Site>.sharepoint.com/permissions" -Headers $headers -Body $body Rechecking the current SharePoint site's allowed access list confirms the addition. After that, writing files to the site will succeed, and you could delete the temp App Registration. References Microsoft will require MFA for all Azure users Acquire a token to call a web API using device code flow (desktop app) - Microsoft identity platform | Microsoft Learn Implement cross-tenant communication by using multitenant applications - Azure Architecture Center819Views1like0CommentsConnection Between Web App and O365 Resources: Using Mail as an Example
TOC Introduction User Management Grant Permission Setup Security Mail Group Test References Introduction When using the Graph API to manage mail-related services, setting the permission to Delegate permission restricts the authorization to the user’s identity, limiting management to the specific user’s mailbox. While this might not be sufficient for certain business scenarios, Application permission, on the other hand, allows authorization under the App’s identity, enabling access to all users’ mailboxes within the tenant, which could be overly broad for certain use cases. Therefore, a method is required that allows the management of a specific mailbox using the App’s identity. This scenario is not recommended to use Delegate permission and requires some prerequisites, which are outlined in this article: Connection Between Web App and O365 Resources: Using SharePoint as an Example. User Management In your Microsoft Entra ID tenant, you will need: An admin user with permissions to "create users" and "assign roles." This user will perform the following operations. For simplicity, we’ll refer to this user as the admin user. An Exchange Administrator user who has the Exchange Administrator role. If not assigned, ensure to assign it to a user. In this example, the user is cch. A user account (or multiple users) to be managed by the Web App for mailbox operations. In this example, the user is support. Additionally, remember to visit https://admin.microsoft.com/ to assign a Microsoft 365 license to the new user, enabling mailbox access. Grant Permission For this example, we’ll use Managed Identity to grant the Mail.ReadWrite permission to the Enterprise Application corresponding to the Web App's Managed Identity. Note: Depending on your business requirements: You can replace the Managed Identity with a Multi-Tenant App Registration. You can also adjust Mail.ReadWrite to other permissions aligned with your business needs. Log in to the Azure Portal with your admin user and open a PowerShell CloudShell session. Modify and run the following commands to grant the necessary Graph API permissions to the Web App’s Managed Identity. Connect-MgGraph -Scopes "AppRoleAssignment.ReadWrite.All" $PrincipalId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" # Please setup your Managed Identity's OBJ ID $ResourceId = (Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'" | Select-Object -ExpandProperty Id) $AppRoles = Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'" -Property AppRoles | Select -ExpandProperty AppRoles | Where-Object { $_.Value -like "Mail.ReadWrite" } # Please setup your permission $AppRoles | ForEach-Object { $params = @{ "PrincipalId" = $PrincipalId "ResourceId" = $ResourceId "AppRoleId" = $_.Id } New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $PrincipalId -BodyParameter $params } Setup Security Mail Group Log in to the Azure Portal with an Exchange Administrator user, open a PowerShell CloudShell session, and run the following commands: Create a Security Mail Group. Add the mailboxes (e.g., support) that need to be accessible via the Web App to the group. Associate the Managed Identity's authorization with the Security Mail Group. az login --tenant XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX--use-device-code # Please setup your tenant id Connect-ExchangeOnline Connect-AzureAD New-DistributionGroup -Name "Policy Scope Group" -Alias "policy-scope-group" -Type Security Add-DistributionGroupMember -Identity "Policy Scope Group" -Member "XXX@XXX.com" # Please setup your receiver mailbox $AppId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" # Please setup your Managed Identity's APP ID $GroupId = (Get-AzureADGroup -SearchString "Policy Scope Group" | Select-Object ObjectId).ObjectId New-ApplicationAccessPolicy -AppId $AppId -PolicyScopeGroupId $GroupId -AccessRight RestrictAccess Important Notes Allow at least one hour for all configurations to take effect. Ensure the Microsoft 365 license has been assigned to the relevant user(s). Test You can deploy the following example code to your Web App. Replace support@xx.com with the mailbox to be accessed programmatically, and prepare another mailbox (e.g., cch@xx.com) for testing to ensure that only mailboxes within the Security Mail Group can be accessed. import requests from azure.identity import ManagedIdentityCredential def get_access_token(): credential = ManagedIdentityCredential() token = credential.get_token("https://graph.microsoft.com/.default") return token.token def get_latest_email_subject(target_email): access_token = get_access_token() headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } url = f"https://graph.microsoft.com/v1.0/users/{target_email}/mailFolders/Inbox/messages?$count=true" response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() if "value" in data and len(data["value"]) > 0: return data["value"][0].get("subject", "No Subject") else: print("No emails found in the inbox.") return None else: print("Failed to fetch emails.") print("Status Code:", response.status_code) print("Response:", response.json()) return None if __name__ == "__main__": print("=============================================") print("Fetching support@xx.com's latest email subject...") target_email = "support@xx.com" subject = get_latest_email_subject(target_email) if subject: print("Latest Email Subject:", subject) else: print("No email subject found.") print("=============================================") print("Fetching cch@xx.com's latest email subject...") target_email = "cch@xx.com" subject = get_latest_email_subject(target_email) if subject: print("Latest Email Subject:", subject) else: print("No email subject found.") After testing, you should observe that only the mailboxes of members within the Security Mail Group can be accessed by the Web App, while other mailboxes remain inaccessible. This ensures secure and specific access control. References Connection Between Web App and O365 Resources: Using SharePoint as an Example | Microsoft Community Hub Microsoft Graph permissions reference - Microsoft Graph | Microsoft Learn Connection Between Web App and O365 Resources: Using SharePoint as an Example | Microsoft Community Hub2KViews0likes0CommentsConnect Azure SQL Server via User Assigned Managed Identity under Django
This tutorial will introduce how to integrate Microsoft Entra with Azure SQL Server to avoid using fixed usernames and passwords. By utilizing user-assigned managed identities as a programmatic bridge, it becomes easier for Azure-related PaaS services (such as Function App or App Services) to communicate with the database without storing connection information in plain text.3.9KViews2likes0Comments