Learn to enable managed identities for secure SQL database connections without exposing credentials in plain text.
In this article, you will learn how to enable managed identities to securely connect to a SQL database without exposing credentials in plain text. Managed identities allow an Azure resource (such as a Function App) to authenticate with Azure Active Directory (Azure AD) and access other resources that support Azure AD authentication.
Avoid hardcoding credentials in your source code. Instead, leverage managed identities to improve your security posture.
Initially, consider a Python script that connects to a SQL database by hardcoding the username and password. Hardcoding credentials is a major vulnerability since anyone with access to the code can see the sensitive data.
Copy
Ask AI
import pyodbcserver = 'mykodekloud.database.windows.net'database = 'products'username = 'dbAdmin'password = 'VeryStrongPassword#889'driver = '{ODBC Driver 17 for SQL Server}'with pyodbc.connect('DRIVER='+driver+';SERVER=tcp:'+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+password) as conn: with conn.cursor() as cursor: cursor.execute("SELECT TOP 3 name, collation_name FROM sys.databases") row = cursor.fetchone() while row: print(str(row[0]) + " " + str(row[1])) row = cursor.fetchone()
Using this method exposes your database to unauthorized access. While storing the connection string in Azure Key Vault is an option, a more secure alternative is to utilize managed identities.
Using Managed Identity for Azure AD Authentication
Managed identities enable your code to authenticate with Azure AD by obtaining a token. Azure SQL Database then uses this token for authentication without the need for a username and password. The following Python example shows the modifications needed to use Azure AD authentication via a managed identity:
Copy
Ask AI
import pyodbcimport structserver = 'mykodekloud.database.windows.net'database = 'products'driver = '{ODBC Driver 17 for SQL Server}'connection_string = 'DRIVER='+driver+';SERVER='+server+';DATABASE='+database# Authentication using Azure AD Managed Identity# Note: Ensure that 'Active DirectoryMsi' is formatted correctly as per driver support.conn = pyodbc.connect(connection_string + ';Authentication=Active DirectoryMsi')tokenstruct = struct.pack("=I", len(extoken)) + exptokenconn = pyodbc.connect(connection_string, attrs_before={SQL_COPT_SS_ACCESS_TOKEN: tokenstruct})with conn.cursor() as cursor: cursor.execute("SELECT TOP 3 name, collation_name FROM sys.databases") row = cursor.fetchone() while row: print(row[0]) row = cursor.fetchone()
In this code, the managed identity of the resource is used to securely retrieve authentication details from Azure AD without exposing any credentials.
Another approach is to configure your Function App to use a managed identity for accessing a Key Vault. The Function App obtains an access token from Azure AD, retrieves the connection string stored in the Key Vault, and uses it to connect securely to the SQL database.
The following PowerShell script deploys the infrastructure by creating a SQL server with a preloaded sample database (AdventureWorksLT), a Key Vault to securely store the connection string, and two Function Apps—one using a plain text connection string and the other using a managed identity:
Function Using Managed Identity to Access Key Vault
This function uses a system-assigned managed identity to request an access token. It then retrieves the connection string from Key Vault and connects to the SQL database:
Copy
Ask AI
# Input bindings are provided via the param block.param($Request, $TriggerMetadata)$keyVaultUrl = $env:AKV$resourceUri = 'https://vault.azure.net'$tokenAuthUri = $env:MSI_ENDPOINT + '?resource=' + $resourceUri + '&api-version=2017-09-01'$tokenResponse = Invoke-RestMethod -Uri $tokenAuthUri -Headers @{ "Secret" = "$env:MSI_SECRET" } -Method GET$token = $tokenResponse.access_token$connectionString = (Invoke-RestMethod -Method GET -Headers @{ "Authorization" = "Bearer $token" } -Uri "$keyVaultUrl/secrets/sql?api-version=7.1").value# Create a SQL connection$connection = New-Object System.Data.SqlClient.SqlConnection$connection.ConnectionString = $connectionString# Open the connection$connection.Open()# Create a SQL command to fetch table names$command = $connection.CreateCommand()$command.CommandText = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'"# Execute the command and fetch results$reader = $command.ExecuteReader()$tables = @()while ($reader.Read()) { $tables += $reader["TABLE_NAME"]}# Close the connection$connection.Close()# Return table names as the response$body = @{ tables = $tables } | ConvertTo-JsonPush-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [System.Net.HttpStatusCode]::OK Body = $body})
After configuring both functions, deploy the Function App. The deployment script creates the functions “GetDatabaseTables” (using a plain text connection string) and “GetDatabaseTablesMSI” (using managed identity):
Managed identities ensure that only Azure resources can authenticate using credentials stored in Azure AD. Since the source must be an Azure resource, on-premises solutions cannot directly use managed identities.There are two types of managed identities:
System-assigned Managed Identity: Tied directly to a single Azure resource, this identity is deleted if the resource is removed.
User-assigned Managed Identity: A separate Azure resource that can be associated with multiple resources and remains even if one resource is deleted.
After deployment, navigate to your Function App in the Azure portal to test the functions:
Plain Text Function:
This function returns a list of table names from the SQL database using a hardcoded connection string.
Managed Identity Function:
This function leverages a managed identity to authenticate with Azure AD, retrieve the connection string from Key Vault, and connect securely to the SQL database. If you encounter an error, it may be due to missing permissions for the Function App’s managed identity in Key Vault.
Ensure you configure the Key Vault access policy to grant the Function App’s managed identity permission to read secrets. Without this permission, the managed identity function will fail.
To add the required access policy:
In the Azure portal, navigate to the Key Vault’s Access Policies.
Add an access policy that grants the Function App’s managed identity permission to read secrets.
Save your changes.
Once the access policy is properly configured, the managed identity function will retrieve the connection string from the Key Vault and display the SQL table names. A typical JSON response might look like:
Managed identities provide a secure way for Azure resources to authenticate with other resources via Azure AD. In this article, we explored two approaches:
Using a plain text connection string (an insecure method)
Using a system-assigned managed identity to retrieve secrets from Azure Key Vault
This approach is applicable not only to PowerShell but also to other languages like C#, Python, or Java, whether you are using an official SDK or making direct REST API calls.Now, let’s move on to securing web applications.