Esercitazione: Connettersi ai database di Azure da Servizio app senza segreti usando un'identità gestita
Articolo
Il Servizio app fornisce un servizio di hosting Web ad alta scalabilità e con funzioni di auto-correzione in Azure. Offre anche un'identità gestita per l'app, una soluzione chiavi in mano per proteggere l'accesso ai database di Azure, tra cui:
Le identità gestite nel servizio app rendono l'app più sicura eliminando i segreti dall'app, ad esempio le credenziali nelle stringhe di connessione. Questa esercitazione illustra come connettersi ai database indicati in precedenza dal Servizio app usando identità gestite.
Contenuto dell'esercitazione:
Configurare un utente di Microsoft Entra come amministratore per il database di Azure.
Connettersi al database come e di Microsoft Entra.
Configurare un'identità gestita assegnata dal sistema o dall'utente per un'app del Servizio app.
Concedere all'identità gestita l'accesso al database.
Connettersi al database di Azure dal codice (.NET Framework 4.8, .NET 6, Node.js, Python, Java) usando un'identità gestita.
Connettersi al database di Azure dall'ambiente di sviluppo usando l'utente Microsoft Entra.
Creare un'app nel Servizio app basata su .NET, Node.js, Python o Java.
Creare un server di database con Database SQL di Azure, Database di Azure per MySQL o Database di Azure per PostgreSQL.
È necessario avere familiarità con il modello di connettività standard (con nome utente e password) e potersi connettere correttamente dall'app del Servizio app al database preferito.
Preparare l'ambiente per l'interfaccia della riga di comando di Azure.
Se si preferisce eseguire i comandi di riferimento dell'interfaccia della riga di comando in locale, installare l'interfaccia della riga di comando di Azure. Per l'esecuzione in Windows o macOS, è consigliabile eseguire l'interfaccia della riga di comando di Azure in un contenitore Docker. Per altre informazioni, vedere Come eseguire l'interfaccia della riga di comando di Azure in un contenitore Docker.
Se si usa un'installazione locale, accedere all'interfaccia della riga di comando di Azure con il comando az login. Per completare il processo di autenticazione, seguire la procedura visualizzata nel terminale. Per altre opzioni di accesso, vedere Accedere tramite l'interfaccia della riga di comando di Azure.
Eseguire az version per trovare la versione e le librerie dipendenti installate. Per eseguire l'aggiornamento alla versione più recente, eseguire az upgrade.
1. Installare l'estensione senza password del Connettore di servizi
Installare l'estensione senza password Connettore di servizi più recente per l'interfaccia della riga di comando di Azure:
az extension add --name serviceconnector-passwordless --upgrade
Nota
Verificare che la versione dell'estensione "serviceconnector-passwordless" sia "2.0.2" o successiva eseguendo az version. Potrebbe essere necessario aggiornare prima l'interfaccia della riga di comando di Azure per aggiornare la versione dell'estensione.
2. Creare una connessione senza password
Creare quindi una connessione senza password con Connettore di servizi.
Suggerimento
Il portale di Azure consente di comporre i comandi seguenti. Nel portale di Azure andare alla risorsa Servizio app di Azure, selezionare Connettore di servizi nel menu a sinistra seguito da Crea. Compilare il modulo con tutti i parametri obbligatori. Azure genera automaticamente il comando di creazione della connessione, che è possibile copiare da usare nell'interfaccia della riga di comando o eseguire in Azure Cloud Shell.
Per Database di Azure per MySQL - Server flessibile, è prima necessario configurare manualmente l'autenticazione di Microsoft Entra, che richiede un'identità gestita assegnata dall'utente separata e autorizzazioni specifiche di Microsoft Graph. Questo passaggio non può essere automatizzato.
Facoltativamente, eseguire il comando az webapp connection create mysql-flexible -h per ottenere i tipi di client supportati.
Scegliere un tipo di client ed eseguire il comando corrispondente. Il comando seguente dell'interfaccia della riga di comando di Azure usa un parametro --client-type.
Concedere l'autorizzazione alle tabelle create in modo preliminare
Successivamente, se si sono create tabelle e sequenze nel server flessibile PostgreSQL prima di usare Connettore di servizi, è necessario connettersi come proprietario e concedere l'autorizzazione alle <aad-username> create da Connettore di servizi. Il nome utente della stringa di connessione o della configurazione impostata da Connettore di servizi dovrebbe essere simile a aad_<connection name>. Se si usa il portale di Azure, selezionare il pulsante Espandi accanto alla colonna Service Type e ottenere il valore. Se si usa l'interfaccia della riga di comando di Azure, controllare configurations nell'output del comando dell'interfaccia della riga di comando.
Eseguire quindi la query per concedere l'autorizzazione
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> e <owner-password> sono i proprietari della tabella esistente che può concedere autorizzazioni ad altri utenti. <aad-username> è l'utente creato da Connettore di servizi. Sostituirlo con il valore effettivo.
Convalidare il risultato tramite il 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
Questo comando di Connettore servizio completa le attività seguenti in background:
Abilitare l'identità gestita assegnata dal sistema oppure assegnare un'identità utente per l'app <server-name> ospitata dal Servizio app di Azure.
Impostare l'amministratore di Microsoft Entra sull'utente connesso corrente.
Aggiungere un utente del database per l'identità gestita assegnata dal sistema o dall'utente. Concedere a questo utente tutti i privilegi del database <database-name>. Il nome utente è disponibile nella stringa di connessione nell'output del comando precedente.
Impostare le configurazioni denominate AZURE_MYSQL_CONNECTIONSTRING, AZURE_POSTGRESQL_CONNECTIONSTRING o AZURE_SQL_CONNECTIONSTRING sulla risorsa di Azure in base al tipo di database.
Per il Servizio app, le configurazioni vengono impostate nel pannello Impostazioni app.
Se si verificano problemi durante la creazione di una connessione, vedere Risoluzione dei problemi per assistenza.
Ottenere la stringa di connessione del database SQL di Azure dalla variabile di ambiente aggiunta dal connettore di servizi.
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();
Ottenere le configurazioni di connessione del database SQL di Azure dalla variabile di ambiente aggiunta dal connettore di servizi. Rimuovere il commento dalla parte del frammento di codice per il tipo di autenticazione che si vuole usare.
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)
Ottenere le configurazioni di connessione del database SQL di Azure dalle variabili di ambiente aggiunte dal connettore di servizi. Rimuovere il commento dalla parte del frammento di codice per il tipo di autenticazione che si vuole usare.
La connettività al Database di Azure per MySQL nel codice segue il criterio DefaultAzureCredential per tutti gli stack di linguaggi. DefaultAzureCredential è sufficientemente flessibile da adattarsi sia all'ambiente di sviluppo che all'ambiente di Azure. Quando viene eseguito in locale, può recuperare l'utente di Azure connesso dall'ambiente preferito (Visual Studio, Visual Studio Code, interfaccia della riga di comando di Azure o Azure PowerShell). Durante l'esecuzione in Azure, recupera l'identità gestita. È quindi possibile avere connettività al database sia in fase di sviluppo che di produzione. Il modello è il seguente:
Creare un'istanza di DefaultAzureCredential dalla libreria client di Azure Identity. Se si usa un'identità assegnata dall'utente, specificare l'ID client dell'identità.
Ottenere un token di accesso per Database di Azure per MySQL: https://ossrdbms-aad.database.windows.net/.default.
Per .NET, ottenere un token di accesso per l'identità gestita usando una libreria client, ad esempio Azure.Identity. Usare quindi il token di accesso come password per connettersi al database. Quando si usa il codice seguente, assicurarsi di rimuovere il commento dalla parte del frammento di codice corrispondente al tipo di autenticazione che si vuole usare.
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
Aggiungere le dipendenze seguenti nel file pom.xml:
Eseguire l'autenticazione con un token di accesso dalla libreria azure-identity. Ottenere le informazioni di connessione dalla variabile di ambiente aggiunta da Connettore di servizi. Quando si usa il codice seguente, assicurarsi di rimuovere il commento dalla parte del frammento di codice corrispondente al tipo di autenticazione che si vuole usare.
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()
Ottenere un token di accesso usando @azure/identity e le informazioni sul database MySQL di Azure dalle variabili di ambiente aggiunte dal Connettore di servizi. Quando si usa il codice seguente, assicurarsi di rimuovere il commento dalla parte del frammento di codice corrispondente al tipo di autenticazione che si vuole usare.
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 connettività al Database di Azure per PostgreSQL nel codice segue il criterio DefaultAzureCredential per tutti gli stack di linguaggi. DefaultAzureCredential è sufficientemente flessibile da adattarsi sia all'ambiente di sviluppo che all'ambiente di Azure. Quando viene eseguito in locale, può recuperare l'utente di Azure connesso dall'ambiente preferito (Visual Studio, Visual Studio Code, interfaccia della riga di comando di Azure o Azure PowerShell). Durante l'esecuzione in Azure, recupera l'identità gestita. È quindi possibile avere connettività al database sia in fase di sviluppo che di produzione. Il modello è il seguente:
Creare un'istanza di DefaultAzureCredential dalla libreria client di Azure Identity. Se si usa un'identità assegnata dall'utente, specificare l'ID client dell'identità.
Ottenere un token di accesso per Database di Azure per PostgreSQL: https://ossrdbms-aad.database.windows.net/.default.
Per .NET, ottenere un token di accesso per l'identità gestita usando una libreria client, ad esempio Azure.Identity. Usare quindi il token di accesso come password per connettersi al database. Quando si usa il codice seguente, assicurarsi di rimuovere il commento dalla parte del frammento di codice corrispondente al tipo di autenticazione che si vuole usare.
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();
}
Aggiungere le dipendenze seguenti nel file pom.xml:
Eseguire l'autenticazione con un token di accesso dalla libreria azure-identity e usare il token come password. Ottenere le informazioni di connessione dalle variabili di ambiente aggiunte da Connettore di servizi. Quando si usa il codice seguente, assicurarsi di rimuovere il commento dalla parte del frammento di codice corrispondente al tipo di autenticazione che si vuole usare.
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)
Per ulteriori informazioni, vedi le seguenti risorse:
Nel codice, ottenere il token di accesso tramite @azure/identity e le informazioni sulla connessione PostgreSQL dalle variabili di ambiente aggiunte dal servizio Connettore di servizi. Combinarli per stabilire la connessione. Quando si usa il codice seguente, assicurarsi di rimuovere il commento dalla parte del frammento di codice corrispondente al tipo di autenticazione che si vuole usare.
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();
})();
Questo codice di esempio usa DefaultAzureCredential per ottenere un token utilizzabile per il database di Azure dall'ID Microsoft Entra e quindi lo aggiunge alla connessione al database. Anche se è possibile personalizzare DefaultAzureCredential, è già versatile per impostazione predefinita. Ottiene un token dall'utente Microsoft Entra connesso o da un'identità gestita, a seconda che venga eseguito localmente nell'ambiente di sviluppo o nel Servizio app.
Senza ulteriori modifiche, il codice è pronto per l'esecuzione in Azure. Per eseguire il debug del codice in locale, tuttavia, l'ambiente di sviluppo richiede un utente connesso a Microsoft Entra. In questo passaggio si configura l'ambiente preferito accedendo con l'utente di Microsoft Entra.
Visual Studio per Windows è integrato con l'autenticazione di Microsoft Entra. Per abilitare lo sviluppo e il debug in Visual Studio, aggiungere l'utente Microsoft Entra in Visual Studio selezionando File>Impostazioni account nel menu e facendo clic su Accedi o Aggiungi.
Per impostare l'utente di Microsoft Entra per l'autenticazione dei servizi di Azure, scegliere Strumenti>Opzioni dal menu, quindi selezionare Azure Service Authentication (Autenticazione servizi di Azure)>Selezione account. Selezionare l'utente di Microsoft Entra aggiunto, quindi selezionare OK.
Visual Studio per Mac non è integrato con l'autenticazione di Microsoft Entra. Tuttavia, la libreria client di Azure Identity che verrà usata in un secondo momento può anche recuperare i token dall'interfaccia della riga di comando di Azure. Per abilitare lo sviluppo e il debug in Visual Studio, installare l'interfaccia della riga di comando di Azure nel computer locale.
Accedere all'interfaccia della riga di comando di Azure con il comando seguente usando l'utente di Microsoft Entra:
az login --allow-no-subscriptions
Visual Studio Code è integrato con l'autenticazione di Microsoft Entra tramite l'estensione Azure. Installare l'estensione Strumenti di Azure in Visual Studio Code.
Nella barra attività in Visual Studio Code selezionare il logo di Azure.
Nello strumento di esplorazione del Servizio app selezionare Accedi ad Azure e seguire le istruzioni.
La libreria client di Azure Identity che verrà usata in un secondo momento può usare i token dall'interfaccia della riga di comando di Azure. Per abilitare lo sviluppo basato sulla riga di comando, installare l'interfaccia della riga di comando di Azure nel computer locale.
Accedere ad Azure con il comando seguente usando l'utente di Microsoft Entra:
az login --allow-no-subscriptions
La libreria client di Azure Identity che verrà usata in un secondo momento può usare i token di Azure PowerShell. Per abilitare lo sviluppo basato su riga di comando, installare Azure PowerShell nel computer locale.
Accedere all'interfaccia della riga di comando di Azure con il cmdlet seguente usando l'utente di Microsoft Entra:
A questo punto è possibile iniziare a sviluppare l'app ed eseguirne il debug con il database SQL come back-end, usando l'autenticazione di Microsoft Entra.
5. Testare e pubblicare
Eseguire il codice nell'ambiente di sviluppo. Il codice usa l'utente connesso di Microsoft Entra nell'ambiente per connettersi al database back-end. L'utente può accedere al database perché è configurato come amministratore di Microsoft Entra per il database.
Pubblicare il codice in Azure usando il metodo di pubblicazione preferito. Nel Servizio app il codice usa l'identità gestita dell'app per connettersi al database back-end.
Viene visualizzato l'errore Login failed for user '<token-identified principal>'.
L'identità gestita per cui si sta tentando di richiedere un token non è autorizzata ad accedere al database di Azure.
Sono state apportate modifiche all'autenticazione del Servizio app o alla registrazione dell'app associata. Perché si ottiene ancora il vecchio token?
Anche i servizi back-end delle identità gestite gestiscono una cache di token che aggiorna il token per una risorsa di destinazione solo quando scade. Se si tenta di modificare la configurazione dopo aver provato a ottenere un token con l'applicazione, non si otterrà un nuovo token con le autorizzazioni aggiornate fino alla scadenza del token memorizzato nella cache. Il modo migliore per risolvere questo problema consiste nel testare le modifiche con una nuova finestra InPrivate (Edge)/privata (Safari)/Incognito (Chrome). In questo modo, si è sicuri di iniziare da una nuova sessione autenticata.
Come si aggiunge l'identità gestita a un gruppo Microsoft Entra?
Se lo si desidera, aggiungere l'identità a un gruppo Microsoft Entra, quindi concedere l'accesso al gruppo Microsoft Entra invece che all'identità. Ad esempio, i comandi seguenti aggiungono l'identità gestita del passaggio precedente a un nuovo gruppo denominato 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
Per concedere le autorizzazioni di database per un gruppo Microsoft Entra, vedere la documentazione relativa al tipo di database corrispondente.
Viene visualizzato l'errore SSL connection is required. Please specify SSL options and retry.
La connessione al database di Azure richiede impostazioni aggiuntive ed esula dall'ambito di questa esercitazione. Per ulteriori informazioni, vedere uno degli link seguenti:
Ho creato l'app con il modello App Web + Database e ora non posso configurare una connessione identità gestita con i comandi di Connettore di servizi.
Connettore di servizi richiede l'accesso di rete al database per concedere l'accesso per l'identità dell'app. Quando si crea un'architettura di database e app sicura per impostazione predefinita nel portale di Azure con il modello App Web + Database, l'architettura blocca l'accesso alla rete al database e consente solo le connessioni dall'interno della rete virtuale. Ciò vale anche per Azure Cloud Shell. Tuttavia, è possibile distribuire Cloud Shell nella rete virtuale, quindi eseguire il comando Connettore di servizi in tale Cloud Shell.
Passaggi successivi
Contenuto dell'esercitazione:
Configurare un utente di Microsoft Entra come amministratore per il database di Azure.
Connettersi al database come e di Microsoft Entra.
Configurare un'identità gestita assegnata dal sistema o dall'utente per un'app del Servizio app.
Concedere all'identità gestita l'accesso al database.
Connettersi al database di Azure dal codice (.NET Framework 4.8, .NET 6, Node.js, Python, Java) usando un'identità gestita.
Connettersi al database di Azure dall'ambiente di sviluppo usando l'utente Microsoft Entra.