Tutorial: Conexión a bases de datos de Azure desde App Service sin secretos mediante una identidad administrada
Artículo
App Service proporciona un servicio de hospedaje web muy escalable y con aplicación de revisiones de un modo automático en Azure. También proporciona una identidad administrada para la aplicación, la cual constituye una solución inmediata para proteger el acceso a bases de datos de Azure, entre las que se incluyen:
Las identidades administradas de App Service hacen que su aplicación sea más segura mediante la eliminación de los secretos de aplicación como, por ejemplo, las credenciales en las cadenas de conexión. En este tutorial se muestra cómo conectarse a las bases de datos mencionadas anteriormente desde App Service mediante identidades administradas.
Lo qué aprenderá:
Configure un usuario de Microsoft Entra como administrador para la base de datos de Azure.
Conéctese a la base de datos como usuario de Microsoft Entra.
Configuración de una identidad administrada asignada por el sistema o por el usuario para una aplicación de App Service.
Concesión del acceso a la base de datos a la identidad administrada.
Conexión a la base de datos de Azure desde el código (.NET Framework 4.8, .NET 6, Node.js, Python, Java) mediante una identidad administrada.
Conéctese a la base de datos Azure desde su entorno de desarrollo mediante el usuario Microsoft Entra.
Creación de una aplicación en App Service basada en .NET, Node.js, Python o Java.
Creación de un servidor de base de datos con Azure SQL Database, Azure Database for MySQL o Azure Database for PostgreSQL.
Debe estar familiarizado con el patrón de conectividad estándar (con nombre de usuario y contraseña) y poder conectarse correctamente desde la aplicación App Service a la base de datos que prefiera.
Si prefiere ejecutar comandos de referencia de la CLI localmente, instale la CLI de Azure. Si utiliza Windows o macOS, considere la posibilidad de ejecutar la CLI de Azure en un contenedor Docker. Para más información, vea Ejecución de la CLI de Azure en un contenedor de Docker.
Si usa una instalación local, inicie sesión en la CLI de Azure mediante el comando az login. Siga los pasos que se muestran en el terminal para completar el proceso de autenticación. Para ver otras opciones de inicio de sesión, consulte Inicio de sesión con la CLI de Azure.
En caso de que se le solicite, instale las extensiones de la CLI de Azure la primera vez que la use. Para más información sobre las extensiones, consulte Uso de extensiones con la CLI de Azure.
Ejecute az version para buscar cuál es la versión y las bibliotecas dependientes que están instaladas. Para realizar la actualización a la versión más reciente, ejecute az upgrade.
1. Instalar la extensión sin contraseña del conector de servicio
Instale la extensión sin contraseña más reciente del Conector de servicio para la CLI de Azure:
az extension add --name serviceconnector-passwordless --upgrade
Nota:
Para comprobar que la versión de "serviceconnector-passwordless" es "2.0.2" o posterior, ejecute az version. Es posible que tenga que actualizar primero la CLI de Azure para actualizar la versión de la extensión.
2. Creación de una conexión sin contraseña
A continuación, cree una conexión sin contraseña con el conector de servicio.
Sugerencia
Azure Portal puede ayudarle a redactar los comandos siguientes. En Azure Portal, vaya al recurso Azure App Service, seleccione Conector de servicio en el menú de la izquierda y seleccione Crear. Rellene el formulario con todos los parámetros necesarios. Azure genera automáticamente el comando de creación de conexión, que puede copiar para usarlo en la CLI o ejecutarlo en Azure Cloud Shell.
Para Azure Database for MySQL: servidor flexible, primero debe configurar manualmente la autenticación de Microsoft Entra, que requiere una identidad administrada asignada por el usuario independiente y permisos específicos de Microsoft Graph. Este paso no se puede automatizar.
A continuación, si ha creado tablas y secuencias en el servidor flexible de PostgreSQL antes de usar el conector de servicio, debe conectarse como propietario y conceder permiso a <aad-username>, que se crea mediante el conector de servicio. El nombre de usuario de la cadena de conexión o la configuración establecida por el conector de servicio debería parecerse a aad_<connection name>. Si usa Azure Portal, seleccione el botón expandir situado junto a la columna Service Type y obtenga el valor. Si usa la CLI de Azure, compruebe configurations en la salida del comando de la CLI.
A continuación, ejecute la consulta para conceder permiso
az extension add --name rdbms-connect
az postgres flexible-server execute -n <postgres-name> -u <owner-username> -p "<owner-password>" -d <database-name> --querytext "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"<aad-username>\";GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO \"<aad username>\";"
<owner-username> y <owner-password> es el propietario de la tabla existente que puede conceder permisos a otros usuarios. <aad-username> es el usuario creado por Service Connector. Reemplácelos por el valor real.
Valide el resultado con el comando:
az postgres flexible-server execute -n <postgres-name> -u <owner-username> -p "<owner-password>" -d <database-name> --querytext "SELECT distinct(table_name) FROM information_schema.table_privileges WHERE grantee='<aad-username>' AND table_schema='public';" --output table
Este comando del conector de servicio completa las siguientes tareas en segundo plano:
Habilite la identidad administrada asignada por el sistema o asigne una identidad de usuario para la aplicación <server-name> hospedada por Azure App Service.
Establezca el administrador de Microsoft Entra en el usuario que tiene actualmente la sesión iniciada.
Agregue un usuario de base de datos para la identidad administrada asignada por el sistema o la identidad administrada asignada por el usuario. Conceda todos los privilegios de la base de datos <database-name> a este usuario. El nombre de usuario se puede encontrar en la cadena de conexión en la salida del comando anterior.
Establezca configuraciones denominadas AZURE_MYSQL_CONNECTIONSTRING, AZURE_POSTGRESQL_CONNECTIONSTRING o AZURE_SQL_CONNECTIONSTRING en el recurso de Azure en función del tipo de base de datos.
Para App Service, las configuraciones se establecen en la hoja Configuración de la aplicación.
Si encuentra algún problema al crear una conexión, consulte Solución de problemas para obtener ayuda.
Obtenga la cadena de conexión de Azure SQL Database de la variable de entorno agregada por Service Connector.
using Microsoft.Data.SqlClient;
// AZURE_SQL_CONNECTIONSTRING should be one of the following:
// For system-assigned managed identity:"Server=tcp:<server-name>.database.windows.net;Database=<database-name>;Authentication=Active Directory Default;TrustServerCertificate=True"
// For user-assigned managed identity: "Server=tcp:<server-name>.database.windows.net;Database=<database-name>;Authentication=Active Directory Default;User Id=<client-id-of-user-assigned-identity>;TrustServerCertificate=True"
string connectionString =
Environment.GetEnvironmentVariable("AZURE_SQL_CONNECTIONSTRING")!;
using var connection = new SqlConnection(connectionString);
connection.Open();
Obtenga las configuraciones de conexión de Azure SQL Database de la variable de entorno agregada por Service Connector. Quite la marca de comentario de la parte del fragmento de código para el tipo de autenticación que desea usar.
import os;
import pyodbc
server = os.getenv('AZURE_SQL_SERVER')
port = os.getenv('AZURE_SQL_PORT')
database = os.getenv('AZURE_SQL_DATABASE')
authentication = os.getenv('AZURE_SQL_AUTHENTICATION') # The value should be 'ActiveDirectoryMsi'
# Uncomment the following lines according to the authentication type.
# For system-assigned managed identity.
# connString = f'Driver={{ODBC Driver 18 for SQL Server}};Server={server},{port};Database={database};Authentication={authentication};Encrypt=yes;'
# For user-assigned managed identity.
# client_id = os.getenv('AZURE_SQL_USER')
# connString = f'Driver={{ODBC Driver 18 for SQL Server}};Server={server},{port};Database={database};UID={client_id};Authentication={authentication};Encrypt=yes;'
conn = pyodbc.connect(connString)
Obtenga las configuraciones de conexión de Azure SQL Database de las variables de entorno agregadas por Service Connector. Quite la marca de comentario de la parte del fragmento de código para el tipo de autenticación que desea usar.
La conectividad con Azure Database for MySQL en el código sigue el patrón de DefaultAzureCredential para todas las pilas de lenguaje. DefaultAzureCredential es lo suficientemente flexible como para adaptarse al entorno de desarrollo y al entorno de Azure. Cuando se ejecuta localmente, puede recuperar el usuario de Azure que ha iniciado sesión en el entorno que prefiera (Visual Studio, Visual Studio Code, la CLI de Azure o Azure PowerShell). Cuando se ejecuta en Azure, recupera la identidad administrada. Por lo tanto, es posible tener conectividad con la base de datos tanto en tiempo de desarrollo como en producción. El patrón es el siguiente:
Cree una instancia de DefaultAzureCredential de la biblioteca cliente de la identidad de Azure. Si usa una identidad asignada por el usuario, especifique el id. de cliente de la identidad.
Obtenga un token de acceso para Azure Database for MySQL: https://ossrdbms-aad.database.windows.net/.default.
Para .NET, obtenga un token de acceso para la identidad administrada mediante una biblioteca cliente como Azure.Identity. A continuación, use el token de acceso como contraseña para conectarse a la base de datos. Al usar el código siguiente, asegúrese de quitar la marca de comentario de la parte del fragmento de código que corresponde al tipo de autenticación que desea usar.
using Azure.Core;
using Azure.Identity;
using MySqlConnector;
// Uncomment the following lines according to the authentication type.
// For system-assigned managed identity.
// var credential = new DefaultAzureCredential();
// For user-assigned managed identity.
// var credential = new DefaultAzureCredential(
// new DefaultAzureCredentialOptions
// {
// ManagedIdentityClientId = Environment.GetEnvironmentVariable("AZURE_MYSQL_CLIENTID");
// });
var tokenRequestContext = new TokenRequestContext(
new[] { "https://ossrdbms-aad.database.windows.net/.default" });
AccessToken accessToken = await credential.GetTokenAsync(tokenRequestContext);
// Open a connection to the MySQL server using the access token.
string connectionString =
$"{Environment.GetEnvironmentVariable("AZURE_MYSQL_CONNECTIONSTRING")};Password={accessToken.Token}";
using var connection = new MySqlConnection(connectionString);
Console.WriteLine("Opening connection using access token...");
await connection.OpenAsync();
// do something
Agregue las siguientes dependencias al archivo pom.xml:
Autentíquese con un token de acceso desde la biblioteca azure-identity. Obtenga la información de conexión de la variable de entorno agregada por conector de servicio. Al usar el código siguiente, asegúrese de quitar la marca de comentario de la parte del fragmento de código que corresponde al tipo de autenticación que desea usar.
from azure.identity import ManagedIdentityCredential, ClientSecretCredential
import mysql.connector
import os
# Uncomment the following lines according to the authentication type.
# For system-assigned managed identity.
# cred = ManagedIdentityCredential()
# For user-assigned managed identity.
# managed_identity_client_id = os.getenv('AZURE_MYSQL_CLIENTID')
# cred = ManagedIdentityCredential(client_id=managed_identity_client_id)
# acquire token
accessToken = cred.get_token('https://ossrdbms-aad.database.windows.net/.default')
# open connect to Azure MySQL with the access token.
host = os.getenv('AZURE_MYSQL_HOST')
database = os.getenv('AZURE_MYSQL_NAME')
user = os.getenv('AZURE_MYSQL_USER')
password = accessToken.token
cnx = mysql.connector.connect(user=user,
password=password,
host=host,
database=database)
cnx.close()
Obtenga un token de acceso mediante @azure/identity y la información de la base de datos de Azure MySQL de las variables de entorno agregadas por Conector de servicio. Al usar el código siguiente, asegúrese de quitar la marca de comentario de la parte del fragmento de código que corresponde al tipo de autenticación que desea usar.
import { DefaultAzureCredential,ClientSecretCredential } from "@azure/identity";
const mysql = require('mysql2');
// Uncomment the following lines according to the authentication type.
// for system-assigned managed identity
// const credential = new DefaultAzureCredential();
// for user-assigned managed identity
// const clientId = process.env.AZURE_MYSQL_CLIENTID;
// const credential = new DefaultAzureCredential({
// managedIdentityClientId: clientId
// });
// acquire token
var accessToken = await credential.getToken('https://ossrdbms-aad.database.windows.net/.default');
const connection = mysql.createConnection({
host: process.env.AZURE_MYSQL_HOST,
user: process.env.AZURE_MYSQL_USER,
password: accessToken.token,
database: process.env.AZURE_MYSQL_DATABASE,
port: process.env.AZURE_MYSQL_PORT,
ssl: process.env.AZURE_MYSQL_SSL
});
connection.connect((err) => {
if (err) {
console.error('Error connecting to MySQL database: ' + err.stack);
return;
}
console.log('Connected to MySQL database');
});
La conectividad con Azure Database for PostgreSQL en el código sigue el patrón de DefaultAzureCredential para todas las pilas de lenguaje. DefaultAzureCredential es lo suficientemente flexible como para adaptarse al entorno de desarrollo y al entorno de Azure. Cuando se ejecuta localmente, puede recuperar el usuario de Azure que ha iniciado sesión en el entorno que prefiera (Visual Studio, Visual Studio Code, la CLI de Azure o Azure PowerShell). Cuando se ejecuta en Azure, recupera la identidad administrada. Por lo tanto, es posible tener conectividad con la base de datos tanto en tiempo de desarrollo como en producción. El patrón es el siguiente:
Cree una instancia de DefaultAzureCredential de la biblioteca cliente de la identidad de Azure. Si usa una identidad asignada por el usuario, especifique el id. de cliente de la identidad.
Obtenga un token de acceso para Azure Database for PostgreSQL: https://ossrdbms-aad.database.windows.net/.default.
Para .NET, obtenga un token de acceso para la identidad administrada mediante una biblioteca cliente como Azure.Identity. A continuación, use el token de acceso como contraseña para conectarse a la base de datos. Al usar el código siguiente, asegúrese de quitar la marca de comentario de la parte del fragmento de código que corresponde al tipo de autenticación que desea usar.
using Azure.Identity;
using Azure.Core;
using Npgsql;
// Uncomment the following lines according to the authentication type.
// For system-assigned identity.
// var sqlServerTokenProvider = new DefaultAzureCredential();
// For user-assigned identity.
// var sqlServerTokenProvider = new DefaultAzureCredential(
// new DefaultAzureCredentialOptions
// {
// ManagedIdentityClientId = Environment.GetEnvironmentVariable("AZURE_POSTGRESQL_CLIENTID");
// }
// );
// Acquire the access token.
AccessToken accessToken = await sqlServerTokenProvider.GetTokenAsync(
new TokenRequestContext(scopes: new string[]
{
"https://ossrdbms-aad.database.windows.net/.default"
}));
// Combine the token with the connection string from the environment variables provided by Service Connector.
string connectionString =
$"{Environment.GetEnvironmentVariable("AZURE_POSTGRESQL_CONNECTIONSTRING")};Password={accessToken.Token}";
// Establish the connection.
using (var connection = new NpgsqlConnection(connectionString))
{
Console.WriteLine("Opening connection using access token...");
connection.Open();
}
Agregue las siguientes dependencias al archivo pom.xml:
Autentíquese con un token de acceso desde la biblioteca azure-identity y use el token como contraseña. Obtenga la información de conexión de las variables de entorno agregadas por el conector de servicio. Al usar el código siguiente, asegúrese de quitar la marca de comentario de la parte del fragmento de código que corresponde al tipo de autenticación que desea usar.
from azure.identity import DefaultAzureCredential
import psycopg2
# Uncomment the following lines according to the authentication type.
# For system-assigned identity.
# cred = DefaultAzureCredential()
# For user-assigned identity.
# managed_identity_client_id = os.getenv('AZURE_POSTGRESQL_CLIENTID')
# cred = ManagedIdentityCredential(client_id=managed_identity_client_id)
# Acquire the access token
accessToken = cred.get_token('https://ossrdbms-aad.database.windows.net/.default')
# Combine the token with the connection string from the environment variables added by Service Connector to establish the connection.
conn_string = os.getenv('AZURE_POSTGRESQL_CONNECTIONSTRING')
conn = psycopg2.connect(conn_string + ' password=' + accessToken.token)
Para obtener más información, consulte los siguientes recursos:
En el código, obtenga el token de acceso a través de @azure/identity y la información de conexión de PostgreSQL a partir de variables de entorno agregadas por el conector de servicio. Combínelos para establecer la conexión. Al usar el código siguiente, asegúrese de quitar la marca de comentario de la parte del fragmento de código que corresponde al tipo de autenticación que desea usar.
import { DefaultAzureCredential, ClientSecretCredential } from "@azure/identity";
const { Client } = require('pg');
// Uncomment the following lines according to the authentication type.
// For system-assigned identity.
// const credential = new DefaultAzureCredential();
// For user-assigned identity.
// const clientId = process.env.AZURE_POSTGRESQL_CLIENTID;
// const credential = new DefaultAzureCredential({
// managedIdentityClientId: clientId
// });
// Acquire the access token.
var accessToken = await credential.getToken('https://ossrdbms-aad.database.windows.net/.default');
// Use the token and the connection information from the environment variables added by Service Connector to establish the connection.
(async () => {
const client = new Client({
host: process.env.AZURE_POSTGRESQL_HOST,
user: process.env.AZURE_POSTGRESQL_USER,
password: accesstoken.token,
database: process.env.AZURE_POSTGRESQL_DATABASE,
port: Number(process.env.AZURE_POSTGRESQL_PORT) ,
ssl: process.env.AZURE_POSTGRESQL_SSL
});
await client.connect();
await client.end();
})();
Este código de ejemplo usa DefaultAzureCredential para obtener un token utilizable para la base de datos de Azure desde Microsoft Entra ID y, a continuación, lo agrega a la conexión de base de datos. Aunque puede personalizar DefaultAzureCredential, ya es muy versátil de manera predeterminada. Obtiene un token del usuario de Microsoft Entra ID que ha iniciado sesión o de una identidad administrada, en función de si lo ejecuta localmente en el entorno de desarrollo o en App Service.
Sin más cambios, el código está listo para ejecutarse en Azure. Sin embargo, para depurar el código localmente, el entorno de desarrollo necesita un usuario de Microsoft Entra que haya iniciado sesión. En este paso, configurará el entorno que prefiera iniciando sesión con el usuario de Microsoft Entra.
Visual Studio para Windows es integrado con la autenticación de Microsoft Entra. Para habilitar el desarrollo y la depuración en Visual Studio, agregue el usuario de Microsoft Entra en Visual Studio; para ello, seleccione Archivo>Configuración de la cuenta en el menú y seleccione Iniciar sesión o Agregar.
Para establecer el usuario de Microsoft Entra para la autenticación de servicio de Azure, seleccione Herramientas>Opciones en el menú y, después, Autenticación del servicio de Azure>Selección de cuentas. Seleccione el usuario de Microsoft Entra que agregó y seleccione Aceptar.
Visual Studio para Mac no está integrado con la autenticación de Microsoft Entra. Sin embargo, la biblioteca cliente de la identidad de Azure que usará más adelante también puede recuperar tokens de la CLI de Azure. Para habilitar el desarrollo y la depuración en Visual Studio, instale la CLI de Azure en la máquina local.
Inicie sesión en la CLI de Azure con el comando siguiente mediante el usuario de Microsoft Entra:
az login --allow-no-subscriptions
Visual Studio Code se integra con la autenticación de Microsoft Entra a través de la extensión de Azure. Instale la extensión de Azure Tools en Visual Studio Code.
En Visual Studio Code, en la barra de actividades, seleccione el logotipo de Azure.
En el explorador de App Service, seleccione Iniciar sesión en Azure... y siga las instrucciones.
La biblioteca cliente de identidad de Azure que usará más adelante puede usar tokens de la CLI de Azure. Para habilitar el desarrollo basado en la línea de comandos, instale la CLI de Azure en el equipo local.
Inicie sesión en Azure con el siguiente comando mediante el usuario de Microsoft Entra:
az login --allow-no-subscriptions
La biblioteca cliente de identidad de Azure que usará más adelante puede usar tokens de Azure PowerShell. Para habilitar el desarrollo basado en la línea de comandos, instale Azure PowerShell en el equipo local.
Inicie sesión en la CLI de Azure con el siguiente cmdlet mediante el usuario de Microsoft Entra:
Ahora está listo para desarrollar y depurar la aplicación con SQL Database como back-end y mediante la autenticación de Microsoft Entra.
5. Prueba y publicación
Ejecute el código en el entorno de desarrollo. El código usa el usuario de Microsoft Entra que ha iniciado sesión en su entorno para conectarse a la base de datos back-end. El usuario puede acceder a la base de datos porque está configurado como administrador de Microsoft Entra para la base de datos.
Publique el código en Azure mediante el método de publicación preferido. En App Service, el código usa la identidad administrada de la aplicación para conectarse a la base de datos de back-end.
Obtengo el error Login failed for user '<token-identified principal>'.
La identidad administrada para la que está intentando solicitar un token no está autorizada a acceder a la base de datos de Azure.
He realizado cambios en la autenticación de App Service o en el registro de aplicaciones asociado. ¿Por qué todavía recibo el token anterior?
Los servicios de back-end de las identidades administradas también mantienen una caché de token que actualiza el token de un recurso de destino solo cuando expira. Si modifica la configuración después de intentar obtener un token con su aplicación, no obtendrá realmente un token nuevo con permisos actualizados hasta que expire el token de la caché. La mejor manera de solucionar esto es probar los cambios con una nueva ventana InPrivate (Edge), private (Safari), Incógnito (Chrome). De este modo, está seguro de empezar desde una nueva sesión autenticada.
¿Cómo se agrega la identidad administrada a un grupo de Microsoft Entra?
Si lo desea, puede agregar la identidad a un grupo de Microsoft Entra y, a continuación, conceder acceso al grupo Microsoft Entra en lugar de a la identidad. Por ejemplo, los siguientes comandos agregan la identidad administrada del paso anterior a un nuevo grupo llamado myAzureSQLDBAccessGroup:
groupid=$(az ad group create --display-name myAzureSQLDBAccessGroup --mail-nickname myAzureSQLDBAccessGroup --query objectId --output tsv)
msiobjectid=$(az webapp identity show --resource-group <group-name> --name <app-name> --query principalId --output tsv)
az ad group member add --group $groupid --member-id $msiobjectid
az ad group member list -g $groupid
Para conceder permisos de base de datos para un grupo de Microsoft Entra, consulte la documentación del tipo de base de datos correspondiente.
Obtengo el error SSL connection is required. Please specify SSL options and retry.
La conexión a la base de datos de Azure requiere una configuración adicional y está fuera del ámbito de este tutorial. Para más información, consulte uno de los siguientes vínculos:
He creado mi aplicación con la plantilla Aplicación web + base de datos y ahora no puedo configurar una conexión de identidad administrada con los comandos del Conector de servicios.
El conector de servicio necesita acceso a la red de la base de datos para conceder acceso a la identidad de la aplicación. Cuando crea una arquitectura de aplicación y base de datos segura de forma predeterminada en Azure Portal con la plantilla Aplicación web + base de datos, la arquitectura bloquea el acceso de red a la base de datos y solo permite conexiones desde dentro de la red virtual. También es cierto para Azure Cloud Shell. Sin embargo, puede implementar Cloud Shell en la red virtual, y después ejecutar el comando del conector de servicio en ese Cloud Shell.
Pasos siguientes
¿Qué ha aprendido?
Configure un usuario de Microsoft Entra como administrador para la base de datos de Azure.
Conéctese a la base de datos como usuario de Microsoft Entra.
Configuración de una identidad administrada asignada por el sistema o por el usuario para una aplicación de App Service.
Concesión del acceso a la base de datos a la identidad administrada.
Conexión a la base de datos de Azure desde el código (.NET Framework 4.8, .NET 6, Node.js, Python, Java) mediante una identidad administrada.
Conéctese a la base de datos Azure desde su entorno de desarrollo mediante el usuario Microsoft Entra.