Before using Azure Container Apps (ACA), I deployed my applications on Kubernetes (AKS). In AKS, I only had to set environment variables for authentication, and the Python SDK for Azure would connect to my subscription seamlessly.
Now, I need to migrate my app to ACA, but in a different subscription while still requiring access to resources in the original subscription.
Context: My team (Team A) has been granted permission by our security officer to continue using a Service Principal to access Subscription A. We are working in a Hub-and-Spoke configuration, where network flows are open between Subscription A and Subscription B. However, Team B does not want to grant permissions to our Service Principal to access MySQL in Subscription B. Instead, they have configured System Assigned Managed Identity (MSI) for our ACA instance. What works: Currently, my Django application successfully accesses resources in Subscription A using DefaultAzureCredential, with the following environment variables:
- AZURE_TENANT_ID
- AZURE_CLIENT_ID
- AZURE_CLIENT_SECRET
This setup works fine when accessing Subscription A from Subscription B.
The issue: My MySQL database is in Subscription B, and I need to authenticate using the System Assigned Managed Identity (MSI) instead of the Service Principal.
Question: How can I use System Assigned Identity for MySQL in Django while keeping the rest of my Python code authenticated via DefaultAzureCredential (which still needs the Service Principal)?
My Django settings: I tried configuring the database connection as follows:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": env("DATABASE_NAME"),
"HOST": env("DATABASE_HOST"),
"PORT": 3306,
"CONN_MAX_AGE": env.int("DATABASE_CONN_MAX_AGE", default=0),
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryMsi;Encrypt=yes;TrustServerCertificate=no",
},
}
}
Error received: I get the following error:
File "/home/docker4sg/miniconda3/envs/py310/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 200, in get_new_connection
conn = Database.connect(**conn_params)
TypeError: 'driver' is an invalid keyword argument for this function
I think this error is linked to a bad driver installation. And it's not linked to SP/MSI.
Debugging with az cli
:
When I tried debugging using Azure CLI, I ran:
az login --identity
And got this error:
Failed to connect to MSI. Please make sure MSI is configured correctly.
Get Token request returned: <Response [405]>
I found this post suggesting a workaround, so I tried:
az login --identity
No access was configured for the VM, hence no subscriptions were found. If this is expected, use '--allow-no-subscriptions' to have tenant level access.
Is it possible to use both a Service Principal (via DefaultAzureCredential
) and System Assigned Identity (for MySQL) at the same time?
If so, how can I configure Django to use System Assigned Identity for MySQL, while keeping DefaultAzureCredential for the rest of the Python SDK calls?
EDIT:
Some more debug, using ManagedIdentityCredential
:
from azure.identity import ManagedIdentityCredential
credential = ManagedIdentityCredential(
client_id="XXXXXXX-XXXX-XXXX-XXXX-XXXXXXX",
)
I get this error:
azure.identity._exceptions.CredentialUnavailableError: App Service managed identity configuration not found in environment. invalid_scope
Removing the client_id
I don't get an error on the auth, I can get a token.
from azure.identity import ManagedIdentityCredential
credential = ManagedIdentityCredential()
token_msi = credential.get_token(
"/.default"
).token
import pymysql
pymysql.connect(
host="xxxxxxxxxxxxx.mysql.database.azure",
user="xxxxxx-xxxx-xxxx-xxxx-xxxxxx",
password=token_msi,
db="my_db",
)
And I get:
pymysql.err.OperationalError: (1045, "Access denied for user '52181d1e-0ab2-4e0c-b19d-876223d1f44d'@'10.34.45.173' (using password: YES)")
I've checked in the IAM, and it has the correct roles. But I don't have any database created.
Before using Azure Container Apps (ACA), I deployed my applications on Kubernetes (AKS). In AKS, I only had to set environment variables for authentication, and the Python SDK for Azure would connect to my subscription seamlessly.
Now, I need to migrate my app to ACA, but in a different subscription while still requiring access to resources in the original subscription.
Context: My team (Team A) has been granted permission by our security officer to continue using a Service Principal to access Subscription A. We are working in a Hub-and-Spoke configuration, where network flows are open between Subscription A and Subscription B. However, Team B does not want to grant permissions to our Service Principal to access MySQL in Subscription B. Instead, they have configured System Assigned Managed Identity (MSI) for our ACA instance. What works: Currently, my Django application successfully accesses resources in Subscription A using DefaultAzureCredential, with the following environment variables:
- AZURE_TENANT_ID
- AZURE_CLIENT_ID
- AZURE_CLIENT_SECRET
This setup works fine when accessing Subscription A from Subscription B.
The issue: My MySQL database is in Subscription B, and I need to authenticate using the System Assigned Managed Identity (MSI) instead of the Service Principal.
Question: How can I use System Assigned Identity for MySQL in Django while keeping the rest of my Python code authenticated via DefaultAzureCredential (which still needs the Service Principal)?
My Django settings: I tried configuring the database connection as follows:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": env("DATABASE_NAME"),
"HOST": env("DATABASE_HOST"),
"PORT": 3306,
"CONN_MAX_AGE": env.int("DATABASE_CONN_MAX_AGE", default=0),
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"extra_params": "Authentication=ActiveDirectoryMsi;Encrypt=yes;TrustServerCertificate=no",
},
}
}
Error received: I get the following error:
File "/home/docker4sg/miniconda3/envs/py310/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 200, in get_new_connection
conn = Database.connect(**conn_params)
TypeError: 'driver' is an invalid keyword argument for this function
I think this error is linked to a bad driver installation. And it's not linked to SP/MSI.
Debugging with az cli
:
When I tried debugging using Azure CLI, I ran:
az login --identity
And got this error:
Failed to connect to MSI. Please make sure MSI is configured correctly.
Get Token request returned: <Response [405]>
I found this post suggesting a workaround, so I tried:
az login --identity
No access was configured for the VM, hence no subscriptions were found. If this is expected, use '--allow-no-subscriptions' to have tenant level access.
Is it possible to use both a Service Principal (via DefaultAzureCredential
) and System Assigned Identity (for MySQL) at the same time?
If so, how can I configure Django to use System Assigned Identity for MySQL, while keeping DefaultAzureCredential for the rest of the Python SDK calls?
EDIT:
Some more debug, using ManagedIdentityCredential
:
from azure.identity import ManagedIdentityCredential
credential = ManagedIdentityCredential(
client_id="XXXXXXX-XXXX-XXXX-XXXX-XXXXXXX",
)
I get this error:
azure.identity._exceptions.CredentialUnavailableError: App Service managed identity configuration not found in environment. invalid_scope
Removing the client_id
I don't get an error on the auth, I can get a token.
from azure.identity import ManagedIdentityCredential
credential = ManagedIdentityCredential()
token_msi = credential.get_token(
"https://ossrdbms-aad.database.windows/.default"
).token
import pymysql
pymysql.connect(
host="xxxxxxxxxxxxx.mysql.database.azure",
user="xxxxxx-xxxx-xxxx-xxxx-xxxxxx",
password=token_msi,
db="my_db",
)
And I get:
pymysql.err.OperationalError: (1045, "Access denied for user '52181d1e-0ab2-4e0c-b19d-876223d1f44d'@'10.34.45.173' (using password: YES)")
I've checked in the IAM, and it has the correct roles. But I don't have any database created.
Share Improve this question edited Mar 18 at 13:53 BeGreen asked Mar 18 at 9:06 BeGreenBeGreen 9531 gold badge19 silver badges53 bronze badges 3 |1 Answer
Reset to default 0Here is the solution to connect directly to mysql server from Azure.
from azure.identity import ManagedIdentityCredential
import pymysql
# Get Managed Identity Token
credential = ManagedIdentityCredential()
token_msi = credential.get_token(
"https://ossrdbms-aad.database.windows/.default"
).token
# Define connection parameters
connection = pymysql.connect(
host=f"xxxxxxxx.mysql.database.azure",
user="xxxx", # Predefined my an alias from team B. I did not use the client_id
password=token_msi,
db=f"xxxx", # Same here, they made a db with the name of the project
ssl={"fake_flag_to_enable_tls": True}
)
# Execute a query
query = "SHOW DATABASES;"
with connection.cursor() as cursor:
cursor.execute(query)
print(cursor.fetchall())
For Django I had to do a bit more, in settings.py
from .get_azure_token import get_db_token
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "xxxx",
"USER": "xxxx",
"PASSWORD": None, # Token will be assigned dynamically
"HOST": f"xxxxx.mysql.database.azure",
"PORT": 3306,
}
}
get_db_token()
I had to pip install mysqlclient
+ azure-identity
. Also had to install a MySQL Client CLI on the linux for Django to work. Did not managed to make it work with pymysql
which is pure python implementation of mysql client.
Made a file get_azure_token
with this content:
import os
import django.conf as conf
from azure.identity import ManagedIdentityCredential
def get_db_token():
azure_credential = ManagedIdentityCredential()
token = azure_credential.get_token(
"https://ossrdbms-aad.database.windows"
).token
conf.settings.DATABASES["default"]["PASSWORD"] = token
You can use DefaultAzureCredential
instead of ManagedIdentityCredential
if you want to adapt the way you connect. I my case I needed the System Identity to connect instead of the Service Principal declare in environment variables.
DefaultAzureCredential
) for Subscription A and a System Assigned Managed Identity (MSI) for MySQL in Subscription B, configure your Django database connection to useManagedIdentityCredential
for MySQL authentication andDefaultAzureCredential
for other Azure SDK calls. Set up a custom connection usingmysql-connector-python
with MSI authentication for MySQL, while keeping the rest of the app authenticated viaDefaultAzureCredential
. Ensure your ACA instance has the required permissions on the MySQL server. – Rukmini Commented Mar 18 at 12:26ManagedIdentityCredential
I get this error:azure.identity._exceptions.CredentialUnavailableError: App Service managed identity configuration not found in environment. invalid_scope
But it seems to be a good strategy to use specific auth and not the default one that uses var env as priority 1. – BeGreen Commented Mar 18 at 13:48ManagedIdentityCredential
withoutclient_id
argument. – BeGreen Commented Mar 19 at 8:00