avatarRené Bremer

Summary

The provided content outlines a process for securing Python Flask web APIs using Azure Active Directory (Azure AD) for authentication and authorization, with data retrieval from Azure SQL Database.

Abstract

The article details a method for enhancing the security of Python Flask web applications by integrating Azure AD to manage user authentication and authorization. It describes a sample application that demonstrates user login, token acquisition, and secure data retrieval from Azure SQL Database. The application uses OpenID Connect and OAuth 2.0 protocols to authenticate users and obtain access tokens. It also explains how to configure the application to use either the app's managed identity or the signed-in user's identity for database authentication, with role-based access control (RBAC) for fine-grained permissions. The blog post provides step-by-step instructions, code snippets, and links to official Microsoft documentation for setting up the application, configuring Azure AD, and managing access to the Azure SQL Database.

Opinions

  • The author emphasizes the importance of using Azure AD for securing web APIs, suggesting it as a best practice for identity management in web applications.
  • The article promotes the use of managed identities for Azure resources as a secure way to authenticate to Azure SQL Database without storing credentials in the application code.
  • By providing a GitHub repository with sample code, the author encourages developers to use the provided example as a starting point for their own secure web applications.
  • The author highlights the flexibility of Azure AD in supporting both application permissions and delegated user permissions, allowing for different authentication flows based on the application's requirements.
  • The use of role claims in tokens is presented as an effective method for implementing role-based access control, ensuring that users can only access the data and resources they are authorized to use.

How to secure Python Flask Web APIs with Azure AD

Learn to use identities and tokens in web apps and Azure SQL

1. Introduction

Python Flask is a popular tool to create web applications. Using Azure AD, users can authenticate to the REST APIs and retrieve data from Azure SQL. In this blog, a sample Python web application is created as follows:

  • 1a: User logs in to web app and acquires a token
  • 1b: User calls a REST API to request a dataset
  • 2: Web app uses claims in token to verify user access to dataset
  • 3: Web app retrieves data from Azure SQL. Web app can be configured such that either the a) managed identity of the app or b) signed-in user identity is used for authentication to the database

The code of the project can be found here, architecture can be found below.

1. Secure Python Flask web APIs with Azure AD — introduction. Image by author.

In the remaining of this blog, the following steps are executed:

  • Step 1: Acquire token and call api using token
  • Step 2: Verify claims in token
  • Step 3a: App managed identity authentication
  • Step 3b: Signed-in user passthrough authentication

To learn how to access an Azure Function backend using delegated or application permissions, see my follow-up blog which shares the same git repo as this blog.

Step 1: Acquire token and call api using token

This sample shows how to build a Python web app using Flask and MSAL Python, that signs in a user, and get access to Azure SQL Database. For more information about how the protocols work in this scenario and other scenarios, see Authentication Scenarios for Azure AD. In this step, the following sub steps are executed:

  • 1.1: Preliminaries
  • 1.2: Create and configure app registration
  • 1.3: Configure the python webapp project
  • 1.4: Run the sample

Step 1 focusses on the follow part of the architecture.

Step 1: Acquire token and call api using token. Image by author.

1.1: Preliminaries

To run this sample, you’ll need:

  • Python 2.7+ or Python 3+
  • An Azure Active Directory (Azure AD) tenant. For more information on how to get an Azure AD tenant, see how to get an Azure AD tenant.
  • Git to clone the following project: git clone https://github.com/rebremer/ms-identity-python-webapp-backend.gitor download and extract the repository .zip file.

1.2: Create and configure app registration

Create and configure an app registration as follows:

  • Create an app registration using the steps in this link to create an app registration. Two remarks:
  • Use http://localhost/getAToken as reply URL. In case you did not do this during creation, it can be added using the Authentication tab of the app registration
  • Go to Authentication and enable the option ID tokens in Implicit grant
  • Go to Certificates & Secrets to create a secret. Copy the client_id and client secret

1.3: Configure the pythonwebapp project

  1. Open the app_config.py file and change the variables below.
  2. Find text <<Enter_the_Client_Secret_here>> and replace it with your application secret during the creation of the app registration in step 1.2.
  3. Find text <<Enter_the_Tenant_Name_Here>> and replace the existing value with your Azure AD tenant name.
  4. Find text <<Enter_the_Application_Id_here>> and replace the existing value with the application ID (clientId) of the app registration in step 1.2.

1.4: Run the sample

You will need to install dependencies using pip as follows:

$ pip install -r requirements.txt

Run app.py from shell or command line using the following command:

flask run --host localhost --port 5000

When the app is run locally, it can be visited by localhost:5000 (not 127.0.0.1:5000). After step 1, users can login using their Azure AD credentials. In the next step, the user roles are set that can be used to verify if user is allowed to retrieve data using the API.

Step 2: Verify claims in token

In this step, the claims in the tokens can be set which can be just be the web app to verify whether a user is allowed to call an api. See this link for more information on token claims. The following sub steps are executed:

  • 2.1: Set configuration in app config
  • 2.2: Add roles to manifest
  • 2.3: Assign user to role

Step 2 focusses on the follow part of the architecture.

Step 2: Verify claims in token. Image by author.

2.1: Set configuration in app config

Claim verification is an optional step and can be enabled using the following setting in app_config.py file: AAD_ROLE_CHECK = True .

2.2: Add roles to manifest

Follow the steps in this tutorial to add roles to app registration created in step 1.2. As manifest, the following appRoles shall be used:

"appRoles": [
  {
    "allowedMemberTypes": ["User"],
    "description": "Basic user, only read product data from SQLDB",
    "displayName": "basic_user_access",
    "id": "a8161423-2e8e-46c4-9997-f984faccb625",
    "isEnabled": true,
    "value": "basic_user_access"
  },
  {
    "allowedMemberTypes": ["User"],
    "description": "Premium user, read all data from SQLDB",
    "displayName": "premium_user_access",
    "id": "b8161423-2e8e-46c4-9997-f984faccb625",
    "isEnabled": true,
    "value": "premium_user_access"
  }
],

2.3: Assign user to role

The assignment of users is explained in th link. As a test, two users can be created. User 1 is assigned the basic_user_access, whereas user 2 gets the premium_user_access role.

In the next step, the Azure SQL database is created and the application identity is used to retrieve data form the database.

Step 3a: App Managed Identity authentication

In this step, the managed identity of the app is used to retrieve data, which is linked to the app registration created in step 1. The following sub steps are executed:

  • 3a.1: Create Azure SQL database
  • 3a.2: Set configuration in app config

Step 3a focusses on the follow part of the architecture.

Step 3a: App Managed Identity authentication to Azure SQL. Image by author.

3a.1: Create Azure SQL database

Create an Azure SQL DB using this link in which the cheapest SKU (basic) can be selected. Make sure the following is done:

  • AdvertureWorks is installed as sample database, the cheapest database can be selected (SKU basic).
  • Add app identity as user to Azure SQL database with correct reader roles, see example below as follows
CREATE USER [<<Name of app registration>>] FROM EXTERNAL PROVIDER;
EXEC sp_addrolemember [db_datareader], [<<Name of app registration>>];

3a.2: Set configuration in app config

The backend_settings needs to be set to database. Make also sure that connection is filled in with your settings. Since the MI of the app is used, application_permissions need to point to “https://database.windows.net//.default" in the app_config.py file, see also below.

# 2. Type of BACKEND
#
# Option 2a. Database
BACKEND_SETTINGS = {"Type": "Database", "Connection":{"SQL_SERVER": "<<Enter_logical_SQL_server_URL_here>>.database.windows.net", "DATABASE": "<<Enter_SQL_database_name_here>>"}}
# Option 3a. Delegated user is used to authenticate to Graph API, MI is then used to authenticate to backend
...
APPLICATION_PERMISSIONS = ["https://database.windows.net//.default"]

Now the app can be run as described in step 1.4. When you click on the link (Premium users only) Get Customer data from Database , customer data is retrieved. Subsequently, when there is clicked on the link Get Product data from Database, product data is retrieved (provided that claims are set correctly for user in step 2 or check is disabled)

In this step, the identity of the app is used to retrieve data. However, the identity of the user can also passed (AAD passthrough) to retrieve data from the database.

Step 3b: Signed-in user passthrough authentication

In the step, the identity of the user itself is used to retrieve data. This means that the token created in step 1 to login in the web app is also used to authenticate to the database. The following sub steps are executed:

  • 3b.1: Add Azure SQL DB Scope to app registration
  • 3b.2: Add AAD user to database
  • 3b.3: Set configuration in app config

Step 3b focusses on the follow part of the architecture.

Step 3b: Signed-in user passthrough authentication to Azure SQL. Image by author.

3b.1: Add Azure SQL DB Scope to app registration

  • Modify your app registration created in step 1.2. with permissions for Azure SQL database as delegated user. This is explained in this link
  • Important: Admin consent is required for Azure SQL Database. This can be either done by selecting Grant_admin consent for Default Directory in the permissions tab or at runtime while logging in

3b.2: Add AAD user to database

Since AAD passthrough is used in this step, the users themselves shall have the appropriate roles in the SQLDB as external user and datareader. See example how to do this below.

CREATE USER [<<AAD user email address>>] FROM EXTERNAL PROVIDER;
EXEC sp_addrolemember [db_datareader], [<<AAD user email address>>];

In case you want to be more granular in rolemembers in the database, read_customer reads data from SalesLT.Customer, whereas read_product reads data from SalesLT.Product)

3b.3: Set configuration in app config

AAD User passthrough authentication can be set in the app_config.py file by setting delegated_permissions to [“https://sql.azuresynapse-dogfood.net/user_impersonation"], see also below

# Option 3b. Delegated user is used to authenticate to backend, graph API disabled
...
DELEGATED_PERMISSONS = ["https://sql.azuresynapse-dogfood.net/user_impersonation"]

Now the app can be run as described in step 1.4, in which data can be retrieved from the database using the identity of the logged in user.

Conclusion

In this blog, a Python web application is created that retrieves data from SQLDB. Users claims, managed identities and signed-in user passthrough tokens are discussed to authenticate and authorize users to retrieve data from Azure SQL, see also overview below.

4. Secure Python Flask web APIs with Azure AD — conclusion. Image by author.
Azure
Python
Software Engineering
Programming
Towards Data Science
Recommended from ReadMedium