教程:使用托管标识确保从应用服务进行的 Azure SQL 数据库连接的安全

应用服务在 Azure 中提供高度可缩放、自修补的 Web 托管服务。 它还为应用提供托管标识,这是一项统包解决方案,可以确保安全地访问 Azure SQL 数据库和其他 Azure 服务。 应用服务中的托管标识可以让应用更安全,因为不需在应用中存储机密,例如连接字符串中的凭据。 在本教程中,会将托管标识添加到在教程:使用 SQL 数据库在 Azure 中构建 ASP.NET 应用中构建的示例 ASP.NET Web 应用。 完成后,示例应用就可以安全地连接到 SQL 数据库,不需用户名和密码。

Note

此方案目前受 .NET Framework 4.6 及更高版本的支持,但不受 .NET Core 2.1 的支持。 .NET Core 2.2 支持此方案,但它尚未包括在应用服务的默认映像中。

学习如何:

  • 启用托管标识
  • 授予 SQL 数据库访问托管标识的权限
  • 配置应用程序代码,以便使用 Azure Active Directory 身份验证通过 SQL 数据库进行身份验证
  • 在 SQL 数据库中向托管标识授予最低特权

Note

在本地 Active Directory (AD DS) 中,Azure Active Directory 身份验证_不同_于集成式 Windows 身份验证。 AD DS 和 Azure Active Directory 使用的身份验证协议完全不相同。

如果没有 Azure 订阅,可在开始前创建一个试用帐户

先决条件

本文是教程:使用 SQL 数据库在 Azure 中构建 ASP.NET 应用的后续内容。 如果尚未学习该教程,请先学习该教程。 也可调整这些步骤,使用 SQL 数据库来构建自己的 ASP.NET 应用。

启用托管标识

若要为 Azure 应用启用托管标识,请在 Azure CLI 中使用 az webapp identity assign 命令。 在以下命令中,替换 <app name>

az webapp identity assign --resource-group myResourceGroup --name <app name>

以下示例演示了在 Azure Active Directory 中创建标识后的输出:

{
  "additionalProperties": {},
  "principalId": "21dfa71c-9e6f-4d17-9e90-1d28801c9735",
  "tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
  "type": "SystemAssigned"
}

下一步将用到 principalId 的值。 若要在 Azure Active Directory 中查看新标识的详细信息,请使用 principalId 的值运行以下可选命令:

az ad sp show --id <principalid>

授予数据库访问标识的权限

接下来,请在 Azure CLI中使用 az sql server ad-admin create 命令授予数据库访问应用的托管标识的权限。 在以下命令中,替换 <server_name> 和 <principalid_from_last_step>。 键入 <admin_user> 的管理员名称。

az sql server ad-admin create --resource-group myResourceGroup --server-name <server_name> --display-name <admin_user> --object-id <principalid_from_last_step>

托管标识现在可以访问 Azure SQL 数据库服务器了。

修改连接字符串

在 Azure CLI 中使用 az webapp config appsettings set 命令修改以前为应用设置的连接。 在以下命令中,将 <app name> 替换为应用的名称,将 <server_name><db_name> 替换为 SQL 数据库的相应名称。

az webapp config connection-string set --resource-group myResourceGroup --name <app name> --settings MyDbConnection='Server=tcp:<server_name>.database.chinacloudapi.cn,1433;Database=<db_name>;' --connection-string-type SQLAzure

修改 ASP.NET 代码

在 Visual Studio 中,打开包管理器控制台,并添加 NuGet 包 Microsoft.Azure.Services.AppAuthentication

Install-Package Microsoft.Azure.Services.AppAuthentication -Version 1.1.0-preview

打开 Models\MyDatabaseContext.cs,将以下 using 语句添加到文件顶部:

using System.Data.SqlClient;
using Microsoft.Azure.Services.AppAuthentication;
using System.Web.Configuration;

MyDatabaseContext 类中,添加以下构造函数:

public MyDatabaseContext(SqlConnection conn) : base(conn, true)
{
    conn.ConnectionString = WebConfigurationManager.ConnectionStrings["MyDbConnection"].ConnectionString;
    // DataSource != LocalDB means app is running in Azure with the SQLDB connection string you configured
    if(conn.DataSource != "(localdb)\\MSSQLLocalDB")
        conn.AccessToken = (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.chinacloudapi.cn/").Result;

    Database.SetInitializer<MyDatabaseContext>(null);
}

此构造函数将自定义 SqlConnection 对象配置为使用应用服务提供的 Azure SQL 数据库的访问令牌。 有了访问令牌,应用服务应用就可以使用其托管标识通过 Azure SQL 数据库进行身份验证。 有关详细信息,请参阅获取 Azure 资源的令牌。 可以使用 if 语句,通过 LocalDB 继续在本地测试应用。

Note

SqlConnection.AccessToken 目前仅在 .NET Framework 4.6 及更高版本中受支持,以及在 .NET Core 2.2 中受支持,但在 .NET Core 2.1 中不受支持。

若要使用这个新的构造函数,请打开 Controllers\TodosController.cs 并找到 private MyDatabaseContext db = new MyDatabaseContext(); 行。 现有的代码使用默认的 MyDatabaseContext 控制器通过标准的连接字符串来创建数据库,该字符串在未经更改的情况下以明文形式保存用户名和密码。

请将整行替换为以下代码:

private MyDatabaseContext db = new MyDatabaseContext(new System.Data.SqlClient.SqlConnection());

发布更改

现在,剩下的操作是将更改发布到 Azure。

在“解决方案资源管理器”中,右键单击 “DotNetAppSqlDb”项目,并选择“发布”。

从解决方案资源管理器发布

在发布页中单击“发布”。 当新网页显示待办事项列表时,表明应用使用了托管标识连接到数据库。

Code First 迁移后的 Azure 应用

现在应该可以像以前一样编辑待办事项列表了。

清理资源

若要删除通过此快速入门创建的所有资源,请运行以下命令:

az group delete --name myResourceGroup

向标识授予最低特权

在此前的步骤中,你可能已注意到托管标识是以 Azure AD 管理员身份连接到 SQL Server。 为了向托管标识授予最低特权,需以 Azure AD 管理员身份登录到 Azure SQL 数据库服务器,然后添加包含托管标识的 Azure Active Directory 组。

向 Azure Active Directory 组添加托管标识

在 Azure CLI 中,将应用的托管标识添加到名为 myAzureSQLDBAccessGroup 的新 Azure Active Directory 组,如以下脚本所示:

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

若要查看每个命令的完整 JSON 输出,请删除参数 --query objectId --output tsv

重新配置 Azure AD 管理员

你此前已经以 Azure AD 管理员身份为 SQL 数据库分配托管标识。 不能使用此标识进行交互式登录(以添加数据库用户),因此需使用实际的 Azure AD 用户。 若要添加 Azure AD 用户,请执行为 Azure SQL 数据库服务器预配 Azure Active Directory 管理员中的步骤。

Important

添加之后,除非你想完全禁用 Azure AD 对 SQL 数据库的访问(从所有 Azure AD 帐户),否则不要删除 SQL 数据库的 Azure AD 管理员。

向 Azure Active Directory 组授予权限

在 Azure CLI 中,使用 SQLCMD 命令登录到 SQL 数据库。 将 <server_name> 替换为 SQL 数据库服务器名称,将 <db_name> 替换为应用使用的数据库名称,将 <AADuser_name><AADpassword> 替换为 Azure AD 用户的凭据。

sqlcmd -S <server_name>.database.chinacloudapi.cn -d <db_name> -U <AADuser_name> -P "<AADpassword>" -G -l 30

在所需数据库的 SQL 提示符窗口中运行以下命令,添加以前创建的 Azure Active Directory 组并授予应用所需的权限。 例如,

CREATE USER [myAzureSQLDBAccessGroup] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [myAzureSQLDBAccessGroup];
ALTER ROLE db_datawriter ADD MEMBER [myAzureSQLDBAccessGroup];
ALTER ROLE db_ddladmin ADD MEMBER [myAzureSQLDBAccessGroup];
GO

键入 EXIT,返回到 Azure CLI 提示符窗口。

后续步骤

你已了解:

  • 启用托管标识
  • 授予 SQL 数据库访问托管标识的权限
  • 配置应用程序代码,以便使用 Azure Active Directory 身份验证通过 SQL 数据库进行身份验证
  • 在 SQL 数据库中向托管标识授予最低特权

转到下一教程,了解如何向 Web 应用映射自定义 DNS 名称。