Since I had to spend a few hours figuring this out, and all examples/docs are wrong, here’s an example of how to use Python in an Azure Function to connect to an Azure PaaS database without credentials by utilizing the managed identity of the azure function app.
__init__.py:
import logging
import os
import pyodbc
import requests
import struct
import sys
import azure.functions as func
resource_uri="https://database.windows.net/"
sql_server="XXXXXX.database.windows.net"
sql_database="primary"
def get_bearer_token(resource_uri):
identity_endpoint = os.environ["IDENTITY_ENDPOINT"]
identity_header = os.environ["IDENTITY_HEADER"]
logging.info('identity_endpoint: {}'.format(identity_endpoint))
logging.info('identity_header : {}'.format(identity_header))
token_auth_uri = f"{identity_endpoint}?resource={resource_uri}&api-version=2017-09-01"
head_msi = {'X-IDENTITY-HEADER':identity_header}
resp = requests.get(token_auth_uri, headers=head_msi)
access_token = resp.json()['access_token']
logging.info('response received from token endpoint: {}'.format(access_token))
return access_token
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Function Starting')
try:
access_token = get_bearer_token(resource_uri)
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:{},1433;Database={}".format(sql_server,sql_database), attrs_before = { 1256:bytearray(tokenstruct) })
logging.info('connected to {} on {}'.format(sql_server,sql_database))
cursor = conn.cursor()
cursor.execute("select @@version")
row = cursor.fetchall()
logging.info('sql data: {}'.format(row[0]))
logging.info('finished')
except BaseException as error:
logging.info('An exception occurred: {}'.format(error))
return func.HttpResponse("done!")
requirements.txt:
astroid==2.4.2
azure-functions==1.2.1
certifi==2020.6.20
chardet==3.0.4
colorama==0.4.3
idna==2.9
isort==4.3.21
lazy-object-proxy==1.4.3
mccabe==0.6.1
pylint==2.5.3
pyodbc==4.0.30
requests==2.24.0
six==1.15.0
toml==0.10.1
urllib3==1.25.9
wrapt==1.12.1