请勿在 Web 应用程序中设置
AZURE_CLIENT_ID
和 AZURE_TENANT_ID
环境变量。另外,使用 DefaultAzureCredential
时,请执行以下操作:DefaultAzureCredential(exclude_environment_credential = False)
。
我有一个简单的 Python 应用程序,它使用 Docker 部署为 Azure Web 应用程序。应用程序本身正在运行,但无法与配置为仅允许通过托管标识进行身份验证的 Azure SQL 数据库连接。
我自己和应用程序的托管身份都已添加到安全组(我们称之为
my-group
)。我使用 az sql server create ... --external-admin-name my-group
创建了托管数据库的 SQL Server。这样做之后,我还运行了这些查询:
CREATE USER [my-group] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [my-group];
ALTER ROLE db_datawriter ADD MEMBER [my-group];
ALTER ROLE db_ddladmin ADD MEMBER [my-group];
以下代码也是我的应用程序的一部分,可以在没有 Docker 的情况下在本地运行,前提是我首先使用
az login
登录。 (使用 Docker 时,应用程序也无法连接到数据库,但其他一切都工作正常。)
from azure.identity import DefaultAzureCredential
def create_token_struct(databaseToken):
exptoken = b''
for i in bytes(databaseToken[0], "UTF-8"):
exptoken += bytes({i})
exptoken += bytes(1)
return struct.pack("=i", len(exptoken)) + exptoken
credential = DefaultAzureCredential()
pyodbc.connect(AZURE_SQL_CONNECTION_STRING, attrs_before = {1256: create_token_struct(credential.get_token('https://database.windows.net/'))})
连接字符串如下所示:
Driver={ODBC Driver 18 for SQL Server};Server=tcp:my-server-name.database.windows.net,1433;Database=my_database_name;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30
在 Azure 中运行时,应用程序在运行该代码时会返回错误。起初它只是给出了
Login timeout expired
错误,但在向我的 Azure Web 应用程序添加两个环境变量(AZURE_CLIENT_ID
和 AZURE_TENANT_ID
)后,我现在收到以下错误:
azure.core.exceptions.ClientAuthenticationError: DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
ManagedIdentityCredential: (None) No User Assigned or Delegated Managed Identity found for specified ClientId/ResourceId/PrincipalId.
Code: None
Message: No User Assigned or Delegated Managed Identity found for specified ClientId/ResourceId/PrincipalId.
To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.
环境变量的值通过运行
az webapp identity show
获取; AZURE_CLIENT_ID
设置为输出的 principalId
,并且 AZURE_TENANT_ID
设置为 tenantId
。我还尝试了其他值,例如应用程序的 Application ID
和安全组的 Object Id
。
我在这里缺少什么?我可以在本地访问数据库,因此,不知何故,Docker 容器似乎没有“接收”系统分配的 Azure Web App 托管标识。
这是我的 Dockerfile
FROM python:3.10
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
# For pyodbc
RUN apt-get update && apt-get -y install unixodbc-dev
RUN sh -c "curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -" \
&& apt-get update \
&& sh -c "curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list" \
&& apt-get update \
&& ACCEPT_EULA=Y apt-get install -y msodbcsql18 \
&& ACCEPT_EULA=Y apt-get install -y mssql-tools18
# Azure CLI
RUN sh -c "curl -sL https://aka.ms/InstallAzureCLIDeb | bash"
WORKDIR /app
COPY . /app
EXPOSE 8501
这对我有用 我创建了一个简单的 Flask 应用程序来从表中获取数据
Dockerfile
:
FROM python
RUN sh -c "curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -" \
&& apt-get update \
&& sh -c "curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list" \
&& apt-get update \
&& ACCEPT_EULA=Y apt-get install -y msodbcsql18 \
&& ACCEPT_EULA=Y apt-get install -y mssql-tools18
RUN pip install gunicorn
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 5000
ENTRYPOINT [ "gunicorn", "app:app"]
app.py
:
from flask import Flask, render_template_string
import azure.identity as ad
import pyodbc
import struct
import json
app = Flask(__name__)
@app.route('/')
def hello():
message = "Greetings! Wecome to Flask App"
try:
cred = ad.DefaultAzureCredential()
Connectionstring = "Driver={ODBC Driver 18 for SQL Server};Server=tcp:mi-in-docker-server.database.windows.net,1433;Database=manageidentyindocker;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30"
with pyodbc.connect(Connectionstring,attrs_before = {1256: create_token_struct(cred.get_token('https://database.windows.net/'))}) as conn:
with conn.cursor() as cursor:
cursor.execute("Select * from Users;")
data= []
data = cursor.fetchall() # Fetch the result
return str(data)
except pyodbc.Error as e:
return(f"SQL query failed: {e}")
def create_token_struct(databaseToken):
exptoken = b''
for i in bytes(databaseToken[0], "UTF-8"):
exptoken += bytes({i})
exptoken += bytes(1)
return struct.pack("=i", len(exptoken)) + exptoken
app.run(host='0.0.0.0', port=5000)
INPUT
:为网络应用程序的系统分配身份分配角色:
注意: 您可以在 Azure 中使用 Microsoft Entra 身份验证登录时分配角色。
DECLARE @USERNAME nvarchar(128)
SET @USERNAME = 'my-system-assign-identity-name'
BEGIN
EXECUTE('CREATE USER "' + @USERNAME + '" FROM EXTERNAL PROVIDER');
EXECUTE('ALTER ROLE db_datareader ADD MEMBER "' + @USERNAME + '"');
EXECUTE('ALTER ROLE db_datawriter ADD MEMBER "' + @USERNAME + '"');
EXECUTE('ALTER ROLE db_ddladmin ADD MEMBER "' + @USERNAME + '"')
END
创建表格
Users
OUTPUT
:有关参考,请查看此问答帖子。