简体   繁体   中英

Use Managed Identity to authenticate Azure App Service to SQL Database

I am trying to connect a Python Flask app running in Azure App Service Web App to an Azure SQL Database. The works just fine when I use SQL authentication with username and password.

Now I want to move to using the Web Apps managed identity. I have activated the system-assigned managed identity, created a user for it in SQL and added it to the db_datareader role.

I am connecting with SqlAlchemy using a connection string like this

params = urllib.parse.quote_plus(os.environ['SQL_CONNECTION_STRING'])
conn_str = 'mssql+pyodbc:///?odbc_connect={}'.format(params)
engine_azure = db.create_engine(conn_str,echo=True)

The connection string is stored as an application setting, and its value is

"Driver={ODBC Driver 17 for SQL Server};Server=tcp:<server>.database.windows.net,1433;Database=<database>;Authentication=ActiveDirectoryMsi;"

I expected this to be all I need to do, but now my app is not starting. The logs report a timeout when connecting to the database.

How can I fix this?

If you want to connect Azure SQL database with Azure MSI in python application, we can use the SDK pyodbc to implement it.

For example

  1. Enable system-assigned identity for your Azure app service

  2. Add the MSi as contained database users in your database

    a. Connect your SQL database with Azure SQL AD admin (I use SSMS to do it)

    b. run the following the script in your database

    CREATE USER <your app service name> FROM EXTERNAL PROVIDER; ALTER ROLE db_datareader ADD MEMBER <your app service name> ALTER ROLE db_datawriter ADD MEMBER <your app service name> ALTER ROLE db_ddladmin ADD MEMBER <your app service name>
  3. Code
import os
import pyodbc
import requests 
import struct

#get access token
identity_endpoint = os.environ["IDENTITY_ENDPOINT"]
identity_header = os.environ["IDENTITY_HEADER"]
resource_uri="https://database.windows.net/"
token_auth_uri = f"{identity_endpoint}?resource={resource_uri}&api-version=2019-08-01"
head_msi = {'X-IDENTITY-HEADER':identity_header}
resp = requests.get(token_auth_uri, headers=head_msi)
access_token = resp.json()['access_token']


accessToken = bytes(access_token, 'utf-8');
exptoken = b"";
for i in accessToken:
        exptoken += bytes({i});
        exptoken += bytes(1);
tokenstruct = struct.pack("=i", len(exptoken)) + exptoken;

conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=tcp:andyserver.database.windows.net,1433;Database=database2", attrs_before = { 1256:bytearray(tokenstruct) });

cursor = conn.cursor()
cursor.execute("select @@version")
row = cursor.fetchall()

For more details, please refer to the

https://github.com/AzureAD/azure-activedirectory-library-for-python/wiki/Connect-to-Azure-SQL-Database

https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity

https://docs.microsoft.com/en-us/azure/sql-database/sql-database-aad-authentication-configure

I know this is quite an old post, but it may help people like me who are looking for a solution.

You could modify the connection string by adding "Authentication" parameters as "ActiveDirectoryMsi", no need to use endpoint and headers.

(Works with Azure SQL, for other databases like Postgress you may need to use the struct token)

import pyodbc


pyodbc.connect(
        "Driver="
        + driver
        + ";Server="
        + server
        + ";PORT=1433;Database="
        + database
        + ";Authentication=ActiveDirectoryMsi")

I wrote a quick article for those who are interested in Azure MSI: https://hedihargam.medium.com/python-sql-database-access-with-managed-identity-from-azure-web-app-functions-14566e5a0f1a

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM