マネージド ID がサポートされている Azure リソースには、Microsoft Entra 認証をサポートしている Azure リソースに接続するためにマネージド ID を指定するオプションが常に用意されています。 マネージド ID のサポートにより、開発者はコードで資格情報を管理しなくて済みます。 マネージド ID は、それをサポートしている Azure リソースを操作する場合に推奨される認証オプションです。 マネージド ID の概要をご覧ください。
このページでは、Azure Key Vault、Azure Storage、Microsoft SQL Server に接続できるように App Service を構成する方法について説明します。 マネージド ID をサポートしていて、Microsoft Entra 認証をサポートしているリソースに接続する任意の Azure リソースに対して同じ原則を使用できます。
コード サンプルでは、Azure ID クライアント ライブラリを使用します。これは、接続で使用されるアクセス トークンの取得など、多くの手順が自動的に処理されるため、推奨される方法です。
マネージド ID ではどのようなリソースに接続できますか?
マネージド ID は、Microsoft Entra 認証をサポートする任意のリソースに接続できます。 一般に、マネージド ID で接続できるようにするためにリソースで必要な特別なサポートはありません。
一部のリソースでは、Microsoft Entra 認証がサポートされておらず、またクライアント ライブラリでトークンによる認証もサポートされていない場合があります。 マネージド ID を使用して、コードやアプリケーション構成に保存することなく資格情報に安全にアクセスする方法のガイダンスを続けてお読みください。
マネージド ID を作成する
マネージド ID には、システム割り当てとユーザー割り当ての 2 種類があります。 システム割り当て ID は、1 つの Azure リソースに直接リンクされます。 Azure リソースが削除されると、ID も削除されます。 ユーザー割り当てマネージド ID は複数の Azure リソースに関連付けることができ、そのライフサイクルはそれらのリソースから独立しています。
ほとんどのシナリオでは、ユーザー割り当てマネージド ID を使用することをお勧めします。 使用しているソース リソースがユーザー割り当てマネージド ID をサポートしていない場合は、そのリソース プロバイダーのドキュメントを参照して、システム割り当てマネージド ID を持つように構成する方法を確認する必要があります。
重要
マネージド ID の作成に使用されるアカウントには、新しいユーザー割り当てマネージド ID を作成するための "マネージド ID 共同作成者" などのロールが必要です。
ユーザー割り当てマネージド ID を作成したら、マネージド ID の作成時に返される clientId と principalId の値を書き留めます。 principalId はアクセス許可の追加時に使用し、clientId はアプリケーションのコードで使用します。
App Service にユーザー割り当てマネージド ID を構成する
コードでマネージド ID を使用する前に、それを使用する App Service に割り当てる必要があります。 ユーザー割り当てマネージド ID を使用するように App Service を構成するプロセスでは、アプリ構成でマネージド ID のリソース識別子を指定する必要があります。
ID にアクセス許可を追加する
ユーザー割り当てマネージド ID を使用するように App Service を構成したら、その ID に必要なアクセス許可を付与します。 このシナリオでは、この ID を使用して Azure Storage を操作するため、 Azure ロール ベースのアクセス制御 (RBAC) システムを使用して ユーザー割り当てマネージド ID にリソースへのアクセス許可を付与する必要があります。
using Azure.Identity;
using Azure.Storage.Blobs;
// code omitted for brevity
// Specify the Client ID if using user-assigned managed identities
var clientID = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID");
var credentialOptions = new DefaultAzureCredentialOptions
{
ManagedIdentityClientId = clientID
};
var credential = new DefaultAzureCredential(credentialOptions);
var blobServiceClient1 = new BlobServiceClient(new Uri("<URI of Storage account>"), credential);
BlobContainerClient containerClient1 = blobServiceClient1.GetBlobContainerClient("<name of blob>");
BlobClient blobClient1 = containerClient1.GetBlobClient("<name of file>");
if (blobClient1.Exists())
{
var downloadedBlob = blobClient1.Download();
string blobContents = downloadedBlob.Value.Content.ToString();
}
import com.azure.identity.DefaultAzureCredential;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
// read the Client ID from your environment variables
String clientID = System.getProperty("Client_ID");
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
.managedIdentityClientId(clientID)
.build();
BlobServiceClient blobStorageClient = new BlobServiceClientBuilder()
.endpoint("<URI of Storage account>")
.credential(credential)
.buildClient();
BlobContainerClient blobContainerClient = blobStorageClient.getBlobContainerClient("<name of blob container>");
BlobClient blobClient = blobContainerClient.getBlobClient("<name of blob/file>");
if (blobClient.exists()) {
String blobContent = blobClient.downloadContent().toString();
}
import { DefaultAzureCredential } from "@azure/identity";
import { BlobServiceClient } from "@azure/storage-blob";
// Specify the Client ID if using user-assigned managed identities
const clientID = process.env.Managed_Identity_Client_ID;
const credential = new DefaultAzureCredential({
managedIdentityClientId: clientID
});
const blobServiceClient = new BlobServiceClient("<URI of Storage account>", credential);
const containerClient = blobServiceClient.getContainerClient("<name of blob>");
const blobClient = containerClient.getBlobClient("<name of file>");
async function downloadBlob() {
if (await blobClient.exists()) {
const downloadBlockBlobResponse = await blobClient.download();
const downloadedBlob = await streamToString(downloadBlockBlobResponse.readableStreamBody);
console.log("Downloaded blob content:", downloadedBlob);
}
}
async function streamToString(readableStream) {
return new Promise((resolve, reject) => {
const chunks = [];
readableStream.on("data", (data) => {
chunks.push(data.toString());
});
readableStream.on("end", () => {
resolve(chunks.join(""));
});
readableStream.on("error", reject);
});
}
downloadBlob().catch(console.error);
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
import os
# Specify the Client ID if using user-assigned managed identities
client_id = os.getenv("Managed_Identity_Client_ID")
credential = DefaultAzureCredential(managed_identity_client_id=client_id)
blob_service_client = BlobServiceClient(account_url="<URI of Storage account>", credential=credential)
container_client = blob_service_client.get_container_client("<name of blob>")
blob_client = container_client.get_blob_client("<name of file>")
def download_blob():
if blob_client.exists():
download_stream = blob_client.download_blob()
blob_contents = download_stream.readall().decode('utf-8')
print("Downloaded blob content:", blob_contents)
download_blob()
package main
import (
"context"
"fmt"
"io"
"os"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
)
func main() {
// The client ID for the user-assigned managed identity is read from the AZURE_CLIENT_ID env var
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
fmt.Printf("failed to obtain a credential: %v\n", err)
return
}
accountURL := "<URI of Storage account>"
containerName := "<name of blob>"
blobName := "<name of file>"
serviceClient, err := azblob.NewServiceClient(accountURL, cred, nil)
if err != nil {
fmt.Printf("failed to create service client: %v\n", err)
return
}
containerClient := serviceClient.NewContainerClient(containerName)
blobClient := containerClient.NewBlobClient(blobName)
// Check if the blob exists
_, err = blobClient.GetProperties(context.Background(), nil)
if err != nil {
fmt.Printf("failed to get blob properties: %v\n", err)
return
}
// Download the blob
downloadResponse, err := blobClient.Download(context.Background(), nil)
if err != nil {
fmt.Printf("failed to download blob: %v\n", err)
return
}
// Read the blob content
blobData := downloadResponse.Body(nil)
defer blobData.Close()
blobContents := new(strings.Builder)
_, err = io.Copy(blobContents, blobData)
if err != nil {
fmt.Printf("failed to read blob data: %v\n", err)
return
}
fmt.Println("Downloaded blob content:", blobContents.String())
}
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Azure.Core;
// code omitted for brevity
// Specify the Client ID if using user-assigned managed identities
var clientID = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID");
var credentialOptions = new DefaultAzureCredentialOptions
{
ManagedIdentityClientId = clientID
};
var credential = new DefaultAzureCredential(credentialOptions);
var client = new SecretClient(
new Uri("https://<your-unique-key-vault-name>.vault.azure.net/"),
credential);
KeyVaultSecret secret = client.GetSecret("<my secret>");
string secretValue = secret.Value;
using Azure.Identity;
using Microsoft.Data.SqlClient;
// code omitted for brevity
// Specify the Client ID if using user-assigned managed identities
var clientID = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID");
var credentialOptions = new DefaultAzureCredentialOptions
{
ManagedIdentityClientId = clientID
};
AccessToken accessToken = await new DefaultAzureCredential(credentialOptions).GetTokenAsync(
new TokenRequestContext(new string[] { "https://database.windows.net//.default" }));
using var connection = new SqlConnection("Server=<DB Server>; Database=<DB Name>;")
{
AccessToken = accessToken.Token
};
var cmd = new SqlCommand("select top 1 ColumnName from TableName", connection);
await connection.OpenAsync();
SqlDataReader dr = cmd.ExecuteReader();
while(dr.Read())
{
Console.WriteLine(dr.GetValue(0).ToString());
}
dr.Close();
Azure Spring Apps を使用すると、コードに変更を加えることなく、マネージド ID を使用して Azure SQL データベースに接続できます。
import { DefaultAzureCredential } from "@azure/identity";
import { Connection, Request } from "tedious";
// Specify the Client ID if using a user-assigned managed identity
const clientID = process.env.Managed_Identity_Client_ID;
const credential = new DefaultAzureCredential({
managedIdentityClientId: clientID
});
async function getAccessToken() {
const tokenResponse = await credential.getToken("https://database.windows.net//.default");
return tokenResponse.token;
}
async function queryDatabase() {
const accessToken = await getAccessToken();
const config = {
server: "<your-server-name>",
authentication: {
type: "azure-active-directory-access-token",
options: {
token: accessToken
}
},
options: {
database: "<your-database-name>",
encrypt: true
}
};
const connection = new Connection(config);
connection.on("connect", err => {
if (err) {
console.error("Connection failed:", err);
return;
}
const request = new Request("SELECT TOP 1 ColumnName FROM TableName", (err, rowCount, rows) => {
if (err) {
console.error("Query failed:", err);
return;
}
rows.forEach(row => {
console.log(row.value);
});
connection.close();
});
connection.execSql(request);
});
connection.connect();
}
queryDatabase().catch(err => console.error("Error:", err));
import os
from azure.identity import DefaultAzureCredential
from azure.core.credentials import AccessToken
import pyodbc
# Specify the Client ID if using a user-assigned managed identity
client_id = os.getenv("Managed_Identity_Client_ID")
credential = DefaultAzureCredential(managed_identity_client_id=client_id)
# Get the access token
token = credential.get_token("https://database.windows.net//.default")
access_token = token.token
# Set up the connection string
connection_string = "Driver={ODBC Driver 18 for SQL Server};Server=<your-server-name>;Database=<your-database-name>;"
# Connect to the database
connection = pyodbc.connect(connection_string, attrs_before={"AccessToken": access_token})
# Execute the query
cursor = connection.cursor()
cursor.execute("SELECT TOP 1 ColumnName FROM TableName")
# Fetch and print the result
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
# Close the connection
cursor.close()
connection.close()
package main
import (
"context"
"database/sql"
"fmt"
"os"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/denisenkom/go-mssqldb"
)
func main() {
// The client ID for the user-assigned managed identity is read from the AZURE_CLIENT_ID env var
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
fmt.Printf("failed to obtain a credential: %v\n", err)
return
}
// Get the access token
token, err := credential.GetToken(context.TODO(), azidentity.TokenRequestOptions{
Scopes: []string{"https://database.windows.net//.default"},
})
if err != nil {
fmt.Printf("Failed to get token: %v\n", err)
return
}
// Set up the connection string
connString := fmt.Sprintf("sqlserver://<your-server-name>?database=<your-database-name>&access_token=%s", token.Token)
// Connect to the database
db, err := sql.Open("sqlserver", connString)
if err != nil {
fmt.Printf("Failed to connect to the database: %v\n", err)
return
}
defer db.Close()
// Execute the query
rows, err := db.QueryContext(context.TODO(), "SELECT TOP 1 ColumnName FROM TableName")
if err != nil {
fmt.Printf("Failed to execute query: %v\n", err)
return
}
defer rows.Close()
// Fetch and print the result
for rows.Next() {
var columnValue string
if err := rows.Scan(&columnValue); err != nil {
fmt.Printf("Failed to scan row: %v\n", err)
return
}
fmt.Println(columnValue)
}
}
Microsoft Entra ID またはライブラリのトークン ベースの認証をサポートしていないリソースに接続する
一部の Azure リソースでは、まだ Microsoft Entra 認証がサポートされていない場合や、そのクライアント ライブラリでトークンによる認証をサポートしていない場合があります。 通常、こうしたリソースは、ユーザー名とパスワードまたは接続文字列内のアクセス キーを必要とするオープンソース テクノロジです。